编译器
0.8.23+commit.f704f362
文件 1 的 11:Address.sol
pragma solidity ^0.8.20;
library Address {
error AddressInsufficientBalance(address account);
error AddressEmptyCode(address target);
error FailedInnerCall();
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
function _revert(bytes memory returndata) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}
文件 2 的 11:Constants.sol
pragma solidity ^0.8.23;
library Constants {
address internal constant CRVUSD_ADDRESS = 0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E;
address internal constant USDC_ADDRESS = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address internal constant USDT_ADDRESS = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
address internal constant DAI_ADDRESS = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address internal constant FRX_ETH_ADDRESS = 0x5E8422345238F34275888049021821E8E08CAa1f;
address internal constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address internal constant CVX_ADDRESS = 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B;
address internal constant CRV_ADDRESS = 0xD533a949740bb3306d119CC777fa900bA034cd52;
address internal constant FXS_ADDRESS = 0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0;
address internal constant SPELL_ADDRESS = 0x090185f2135308BaD17527004364eBcC2D37e5F6;
address internal constant SDT_ADDRESS = 0x73968b9a57c6E53d41345FD57a6E6ae27d6CDB2F;
address internal constant SFRXETH_ADDRESS = 0xac3E018457B222d93114458476f3E3416Abbe38F;
address internal constant ZUNUSD_ADDRESS = 0x8C0D76C9B18779665475F3E212D9Ca1Ed6A1A0e6;
address internal constant zunUSD_CONTROLLER_ADDRESS =
0x618eee502CDF6b46A2199C21D1411f3F6065c940;
address internal constant zunETH_ADDRESS = 0xc2e660C62F72c2ad35AcE6DB78a616215E2F2222;
address internal constant zunETH_CONTROLLER_ADDRESS =
0x54A00DA65c79DDCe24E7fe4691737FD70F7797DF;
address public constant CHAINLINK_FEED_REGISTRY_ETH_ADDRESS =
0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address internal constant CRV_3POOL_ADDRESS = 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7;
address internal constant CRV_3POOL_LP_ADDRESS = 0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490;
address internal constant CRV_TRICRYPTO2_ADDRESS = 0xD51a44d3FaE010294C616388b506AcdA1bfAAE46;
address internal constant ETH_frxETH_ADDRESS = 0xa1F8A6807c402E4A15ef4EBa36528A3FED24E577;
address internal constant ETH_frxETH_LP_ADDRESS = 0xf43211935C781D5ca1a41d2041F397B8A7366C7A;
address internal constant WETH_frxETH_ADDRESS = 0x9c3B46C0Ceb5B9e304FCd6D88Fc50f7DD24B31Bc;
address internal constant WETH_frxETH_LP_ADDRESS = 0x9c3B46C0Ceb5B9e304FCd6D88Fc50f7DD24B31Bc;
address internal constant CRV_FRAX_USDC_POOL_ADDRESS =
0xDcEF968d416a41Cdac0ED8702fAC8128A64241A2;
address internal constant CRV_FRAX_USDC_POOL_LP_ADDRESS =
0x3175Df0976dFA876431C2E9eE6Bc45b65d3473CC;
address internal constant SDT_CRVUSD_USDT_VAULT_ADDRESS =
0x37b24ac19504C0c6FC1ADc8deb5D24f5C4F6A2f2;
address internal constant CRV_CRVUSD_USDT_LP_ADDRESS =
0x390f3595bCa2Df7d23783dFd126427CCeb997BF4;
address internal constant CRV_CRVUSD_USDT_ADDRESS = 0x390f3595bCa2Df7d23783dFd126427CCeb997BF4;
address internal constant SDT_CRVUSD_USDC_VAULT_ADDRESS =
0xb618EA40cb1F5b08839Ba228C8dd58AC3DCA12F3;
address internal constant CRV_CRVUSD_USDC_LP_ADDRESS =
0x4DEcE678ceceb27446b35C672dC7d61F30bAD69E;
address internal constant CRV_CRVUSD_USDC_ADDRESS = 0x4DEcE678ceceb27446b35C672dC7d61F30bAD69E;
address internal constant CRV_BOOSTER_ADDRESS = 0xF403C135812408BFbE8713b5A23a04b3D48AAE31;
address internal constant CRV_ETH_stETH_ADDRESS = 0x21E27a5E5513D6e65C4f830167390997aA84843a;
address internal constant CRV_ETH_stETH_LP_ADDRESS = 0x21E27a5E5513D6e65C4f830167390997aA84843a;
address internal constant CVX_ETH_stETH_REWARDS_ADDRESS =
0x6B27D7BC63F1999D14fF9bA900069ee516669ee8;
uint256 internal constant CVX_ETH_stETH_PID = 177;
address internal constant CRV_zunUSD_crvUSD_ADDRESS =
0x8C24b3213FD851db80245FCCc42c40B94Ac9a745;
address internal constant CRV_zunUSD_crvUSD_LP_ADDRESS =
0x8C24b3213FD851db80245FCCc42c40B94Ac9a745;
address internal constant CVX_zunUSD_crvUSD_REWARDS_ADDRESS =
0xB0408d1477554268Ece9b0a40290C345196fBf1B;
uint256 internal constant CVX_zunUSD_crvUSD_PID = 309;
address internal constant CRV_USDT_crvUSD_ADDRESS = 0x390f3595bCa2Df7d23783dFd126427CCeb997BF4;
address internal constant LLAMALEND_CRVUSD_ADDRESS = 0xCeA18a8752bb7e7817F9AE7565328FE415C0f2cA;
address internal constant CVX_LLAMALEND_CRVUSD_REWARDS_ADDRESS =
0x4bf2d8484474170bff8a8c34475be3d87dFF28cA;
uint256 internal constant CVX_LLAMALEND_CRVUSD_PID = 325;
address internal constant CRV_zunETH_frxETH_ADDRESS =
0x3A65cbaebBFecbeA5D0CB523ab56fDbda7fF9aAA;
address internal constant CRV_zunETH_frxETH_LP_ADDRESS =
0x3A65cbaebBFecbeA5D0CB523ab56fDbda7fF9aAA;
address internal constant CVX_zunETH_frxETH_REWARDS_ADDRESS =
0x756d67A10974Fa0e0cE63F82AF4E7ef0d46d452D;
uint256 internal constant CVX_zunETH_frxETH_PID = 330;
address internal constant SDT_zunETH_frxETH_VAULT_ADDRESS =
0xAaE1Ae12d4C8b811DDa1188b01be23b4ab7C62D2;
address internal constant SDT_LLAMALEND_CRVUSD_VAULT_ADDRESS =
0xfa6D40573082D797CB3cC378c0837fB90eB043e5;
address internal constant CRV_zunUSD_crvFRAX_ADDRESS = address(0);
address internal constant CRV_zunUSD_crvFRAX_LP_ADDRESS = address(0);
address internal constant CVX_zunUSD_crvFRAX_REWARDS_ADDRESS = address(0);
uint256 internal constant CVX_zunUSD_crvFRAX_PID = 0;
}
文件 3 的 11:Context.sol
pragma solidity ^0.8.20;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 4 的 11:ICurveRouter.sol
pragma solidity ^0.8.0;
struct CurveRoute {
address[] route;
uint256[5][] swapParams;
}
interface ICurveRouterV1 {
function exchange(
address[11] calldata _route,
uint[5][5] calldata _swap_params,
uint _amount,
uint _expected
) external returns (uint);
function get_dy(
address[11] calldata _route,
uint[5][5] calldata _swap_params,
uint _amount
) external view returns (uint);
}
文件 5 的 11:IERC20.sol
pragma solidity ^0.8.20;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 value) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
文件 6 的 11:IERC20Permit.sol
pragma solidity ^0.8.20;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 7 的 11:ITokenConverter.sol
pragma solidity ^0.8.23;
interface ITokenConverter {
function handle(
address tokenIn,
address tokenOut,
uint256 amount,
uint256 minAmountOut
) external returns (uint256);
function valuate(
address tokenIn_,
address tokenOut_,
uint256 amountIn_
) external view returns (uint256);
}
文件 8 的 11:Ownable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
error OwnableUnauthorizedAccount(address account);
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
modifier onlyOwner() {
_checkOwner();
_;
}
function owner() public view virtual returns (address) {
return _owner;
}
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 9 的 11:Ownable2Step.sol
pragma solidity ^0.8.20;
import {Ownable} from "./Ownable.sol";
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}
文件 10 的 11:SafeERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
error SafeERC20FailedOperation(address token);
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}
文件 11 的 11:TokenConverter.sol
pragma solidity ^0.8.23;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import { Ownable2Step, Ownable } from '@openzeppelin/contracts/access/Ownable2Step.sol';
import '../utils/Constants.sol';
import '../interfaces/ICurveRouter.sol';
import '../interfaces/ITokenConverter.sol';
contract TokenConverter is ITokenConverter, Ownable2Step {
using SafeERC20 for IERC20;
address public immutable curveRouter;
mapping(address => mapping(address => CurveRoute)) routes;
error ZeroAddress();
error WrongLength();
constructor(address curveRouter_) Ownable(msg.sender) {
if (curveRouter_ == address(0)) revert ZeroAddress();
curveRouter = curveRouter_;
}
function setRoute(
address tokenIn,
address tokenOut,
address[] memory route,
uint256[5][] memory swapParams
) external onlyOwner {
routes[tokenIn][tokenOut] = CurveRoute(route, swapParams);
}
function setRoutes(
address[] memory tokenIn,
address[] memory tokenOut,
address[][] memory route,
uint256[5][][] memory swapParams
) external onlyOwner {
if (tokenIn.length != tokenOut.length) revert WrongLength();
if (tokenIn.length != route.length) revert WrongLength();
if (tokenIn.length != swapParams.length) revert WrongLength();
for (uint256 i; i < tokenIn.length; ++i) {
routes[tokenIn[i]][tokenOut[i]] = CurveRoute(route[i], swapParams[i]);
}
}
function handle(
address tokenIn_,
address tokenOut_,
uint256 amountIn_,
uint256 minAmountOut_
) public returns (uint256 amountOut) {
if (amountIn_ == 0) return 0;
IERC20(tokenIn_).safeIncreaseAllowance(curveRouter, amountIn_);
address[11] memory routes_ = _fillRoutes(tokenIn_, tokenOut_);
uint256[5][5] memory swapParams_ = _fillSwapParams(tokenIn_, tokenOut_);
amountOut = ICurveRouterV1(curveRouter).exchange(
routes_,
swapParams_,
amountIn_,
minAmountOut_
);
IERC20 tokenOut = IERC20(tokenOut_);
tokenOut.safeTransfer(msg.sender, amountOut);
}
function valuate(
address tokenIn_,
address tokenOut_,
uint256 amountIn_
) external view returns (uint256) {
if (amountIn_ == 0) return 0;
address[11] memory routes_ = _fillRoutes(tokenIn_, tokenOut_);
uint256[5][5] memory swapParams_ = _fillSwapParams(tokenIn_, tokenOut_);
return ICurveRouterV1(curveRouter).get_dy(routes_, swapParams_, amountIn_);
}
function _fillRoutes(
address tokenIn_,
address tokenOut_
) internal view returns (address[11] memory routes_) {
for (uint8 i; i < routes[tokenIn_][tokenOut_].route.length; ++i) {
routes_[i] = routes[tokenIn_][tokenOut_].route[i];
}
}
function _fillSwapParams(
address tokenIn_,
address tokenOut_
) internal view returns (uint256[5][5] memory swapParams_) {
for (uint8 i; i < routes[tokenIn_][tokenOut_].swapParams.length; ++i) {
swapParams_[i] = routes[tokenIn_][tokenOut_].swapParams[i];
}
}
}
{
"compilationTarget": {
"contracts/utils/TokenConverter.sol": "TokenConverter"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"curveRouter_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"WrongLength","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"curveRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn_","type":"address"},{"internalType":"address","name":"tokenOut_","type":"address"},{"internalType":"uint256","name":"amountIn_","type":"uint256"},{"internalType":"uint256","name":"minAmountOut_","type":"uint256"}],"name":"handle","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"address[]","name":"route","type":"address[]"},{"internalType":"uint256[5][]","name":"swapParams","type":"uint256[5][]"}],"name":"setRoute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokenIn","type":"address[]"},{"internalType":"address[]","name":"tokenOut","type":"address[]"},{"internalType":"address[][]","name":"route","type":"address[][]"},{"internalType":"uint256[5][][]","name":"swapParams","type":"uint256[5][][]"}],"name":"setRoutes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenIn_","type":"address"},{"internalType":"address","name":"tokenOut_","type":"address"},{"internalType":"uint256","name":"amountIn_","type":"uint256"}],"name":"valuate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]