编译器
0.8.23+commit.f704f362
文件 1 的 18:AccessControl.sol
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}
文件 2 的 18: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();
}
}
}
文件 3 的 18: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 = address(0);
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 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_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;
address internal constant CRV_zunUSD_crvUSD_ADDRESS = address(0);
address internal constant CRV_zunUSD_crvUSD_LP_ADDRESS = address(0);
address internal constant CVX_zunUSD_crvUSD_REWARDS_ADDRESS = address(0);
uint256 internal constant CVX_zunUSD_crvUSD_PID = 0;
}
文件 4 的 18: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;
}
}
文件 5 的 18:ERC165.sol
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 6 的 18:ERC20.sol
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual returns (string memory) {
return _name;
}
function symbol() public view virtual returns (string memory) {
return _symbol;
}
function decimals() public view virtual returns (uint8) {
return 18;
}
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
_totalSupply -= value;
}
} else {
unchecked {
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}
文件 7 的 18:IAccessControl.sol
pragma solidity ^0.8.20;
interface IAccessControl {
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
error AccessControlBadConfirmation();
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address callerConfirmation) external;
}
文件 8 的 18:IERC165.sol
pragma solidity ^0.8.20;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 9 的 18: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);
}
文件 10 的 18:IERC20Metadata.sol
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 11 的 18: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);
}
文件 12 的 18:IPool.sol
pragma solidity ^0.8.23;
import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import { IStrategy } from './IStrategy.sol';
interface IPool is IERC20 {
error WrongDeposit(uint256 sid, uint256[5] amounts);
error AbsentStrategy(uint256 sid);
error NotStartedStrategy(uint256 sid);
error DisabledStrategy(uint256 sid);
error WrongAmount();
error WrongWithdrawParams(uint256 sid);
error WrongRatio();
error ZeroAddress();
error DuplicatedStrategy();
error IncorrectArguments();
error WrongWithdrawPercent();
error WrongReceiver();
error IncorrectSid();
error WrongTokens();
error WrongDecimalMultipliers();
struct StrategyInfo {
IStrategy strategy;
uint256 startTime;
uint256 minted;
bool enabled;
}
event Deposited(
address indexed depositor,
uint256 deposited,
uint256[5] amounts,
uint256 indexed sid
);
event Withdrawn(address indexed withdrawer, uint256 withdrawn, uint256 indexed sid);
event FailedWithdrawal(address indexed withdrawer, uint256[5] amounts, uint256 withdrawn);
event AddedStrategy(uint256 indexed sid, address indexed strategyAddr, uint256 startTime);
event ClaimedRewards(address indexed receiver, IERC20[] rewardTokens);
event ClaimedExtraGains(address indexed receiver, uint256 amount);
event EnabledStrategy(address indexed pool);
event DisableStrategy(address indexed pool);
event UpdatedToken(
uint256 indexed tid,
address indexed token,
uint256 tokenDecimalMultiplier,
address tokenOld
);
function tokens() external view returns (IERC20[5] memory);
function token(uint256 tid) external view returns (IERC20);
function tokenDecimalsMultipliers() external view returns (uint256[5] memory);
function strategyInfo(uint256 sid) external view returns (StrategyInfo memory);
function claimRewards(address receiver, IERC20[] memory rewardTokens) external;
function totalHoldings() external view returns (uint256);
function strategyCount() external view returns (uint256);
function deposit(
uint256 sid,
uint256[5] memory amounts,
address receiver
) external returns (uint256);
function depositStrategy(uint256 sid, uint256[5] memory amounts) external returns (uint256);
function withdraw(
uint256 sid,
uint256 stableAmount,
uint256[5] memory minTokenAmounts,
address receiver
) external;
function mintAndClaimExtraGains(address receiver) external;
}
文件 13 的 18:IStrategy.sol
pragma solidity ^0.8.23;
import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
interface IStrategy {
function deposit(uint256[5] memory amounts) external returns (uint256);
function withdraw(
address receiver,
uint256 userDepositRatio,
uint256[5] memory minTokenAmounts
) external returns (bool);
function withdrawAll(uint256[5] memory minTokenAmounts) external;
function totalHoldings() external view returns (uint256);
function claimRewards(address receiver, IERC20[] memory rewardTokens) external;
function calcTokenAmount(
uint256[5] memory tokenAmounts,
bool isDeposit
) external view returns (uint256 sharesAmount);
}
文件 14 的 18:Pausable.sol
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
abstract contract Pausable is Context {
bool private _paused;
event Paused(address account);
event Unpaused(address account);
error EnforcedPause();
error ExpectedPause();
constructor() {
_paused = false;
}
modifier whenNotPaused() {
_requireNotPaused();
_;
}
modifier whenPaused() {
_requirePaused();
_;
}
function paused() public view virtual returns (bool) {
return _paused;
}
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 15 的 18: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;
}
}
文件 16 的 18:ZunamiPool.sol
pragma solidity ^0.8.23;
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@openzeppelin/contracts/utils/Pausable.sol';
import '@openzeppelin/contracts/access/AccessControl.sol';
import './interfaces/IStrategy.sol';
import './interfaces/IPool.sol';
contract ZunamiPool is IPool, ERC20, Pausable, AccessControl {
using SafeERC20 for IERC20;
uint8 public constant POOL_ASSETS = 5;
bytes32 public constant EMERGENCY_ADMIN_ROLE = keccak256('EMERGENCY_ADMIN_ROLE');
bytes32 public constant CONTROLLER_ROLE = keccak256('CONTROLLER_ROLE');
uint256 public constant RATIO_MULTIPLIER = 1e18;
uint256 public constant MIN_LOCK_TIME = 1 days;
uint256 public constant FUNDS_DENOMINATOR = 1e18;
uint256 public constant MINIMUM_LIQUIDITY = 1e3;
address public constant MINIMUM_LIQUIDITY_LOCKER = 0x000000000000000000000000000000000000dEaD;
StrategyInfo[] private _strategyInfo;
IERC20[POOL_ASSETS] private _tokens;
uint256[POOL_ASSETS] private _decimalsMultipliers;
uint256 public extraGains;
uint256 public extraGainsMintedBlock;
bool public launched;
constructor(string memory name_, string memory symbol_) ERC20(name_, symbol_) {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(EMERGENCY_ADMIN_ROLE, msg.sender);
}
function _checkStrategyExisted(uint256 sid) internal view {
if (sid >= _strategyInfo.length) revert AbsentStrategy(sid);
}
function _checkStrategyStarted(uint256 sid) internal view {
if (block.timestamp < _strategyInfo[sid].startTime) revert NotStartedStrategy(sid);
}
function _checkStrategyEnabled(uint256 sid) internal view {
if (!_strategyInfo[sid].enabled) revert DisabledStrategy(sid);
}
function strategyInfo(uint256 sid) external view returns (StrategyInfo memory) {
return _strategyInfo[sid];
}
function tokens() external view returns (IERC20[POOL_ASSETS] memory) {
return _tokens;
}
function token(uint256 tid) external view returns (IERC20) {
return _tokens[tid];
}
function tokenDecimalsMultipliers() external view returns (uint256[POOL_ASSETS] memory) {
return _decimalsMultipliers;
}
function _setTokens(
address[POOL_ASSETS] memory tokens_,
uint256[POOL_ASSETS] memory tokenDecimalsMultipliers_
) internal {
bool otherZeros = false;
for (uint256 i = 0; i < POOL_ASSETS; i++) {
if (otherZeros && address(tokens_[i]) != address(0)) revert WrongTokens();
if (address(tokens_[i]) == address(0)) otherZeros = true;
if (
(address(tokens_[i]) != address(0) && tokenDecimalsMultipliers_[i] == 0) ||
(address(tokens_[i]) == address(0) && tokenDecimalsMultipliers_[i] != 0)
) revert WrongDecimalMultipliers();
address oldToken = address(_tokens[i]);
_tokens[i] = IERC20(tokens_[i]);
_decimalsMultipliers[i] = tokenDecimalsMultipliers_[i];
emit UpdatedToken(i, tokens_[i], tokenDecimalsMultipliers_[i], oldToken);
}
}
function setTokens(
address[POOL_ASSETS] memory tokens_,
uint256[POOL_ASSETS] memory tokenDecimalMultipliers_
) external onlyRole(DEFAULT_ADMIN_ROLE) {
_setTokens(tokens_, tokenDecimalMultipliers_);
}
function pause() external onlyRole(EMERGENCY_ADMIN_ROLE) {
_pause();
}
function unpause() external onlyRole(DEFAULT_ADMIN_ROLE) {
_unpause();
}
function claimRewards(
address receiver,
IERC20[] memory rewardTokens
) external onlyRole(CONTROLLER_ROLE) {
_mintExtraGains();
_claimExtraGains(receiver);
for (uint256 i = 0; i < _strategyInfo.length; i++) {
StrategyInfo memory strategyInfo_ = _strategyInfo[i];
if (strategyInfo_.minted > 0 && strategyInfo_.enabled) {
strategyInfo_.strategy.claimRewards(receiver, rewardTokens);
}
}
emit ClaimedRewards(receiver, rewardTokens);
}
function _mintExtraGains() internal {
if (extraGainsMintedBlock == block.number) return;
uint256 gains;
uint256 strategyGains_;
for (uint256 sid = 0; sid < _strategyInfo.length; sid++) {
StrategyInfo storage strategyInfo_ = _strategyInfo[sid];
if (strategyInfo_.minted > 0 && strategyInfo_.enabled) {
uint256 holdings = strategyInfo_.strategy.totalHoldings();
uint256 minted = strategyInfo_.minted;
if (holdings <= minted) continue;
unchecked {
strategyGains_ = holdings - minted;
strategyInfo_.minted += strategyGains_;
gains += strategyGains_;
}
}
}
if (gains == 0) return;
extraGains += gains;
extraGainsMintedBlock = block.number;
_mint(address(this), gains);
}
function _claimExtraGains(address receiver) internal {
if (extraGains == 0) return;
uint256 _extraGains = extraGains;
extraGains = 0;
IERC20(address(this)).transfer(receiver, _extraGains);
emit ClaimedExtraGains(receiver, _extraGains);
}
function mintAndClaimExtraGains(address receiver) external onlyRole(CONTROLLER_ROLE) {
_mintExtraGains();
_claimExtraGains(receiver);
}
function totalHoldings() public view returns (uint256) {
uint256 length = _strategyInfo.length;
uint256 total;
for (uint256 sid = 0; sid < length; sid++) {
StrategyInfo memory strategyInfo_ = _strategyInfo[sid];
if (strategyInfo_.minted > 0 && strategyInfo_.enabled) {
total += strategyInfo_.strategy.totalHoldings();
}
}
return total;
}
function strategyCount() external view returns (uint256) {
return _strategyInfo.length;
}
function deposit(
uint256 sid,
uint256[POOL_ASSETS] memory amounts,
address receiver
) external whenNotPaused onlyRole(CONTROLLER_ROLE) returns (uint256) {
_checkStrategyExisted(sid);
_checkStrategyStarted(sid);
_checkStrategyEnabled(sid);
if (receiver == address(0)) {
receiver = _msgSender();
}
_mintExtraGains();
uint256 depositedValue = doDepositStrategy(sid, amounts);
return processSuccessfulDeposit(receiver, depositedValue, amounts, sid);
}
function depositStrategy(
uint256 sid,
uint256[POOL_ASSETS] memory amounts
) external whenNotPaused onlyRole(CONTROLLER_ROLE) returns (uint256) {
_checkStrategyExisted(sid);
_checkStrategyStarted(sid);
return doDepositStrategy(sid, amounts);
}
function doDepositStrategy(
uint256 sid,
uint256[POOL_ASSETS] memory amounts
) internal returns (uint256 depositedValue) {
IStrategy strategy = _strategyInfo[sid].strategy;
for (uint256 i = 0; i < amounts.length; i++) {
if (amounts[i] > 0) {
IERC20(_tokens[i]).safeTransfer(address(strategy), amounts[i]);
}
}
_mintExtraGains();
depositedValue = strategy.deposit(amounts);
if (depositedValue == 0) revert WrongDeposit(sid, amounts);
}
function processSuccessfulDeposit(
address receiver,
uint256 depositedValue,
uint256[POOL_ASSETS] memory depositedTokens,
uint256 sid
) internal returns (uint256) {
uint256 locked = 0;
if (totalSupply() == 0) {
if (depositedValue <= MINIMUM_LIQUIDITY) revert WrongAmount();
locked = MINIMUM_LIQUIDITY;
_mint(MINIMUM_LIQUIDITY_LOCKER, MINIMUM_LIQUIDITY);
}
uint256 depositedValueSubLocked = depositedValue - locked;
_mint(receiver, depositedValueSubLocked);
_strategyInfo[sid].minted += depositedValue;
emit Deposited(receiver, depositedValue, depositedTokens, sid);
return depositedValueSubLocked;
}
function withdraw(
uint256 sid,
uint256 stableAmount,
uint256[POOL_ASSETS] memory tokenAmounts,
address receiver
) external whenNotPaused onlyRole(CONTROLLER_ROLE) {
_checkStrategyExisted(sid);
_checkStrategyStarted(sid);
_checkStrategyEnabled(sid);
IStrategy strategy = _strategyInfo[sid].strategy;
address controllerAddr = _msgSender();
if (balanceOf(controllerAddr) < stableAmount) revert WrongAmount();
_mintExtraGains();
if (
!strategy.withdraw(
receiver == address(0) ? controllerAddr : receiver,
calcRatioSafe(stableAmount, _strategyInfo[sid].minted),
tokenAmounts
)
) revert WrongWithdrawParams(sid);
processSuccessfulWithdrawal(controllerAddr, stableAmount, sid);
}
function processSuccessfulWithdrawal(address user, uint256 stableAmount, uint256 sid) internal {
_burn(user, stableAmount);
_strategyInfo[sid].minted -= stableAmount;
emit Withdrawn(user, stableAmount, sid);
}
function calcRatioSafe(
uint256 outAmount,
uint256 strategyDeposited
) internal pure returns (uint256 ratio) {
ratio = (outAmount * RATIO_MULTIPLIER) / strategyDeposited;
if (ratio == 0 || ratio > RATIO_MULTIPLIER) revert WrongRatio();
}
function addStrategy(address _strategyAddr) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (_strategyAddr == address(0)) revert ZeroAddress();
for (uint256 i = 0; i < _strategyInfo.length; i++) {
if (_strategyAddr == address(_strategyInfo[i].strategy)) revert DuplicatedStrategy();
}
uint256 startTime = block.timestamp + (launched ? MIN_LOCK_TIME : 0);
_strategyInfo.push(
StrategyInfo({
strategy: IStrategy(_strategyAddr),
startTime: startTime,
minted: 0,
enabled: true
})
);
emit AddedStrategy(_strategyInfo.length - 1, _strategyAddr, startTime);
}
function launch() external onlyRole(DEFAULT_ADMIN_ROLE) {
launched = true;
}
function moveFundsBatch(
uint256[] memory _strategies,
uint256[] memory _withdrawalsPercents,
uint256 _receiverStrategy,
uint256[POOL_ASSETS][] memory _minAmounts
) external onlyRole(EMERGENCY_ADMIN_ROLE) {
if (_strategies.length != _withdrawalsPercents.length) revert IncorrectArguments();
if (_receiverStrategy >= _strategyInfo.length) revert WrongReceiver();
_checkStrategyExisted(_receiverStrategy);
_checkStrategyEnabled(_receiverStrategy);
uint256 sid;
uint256 zunamiStables;
for (uint256 i = 0; i < _strategies.length; i++) {
sid = _strategies[i];
zunamiStables += _moveFunds(sid, _withdrawalsPercents[i], _minAmounts[i]);
}
_strategyInfo[_receiverStrategy].minted += zunamiStables;
uint256[POOL_ASSETS] memory tokensRemainder;
for (uint256 i = 0; i < POOL_ASSETS; i++) {
IERC20 token_ = _tokens[i];
if (address(token_) == address(0)) break;
tokensRemainder[i] = token_.balanceOf(address(this));
if (tokensRemainder[i] > 0) {
token_.safeTransfer(
address(_strategyInfo[_receiverStrategy].strategy),
tokensRemainder[i]
);
}
}
if (_strategyInfo[_receiverStrategy].strategy.deposit(tokensRemainder) == 0)
revert WrongDeposit(_receiverStrategy, tokensRemainder);
}
function _moveFunds(
uint256 sid,
uint256 withdrawPercent,
uint256[POOL_ASSETS] memory minAmounts
) private returns (uint256 stableAmount) {
if (withdrawPercent == 0 || withdrawPercent > FUNDS_DENOMINATOR)
revert WrongWithdrawPercent();
if (withdrawPercent == FUNDS_DENOMINATOR) {
stableAmount = _strategyInfo[sid].minted;
_strategyInfo[sid].minted = 0;
_strategyInfo[sid].strategy.withdrawAll(minAmounts);
} else {
stableAmount = (_strategyInfo[sid].minted * withdrawPercent) / FUNDS_DENOMINATOR;
_strategyInfo[sid].minted -= stableAmount;
if (!_strategyInfo[sid].strategy.withdraw(address(this), withdrawPercent, minAmounts))
revert WrongWithdrawParams(sid);
}
return stableAmount;
}
function enableStrategy(uint256 _sid) external onlyRole(DEFAULT_ADMIN_ROLE) {
if (_sid >= _strategyInfo.length) revert IncorrectSid();
_strategyInfo[_sid].enabled = true;
emit EnabledStrategy(address(_strategyInfo[_sid].strategy));
}
function disableStrategy(uint256 _sid) external onlyRole(EMERGENCY_ADMIN_ROLE) {
if (_sid >= _strategyInfo.length) revert IncorrectSid();
_strategyInfo[_sid].enabled = false;
emit DisableStrategy(address(_strategyInfo[_sid].strategy));
}
}
文件 17 的 18:ZunamiPoolZunUSD.sol
pragma solidity ^0.8.23;
import '../../ZunamiPool.sol';
import '../../utils/Constants.sol';
contract ZunamiPoolZunUSD is ZunamiPool {
uint256 public constant ZUNAMI_DAI_TOKEN_ID = 0;
uint256 public constant ZUNAMI_USDC_TOKEN_ID = 1;
uint256 public constant ZUNAMI_USDT_TOKEN_ID = 2;
constructor() ZunamiPool('Zunami USD', 'zunUSD') {
address[POOL_ASSETS] memory tokens;
tokens[ZUNAMI_DAI_TOKEN_ID] = Constants.DAI_ADDRESS;
tokens[ZUNAMI_USDC_TOKEN_ID] = Constants.USDC_ADDRESS;
tokens[ZUNAMI_USDT_TOKEN_ID] = Constants.USDT_ADDRESS;
uint256[POOL_ASSETS] memory tokenDecimalMultipliers;
tokenDecimalMultipliers[ZUNAMI_DAI_TOKEN_ID] = 1;
tokenDecimalMultipliers[ZUNAMI_USDC_TOKEN_ID] = 1e12;
tokenDecimalMultipliers[ZUNAMI_USDT_TOKEN_ID] = 1e12;
_setTokens(tokens, tokenDecimalMultipliers);
}
}
文件 18 的 18:draft-IERC6093.sol
pragma solidity ^0.8.20;
interface IERC20Errors {
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
error ERC20InvalidSender(address sender);
error ERC20InvalidReceiver(address receiver);
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
error ERC20InvalidApprover(address approver);
error ERC20InvalidSpender(address spender);
}
interface IERC721Errors {
error ERC721InvalidOwner(address owner);
error ERC721NonexistentToken(uint256 tokenId);
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
error ERC721InvalidSender(address sender);
error ERC721InvalidReceiver(address receiver);
error ERC721InsufficientApproval(address operator, uint256 tokenId);
error ERC721InvalidApprover(address approver);
error ERC721InvalidOperator(address operator);
}
interface IERC1155Errors {
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
error ERC1155InvalidSender(address sender);
error ERC1155InvalidReceiver(address receiver);
error ERC1155MissingApprovalForAll(address operator, address owner);
error ERC1155InvalidApprover(address approver);
error ERC1155InvalidOperator(address operator);
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}
{
"compilationTarget": {
"contracts/configs/omnipool/ZunamiPoolZunUSD.sol": "ZunamiPoolZunUSD"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"sid","type":"uint256"}],"name":"AbsentStrategy","type":"error"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"sid","type":"uint256"}],"name":"DisabledStrategy","type":"error"},{"inputs":[],"name":"DuplicatedStrategy","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"IncorrectArguments","type":"error"},{"inputs":[],"name":"IncorrectSid","type":"error"},{"inputs":[{"internalType":"uint256","name":"sid","type":"uint256"}],"name":"NotStartedStrategy","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"WrongAmount","type":"error"},{"inputs":[],"name":"WrongDecimalMultipliers","type":"error"},{"inputs":[{"internalType":"uint256","name":"sid","type":"uint256"},{"internalType":"uint256[5]","name":"amounts","type":"uint256[5]"}],"name":"WrongDeposit","type":"error"},{"inputs":[],"name":"WrongRatio","type":"error"},{"inputs":[],"name":"WrongReceiver","type":"error"},{"inputs":[],"name":"WrongTokens","type":"error"},{"inputs":[{"internalType":"uint256","name":"sid","type":"uint256"}],"name":"WrongWithdrawParams","type":"error"},{"inputs":[],"name":"WrongWithdrawPercent","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"sid","type":"uint256"},{"indexed":true,"internalType":"address","name":"strategyAddr","type":"address"},{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"}],"name":"AddedStrategy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ClaimedExtraGains","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"contract IERC20[]","name":"rewardTokens","type":"address[]"}],"name":"ClaimedRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"uint256","name":"deposited","type":"uint256"},{"indexed":false,"internalType":"uint256[5]","name":"amounts","type":"uint256[5]"},{"indexed":true,"internalType":"uint256","name":"sid","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"}],"name":"DisableStrategy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"}],"name":"EnabledStrategy","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"withdrawer","type":"address"},{"indexed":false,"internalType":"uint256[5]","name":"amounts","type":"uint256[5]"},{"indexed":false,"internalType":"uint256","name":"withdrawn","type":"uint256"}],"name":"FailedWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tid","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenDecimalMultiplier","type":"uint256"},{"indexed":false,"internalType":"address","name":"tokenOld","type":"address"}],"name":"UpdatedToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"withdrawer","type":"address"},{"indexed":false,"internalType":"uint256","name":"withdrawn","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"sid","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[],"name":"CONTROLLER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMERGENCY_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FUNDS_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_LIQUIDITY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_LIQUIDITY_LOCKER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_LOCK_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POOL_ASSETS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RATIO_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ZUNAMI_DAI_TOKEN_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ZUNAMI_USDC_TOKEN_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ZUNAMI_USDT_TOKEN_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_strategyAddr","type":"address"}],"name":"addStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"contract IERC20[]","name":"rewardTokens","type":"address[]"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"sid","type":"uint256"},{"internalType":"uint256[5]","name":"amounts","type":"uint256[5]"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sid","type":"uint256"},{"internalType":"uint256[5]","name":"amounts","type":"uint256[5]"}],"name":"depositStrategy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sid","type":"uint256"}],"name":"disableStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sid","type":"uint256"}],"name":"enableStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"extraGains","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"extraGainsMintedBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"launch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"launched","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"mintAndClaimExtraGains","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_strategies","type":"uint256[]"},{"internalType":"uint256[]","name":"_withdrawalsPercents","type":"uint256[]"},{"internalType":"uint256","name":"_receiverStrategy","type":"uint256"},{"internalType":"uint256[5][]","name":"_minAmounts","type":"uint256[5][]"}],"name":"moveFundsBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[5]","name":"tokens_","type":"address[5]"},{"internalType":"uint256[5]","name":"tokenDecimalMultipliers_","type":"uint256[5]"}],"name":"setTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"strategyCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"sid","type":"uint256"}],"name":"strategyInfo","outputs":[{"components":[{"internalType":"contract IStrategy","name":"strategy","type":"address"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"minted","type":"uint256"},{"internalType":"bool","name":"enabled","type":"bool"}],"internalType":"struct IPool.StrategyInfo","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tid","type":"uint256"}],"name":"token","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenDecimalsMultipliers","outputs":[{"internalType":"uint256[5]","name":"","type":"uint256[5]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokens","outputs":[{"internalType":"contract IERC20[5]","name":"","type":"address[5]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalHoldings","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"sid","type":"uint256"},{"internalType":"uint256","name":"stableAmount","type":"uint256"},{"internalType":"uint256[5]","name":"tokenAmounts","type":"uint256[5]"},{"internalType":"address","name":"receiver","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]