编译器
0.8.24+commit.e11b9ed9
文件 1 的 4:IBroker.sol
pragma solidity >0.5.13 <0.9;
pragma experimental ABIEncoderV2;
interface IBroker {
function swapIn(
address exchangeProvider,
bytes32 exchangeId,
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 amountOutMin
) external returns (uint256 amountOut);
function swapOut(
address exchangeProvider,
bytes32 exchangeId,
address tokenIn,
address tokenOut,
uint256 amountOut,
uint256 amountInMax
) external returns (uint256 amountIn);
function getAmountOut(
address exchangeProvider,
bytes32 exchangeId,
address tokenIn,
address tokenOut,
uint256 amountIn
) external view returns (uint256 amountOut);
function getAmountIn(
address exchangeProvider,
bytes32 exchangeId,
address tokenIn,
address tokenOut,
uint256 amountOut
) external view returns (uint256 amountIn);
function getExchangeProviders()
external
view
returns (address[] memory exchangeProviders);
}
文件 2 的 4:IMentoRouter.sol
pragma solidity ^0.8.20;
interface IMentoRouter {
struct Step {
address exchangeProvider;
bytes32 exchangeId;
address assetIn;
address assetOut;
}
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
Step[] calldata path
) external returns (uint256[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
Step[] calldata path
) external returns (uint[] memory amounts);
function getAmountOut(
uint256 amountIn,
Step[] calldata path
) external view returns (uint256 amountOut);
function getAmountIn(
uint256 amountOut,
Step[] calldata path
) external view returns (uint256 amountIn);
function drain(address asset) external;
}
文件 3 的 4:MentoRouter.sol
pragma solidity ^0.8.20;
import {IBroker} from "./IBroker.sol";
import {TransferHelper} from "./TransferHelper.sol";
import {IMentoRouter} from "./IMentoRouter.sol";
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
}
contract MentoRouter is IMentoRouter {
IBroker immutable broker;
address immutable mentoReserveMultisig;
constructor(address _broker, address _mentoReserveMultisig) {
broker = IBroker(_broker);
mentoReserveMultisig = _mentoReserveMultisig;
}
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
Step[] calldata path
) external returns (uint256[] memory amounts) {
amounts = getAmountsOut(amountIn, path);
require(
amounts[amounts.length - 1] >= amountOutMin,
"MentoRouter: INSUFFICIENT_OUTPUT_AMOUNT"
);
TransferHelper.safeTransferFrom(
path[0].assetIn,
msg.sender,
address(this),
amounts[0]
);
swap(amounts, path);
}
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
Step[] calldata path
) external returns (uint[] memory amounts) {
amounts = getAmountsIn(amountOut, path);
require(
amounts[0] <= amountInMax,
"MentoRouter: EXCESSIVE_INPUT_AMOUNT"
);
TransferHelper.safeTransferFrom(
path[0].assetIn,
msg.sender,
address(this),
amounts[0]
);
swap(amounts, path);
}
function getAmountOut(
uint256 amountIn,
Step[] calldata path
) external view returns (uint256 amountOut) {
uint256[] memory amounts = getAmountsOut(amountIn, path);
return amounts[amounts.length - 1];
}
function getAmountIn(
uint256 amountOut,
Step[] calldata path
) external view returns (uint256 amountIn) {
uint256[] memory amounts = getAmountsIn(amountOut, path);
return amounts[0];
}
function drain(address asset) external {
TransferHelper.safeTransfer(
asset,
mentoReserveMultisig,
IERC20(asset).balanceOf(address(this))
);
}
function swap(
uint256[] memory amounts,
Step[] memory path
) internal virtual {
for (uint i; i <= path.length - 1; i++) {
TransferHelper.safeApprove(
path[i].assetIn,
address(broker),
amounts[i]
);
amounts[i + 1] = broker.swapIn(
path[i].exchangeProvider,
path[i].exchangeId,
path[i].assetIn,
path[i].assetOut,
amounts[i],
amounts[i + 1]
);
}
TransferHelper.safeTransfer(
path[path.length - 1].assetOut,
msg.sender,
amounts[amounts.length - 1]
);
}
function getAmountsOut(
uint256 amountIn,
Step[] memory path
) internal view returns (uint256[] memory amounts) {
require(path.length >= 2, "MentoRouter: INVALID_PATH");
amounts = new uint256[](path.length + 1);
amounts[0] = amountIn;
for (uint i; i <= path.length - 1; i++) {
amounts[i + 1] = broker.getAmountOut(
path[i].exchangeProvider,
path[i].exchangeId,
path[i].assetIn,
path[i].assetOut,
amounts[i]
);
}
return amounts;
}
function getAmountsIn(
uint256 amountOut,
Step[] memory path
) internal view returns (uint256[] memory amounts) {
require(path.length >= 2, "MentoRouter: INVALID_PATH");
amounts = new uint256[](path.length + 1);
amounts[amounts.length - 1] = amountOut;
for (uint i = path.length; i > 0; i--) {
amounts[i - 1] = (broker.getAmountIn(
path[i - 1].exchangeProvider,
path[i - 1].exchangeId,
path[i - 1].assetIn,
path[i - 1].assetOut,
amounts[i]
) + 1);
}
return amounts;
}
}
文件 4 的 4:TransferHelper.sol
pragma solidity >=0.6.0;
library TransferHelper {
function safeApprove(address token, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0x095ea7b3, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::safeApprove: approve failed"
);
}
function safeTransfer(address token, address to, uint256 value) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0xa9059cbb, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::safeTransfer: transfer failed"
);
}
function safeTransferFrom(
address token,
address from,
address to,
uint256 value
) internal {
(bool success, bytes memory data) = token.call(
abi.encodeWithSelector(0x23b872dd, from, to, value)
);
require(
success && (data.length == 0 || abi.decode(data, (bool))),
"TransferHelper::transferFrom: transferFrom failed"
);
}
function safeTransferETH(address to, uint256 value) internal {
(bool success, ) = to.call{value: value}(new bytes(0));
require(
success,
"TransferHelper::safeTransferETH: ETH transfer failed"
);
}
}
{
"compilationTarget": {
"src/MentoRouter.sol": "MentoRouter"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": [
":@ds/=lib/multicall/lib/ds-test/src/",
":@std/=lib/multicall/lib/forge-std/src/",
":ds-test/=lib/multicall/lib/ds-test/src/",
":forge-std/=lib/forge-std/src/",
":multicall/=lib/multicall/src/"
]
}
[{"inputs":[{"internalType":"address","name":"_broker","type":"address"},{"internalType":"address","name":"_mentoReserveMultisig","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"drain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"components":[{"internalType":"address","name":"exchangeProvider","type":"address"},{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"address","name":"assetIn","type":"address"},{"internalType":"address","name":"assetOut","type":"address"}],"internalType":"struct IMentoRouter.Step[]","name":"path","type":"tuple[]"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"components":[{"internalType":"address","name":"exchangeProvider","type":"address"},{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"address","name":"assetIn","type":"address"},{"internalType":"address","name":"assetOut","type":"address"}],"internalType":"struct IMentoRouter.Step[]","name":"path","type":"tuple[]"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"components":[{"internalType":"address","name":"exchangeProvider","type":"address"},{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"address","name":"assetIn","type":"address"},{"internalType":"address","name":"assetOut","type":"address"}],"internalType":"struct IMentoRouter.Step[]","name":"path","type":"tuple[]"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"components":[{"internalType":"address","name":"exchangeProvider","type":"address"},{"internalType":"bytes32","name":"exchangeId","type":"bytes32"},{"internalType":"address","name":"assetIn","type":"address"},{"internalType":"address","name":"assetOut","type":"address"}],"internalType":"struct IMentoRouter.Step[]","name":"path","type":"tuple[]"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"}]