Overview
BERA Balance
BERA Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 8,190 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Zap In | 4088046 | 10 mins ago | IN | 0 BERA | 0 | ||||
Zap Out | 4087582 | 25 mins ago | IN | 0 BERA | 0.00037294 | ||||
Zap In | 4086020 | 1 hr ago | IN | 0 BERA | 0 | ||||
Zap Out | 4085944 | 1 hr ago | IN | 0 BERA | 0.00011022 | ||||
Zap In | 4085856 | 1 hr ago | IN | 0 BERA | 0.00008765 | ||||
Zap Out | 4084955 | 1 hr ago | IN | 0 BERA | 0.00018244 | ||||
Zap In | 4084697 | 2 hrs ago | IN | 0 BERA | 0.00002668 | ||||
Zap Out | 4082981 | 2 hrs ago | IN | 0 BERA | 0.00036296 | ||||
Zap In | 4082775 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Zap In | 4082439 | 3 hrs ago | IN | 106.03153188 BERA | 0.00005585 | ||||
Zap In | 4081663 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Zap In | 4081207 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Zap In | 4081172 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Zap In | 4081118 | 3 hrs ago | IN | 0 BERA | 0 | ||||
Zap In | 4081037 | 4 hrs ago | IN | 0.53282176 BERA | 0 | ||||
Zap In | 4081024 | 4 hrs ago | IN | 0 BERA | 0 | ||||
Zap In | 4078339 | 5 hrs ago | IN | 0 BERA | 0 | ||||
Zap In | 4077764 | 5 hrs ago | IN | 0 BERA | 0.00000019 | ||||
Zap Out | 4077539 | 5 hrs ago | IN | 0 BERA | 0 | ||||
Zap Out | 4077461 | 5 hrs ago | IN | 0 BERA | 0 | ||||
Zap In | 4075873 | 6 hrs ago | IN | 0 BERA | 0 | ||||
Zap In | 4075686 | 6 hrs ago | IN | 0 BERA | 0.00000019 | ||||
Zap Out | 4074414 | 7 hrs ago | IN | 0 BERA | 0 | ||||
Zap In | 4074408 | 7 hrs ago | IN | 0 BERA | 0.00000019 | ||||
Zap In | 4074396 | 7 hrs ago | IN | 0 BERA | 0 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
4087582 | 25 mins ago | 69.57456554 BERA | ||||
4087582 | 25 mins ago | 69.57456554 BERA | ||||
4085944 | 1 hr ago | 13.46522399 BERA | ||||
4085944 | 1 hr ago | 13.46522399 BERA | ||||
4082981 | 2 hrs ago | 15.43410758 BERA | ||||
4082981 | 2 hrs ago | 15.43410758 BERA | ||||
4082439 | 3 hrs ago | 106.03153188 BERA | ||||
4081037 | 4 hrs ago | 0.53282176 BERA | ||||
4077539 | 5 hrs ago | 0.22068969 BERA | ||||
4077539 | 5 hrs ago | 0.22068969 BERA | ||||
4077461 | 5 hrs ago | 0.25121323 BERA | ||||
4077461 | 5 hrs ago | 0.25121323 BERA | ||||
4074414 | 7 hrs ago | 15.28669426 BERA | ||||
4074414 | 7 hrs ago | 15.28669426 BERA | ||||
4072944 | 8 hrs ago | 5.51510027 BERA | ||||
4072944 | 8 hrs ago | 5.51510027 BERA | ||||
4069906 | 10 hrs ago | 55.74566427 BERA | ||||
4069906 | 10 hrs ago | 55.74566427 BERA | ||||
4067307 | 11 hrs ago | 15.57370194 BERA | ||||
4067307 | 11 hrs ago | 15.57370194 BERA | ||||
4067281 | 11 hrs ago | 15.50131005 BERA | ||||
4067281 | 11 hrs ago | 15.50131005 BERA | ||||
4067188 | 11 hrs ago | 15.71670323 BERA | ||||
4067188 | 11 hrs ago | 15.71670323 BERA | ||||
4066008 | 12 hrs ago | 74.7838085 BERA |
Loading...
Loading
Contract Name:
InfraredZapper
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 100 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {ZapperBase} from "./ZapperBase.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {IVault} from "../interfaces/IVault.sol"; import {IDexType} from "../interfaces/IDexType.sol"; import {ILpRouter} from "../interfaces/ILpRouter.sol"; import {SphereXProtected} from "@spherex-xyz/contracts/src/SphereXProtected.sol"; import {IBeraPool, IBeraVault, IAsset} from "../interfaces/exchange/Beraswap.sol"; /** * @title InfraredZapper * @notice A zapper contract that enables single-token deposits and withdrawals for Infrared Strategy */ contract InfraredZapper is ZapperBase { using SafeERC20 for IERC20; mapping(address => bool) public isAssetSingleToken; mapping(address => IDexType.DexType) public assetDex; event AssetInfoSet(address asset, bool isSingleToken, IDexType.DexType dex); constructor( address devAddress, address wrappedNative, address stablecoin, address swapRouter, address lpRouter, address feeRecipient, uint16 zapInFee, uint16 zapOutFee ) ZapperBase(devAddress, wrappedNative, stablecoin, swapRouter, lpRouter, feeRecipient, zapInFee, zapOutFee) {} /** * @notice Converts input token amount to vault's asset * @param asset The vault's asset * @param tokenIn The token being deposited * @param tokenInAmount The amount of tokens being deposited * @param recipient The address to receive the asset * @return tokenOutAmount Amount of asset received * @return returnedAssets Array of remaining token balances to be returned to the user */ function swapToAssets( address asset, address tokenIn, uint256 tokenInAmount, address recipient ) public override sphereXGuardPublic(0x07c1e85d, 0x3218e83a) returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets) { // Transfer tokens if needed if (recipient != address(this)) { tokenInAmount = _safeTransferFromTokens(tokenIn, tokenInAmount); } address[] memory tokens; if (isAssetSingleToken[asset]) { IERC20(tokenIn).safeTransfer(address(swapRouter), tokenInAmount); tokenOutAmount = swapRouter.swapWithDefaultDex(address(tokenIn), asset, tokenInAmount, 0, recipient); tokens = new address[](1); tokens[0] = address(tokenIn); returnedAssets = _returnAssets(tokens); return (tokenOutAmount, returnedAssets); } return _swapToAssetsLp(asset, tokenIn, tokenInAmount, recipient); } /** * @notice Converts input token amount to vault's asset * @param asset The vault's asset * @param tokenIn The token being deposited * @param tokenInAmount The amount of tokens being deposited * @param recipient The address to receive the asset * @return tokenOutAmount Amount of asset received * @return returnedAssets Array of remaining token balances to be returned to the user */ function _swapToAssetsLp( address asset, address tokenIn, uint256 tokenInAmount, address recipient ) internal returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets) { // Add liquidity IERC20(tokenIn).safeTransfer(address(lpRouter), tokenInAmount); tokenOutAmount = lpRouter.addLiquidity(asset, tokenIn, tokenInAmount, recipient, assetDex[asset]); // Return assets address[] memory checkTokens = new address[](1); checkTokens[0] = tokenIn; returnedAssets = _returnAssets(checkTokens); } /** * @notice Converts vault's asset to output token * @param asset The vault's asset * @param tokenOut The token the user wants to receive * @param assetsInAmount The amount of LP tokens being withdrawn * @param recipient The address to receive the output token * @return tokenOutAmount The amount of desired tokens received * @return returnedAssets Array of remaining token balances to be returned to the user */ function swapFromAssets( address asset, address tokenOut, uint256 assetsInAmount, address recipient ) public override sphereXGuardPublic(0x362279f7, 0xf99e6387) returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets) { // Transfer tokens if needed if (recipient != address(this)) { assetsInAmount = _safeTransferFromTokens(asset, assetsInAmount); } if (isAssetSingleToken[asset]) { IERC20(asset).safeTransfer(address(swapRouter), assetsInAmount); tokenOutAmount = swapRouter.swapWithDefaultDex(asset, tokenOut, assetsInAmount, 0, recipient); address[] memory tokens = new address[](1); tokens[0] = asset; returnedAssets = _returnAssets(tokens); return (tokenOutAmount, returnedAssets); } return _swapFromAssetsLp(asset, tokenOut, assetsInAmount, recipient); } /** * @notice Converts vault's asset to output token * @param asset The vault's asset * @param tokenOut The token the user wants to receive * @param assetsInAmount The amount of LP tokens being withdrawn * @param recipient The address to receive the output token * @return tokenOutAmount The amount of desired tokens received * @return returnedAssets Array of remaining token balances to be returned to the user */ function _swapFromAssetsLp( address asset, address tokenOut, uint256 assetsInAmount, address recipient ) internal returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets) { // Remove liquidity IERC20(asset).safeTransfer(address(lpRouter), assetsInAmount); tokenOutAmount = lpRouter.removeLiquidity(asset, assetsInAmount, recipient, tokenOut, assetDex[asset]); if (recipient != address(this)) { _returnAsset(tokenOut, recipient); } address[] memory checkTokens = new address[](1); checkTokens[0] = address(0); returnedAssets = _returnAssets(checkTokens); } function setAssetInfo(address asset, bool isSingleToken, IDexType.DexType dex) external onlyGovernance { _revertAddressZero(asset); isAssetSingleToken[asset] = isSingleToken; assetDex[asset] = dex; emit AssetInfoSet(asset, isSingleToken, dex); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol) pragma solidity ^0.8.20; import {IERC20} from "../token/ERC20/IERC20.sol"; import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; /** * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. */ interface IERC4626 is IERC20, IERC20Metadata { event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); event Withdraw( address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares ); /** * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. * * - MUST be an ERC-20 token contract. * - MUST NOT revert. */ function asset() external view returns (address assetTokenAddress); /** * @dev Returns the total amount of the underlying asset that is “managed” by Vault. * * - SHOULD include any compounding that occurs from yield. * - MUST be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT revert. */ function totalAssets() external view returns (uint256 totalManagedAssets); /** * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToShares(uint256 assets) external view returns (uint256 shares); /** * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal * scenario where all the conditions are met. * * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. * - MUST NOT show any variations depending on the caller. * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. * - MUST NOT revert. * * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and * from. */ function convertToAssets(uint256 shares) external view returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, * through a deposit call. * * - MUST return a limited value if receiver is subject to some deposit limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. * - MUST NOT revert. */ function maxDeposit(address receiver) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given * current on-chain conditions. * * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called * in the same transaction. * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the * deposit would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewDeposit(uint256 assets) external view returns (uint256 shares); /** * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * deposit execution, and are accounted for during deposit. * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function deposit(uint256 assets, address receiver) external returns (uint256 shares); /** * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. * - MUST return a limited value if receiver is subject to some mint limit. * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. * - MUST NOT revert. */ function maxMint(address receiver) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given * current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the * same transaction. * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint * would be accepted, regardless if the user has enough tokens approved, etc. * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by minting. */ function previewMint(uint256 shares) external view returns (uint256 assets); /** * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. * * - MUST emit the Deposit event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint * execution, and are accounted for during mint. * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not * approving enough underlying tokens to the Vault contract, etc). * * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. */ function mint(uint256 shares, address receiver) external returns (uint256 assets); /** * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the * Vault, through a withdraw call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST NOT revert. */ function maxWithdraw(address owner) external view returns (uint256 maxAssets); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, * given current on-chain conditions. * * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if * called * in the same transaction. * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though * the withdrawal would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by depositing. */ function previewWithdraw(uint256 assets) external view returns (uint256 shares); /** * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * withdraw execution, and are accounted for during withdraw. * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); /** * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, * through a redeem call. * * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. * - MUST NOT revert. */ function maxRedeem(address owner) external view returns (uint256 maxShares); /** * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, * given current on-chain conditions. * * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the * same transaction. * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the * redemption would be accepted, regardless if the user has enough shares, etc. * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. * - MUST NOT revert. * * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in * share price or some other type of condition, meaning the depositor will lose assets by redeeming. */ function previewRedeem(uint256 shares) external view returns (uint256 assets); /** * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. * * - MUST emit the Withdraw event. * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the * redeem execution, and are accounted for during redeem. * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner * not having enough shares, etc). * * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. * Those methods should be performed separately. */ function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. * * ==== Security Considerations * * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be * considered as an intention to spend the allowance in any specific way. The second is that because permits have * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be * generally recommended is: * * ```solidity * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} * doThing(..., value); * } * * function doThing(..., uint256 value) public { * token.safeTransferFrom(msg.sender, address(this), value); * ... * } * ``` * * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also * {SafeERC20-safeTransferFrom}). * * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so * contracts should have entry points that don't rely on permit. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. * * CAUTION: See Security Considerations above. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.20; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the value of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the value of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves a `value` amount of tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 value) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets a `value` amount of tokens as the allowance of `spender` over the * caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 value) external returns (bool); /** * @dev Moves a `value` amount of tokens from `from` to `to` using the * allowance mechanism. `value` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 value) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.20; import {IERC20} from "../IERC20.sol"; import {IERC20Permit} from "../extensions/IERC20Permit.sol"; import {Address} from "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; /** * @dev An operation with an ERC20 token failed. */ error SafeERC20FailedOperation(address token); /** * @dev Indicates a failed `decreaseAllowance` request. */ error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); /** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeTransfer(IERC20 token, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value))); } /** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */ function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value))); } /** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */ function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 oldAllowance = token.allowance(address(this), spender); forceApprove(token, spender, oldAllowance + value); } /** * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no * value, non-reverting calls are assumed to be successful. */ 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); } } /** * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval * to be set to zero before setting it to a non-zero value, such as USDT. */ 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); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data); if (returndata.length != 0 && !abi.decode(returndata, (bool))) { revert SafeERC20FailedOperation(address(token)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). * * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead. */ function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false // and not revert is the subcall reverts. (bool success, bytes memory returndata) = address(token).call(data); return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) pragma solidity ^0.8.20; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev The ETH balance of the account is not enough to perform the operation. */ error AddressInsufficientBalance(address account); /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @dev A call to an address target failed. The target may have reverted. */ error FailedInnerCall(); /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ 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(); } } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {FailedInnerCall} error. * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ 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); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ 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); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an * unsuccessful call. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { if (!success) { _revert(returndata); } else { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (returndata.length == 0 && target.code.length == 0) { revert AddressEmptyCode(target); } return returndata; } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {FailedInnerCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (!success) { _revert(returndata); } else { return returndata; } } /** * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. */ function _revert(bytes memory returndata) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert FailedInnerCall(); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) pragma solidity ^0.8.20; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; uint256 private _status; /** * @dev Unauthorized reentrant call. */ error ReentrancyGuardReentrantCall(); constructor() { _status = NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be NOT_ENTERED if (_status == ENTERED) { revert ReentrancyGuardReentrantCall(); } // Any calls to nonReentrant after this point will fail _status = ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == ENTERED; } }
// SPDX-License-Identifier: UNLICENSED // (c) SphereX 2023 Terms&Conditions pragma solidity ^0.8.0; /** * @title Interface for SphereXEngine - definitions of core functionality * @author SphereX Technologies ltd * @notice This interface is imported by SphereXProtected, so that SphereXProtected can call functions from SphereXEngine * @dev Full docs of these functions can be found in SphereXEngine */ interface ISphereXEngine { function sphereXValidatePre(int256 num, address sender, bytes calldata data) external returns (bytes32[] memory); function sphereXValidatePost( int256 num, uint256 gas, bytes32[] calldata valuesBefore, bytes32[] calldata valuesAfter ) external; function sphereXValidateInternalPre(int256 num) external returns (bytes32[] memory); function sphereXValidateInternalPost( int256 num, uint256 gas, bytes32[] calldata valuesBefore, bytes32[] calldata valuesAfter ) external; function addAllowedSenderOnChain(address sender) external; /** * This function is taken as is from OZ IERC165, we don't inherit from OZ * to avoid collisions with the customer OZ version. * * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } /** * @dev this struct is used to reduce the stack usage of the modifiers. */ struct ModifierLocals { bytes32[] storageSlots; bytes32[] valuesBefore; uint256 gas; address engine; }
// SPDX-License-Identifier: UNLICENSED // (c) SphereX 2023 Terms&Conditions pragma solidity ^0.8.0; import {ISphereXEngine, ModifierLocals} from "./ISphereXEngine.sol"; /** * @title SphereX base Customer contract template */ /// @custom:oz-upgrades-unsafe-allow constructor abstract contract SphereXConfiguration { /** * @dev we would like to avoid occupying storage slots * @dev to easily incorporate with existing contracts */ bytes32 private constant SPHEREX_ADMIN_STORAGE_SLOT = bytes32(uint256(keccak256("eip1967.spherex.spherex")) - 1); bytes32 private constant SPHEREX_PENDING_ADMIN_STORAGE_SLOT = bytes32(uint256(keccak256("eip1967.spherex.pending")) - 1); bytes32 private constant SPHEREX_OPERATOR_STORAGE_SLOT = bytes32(uint256(keccak256("eip1967.spherex.operator")) - 1); bytes32 private constant SPHEREX_ENGINE_STORAGE_SLOT = bytes32(uint256(keccak256("eip1967.spherex.spherex_engine")) - 1); event ChangedSpherexOperator(address oldSphereXAdmin, address newSphereXAdmin); event ChangedSpherexEngineAddress(address oldEngineAddress, address newEngineAddress); event SpherexAdminTransferStarted(address currentAdmin, address pendingAdmin); event SpherexAdminTransferCompleted(address oldAdmin, address newAdmin); event NewAllowedSenderOnchain(address sender); /** * @dev used when the client doesn't use a proxy */ constructor(address admin, address operator, address engine) { __SphereXProtectedBase_init(admin, operator, engine); } /** * @dev used when the client uses a proxy - should be called by the inhereter initialization */ function __SphereXProtectedBase_init(address admin, address operator, address engine) internal virtual { _setAddress(SPHEREX_ADMIN_STORAGE_SLOT, admin); emit SpherexAdminTransferCompleted(address(0), admin); _setAddress(SPHEREX_OPERATOR_STORAGE_SLOT, operator); emit ChangedSpherexOperator(address(0), operator); _checkSphereXEngine(engine); _setAddress(SPHEREX_ENGINE_STORAGE_SLOT, engine); emit ChangedSpherexEngineAddress(address(0), engine); } // ============ Helper functions ============ function _sphereXEngine() internal view returns (ISphereXEngine) { return ISphereXEngine(_getAddress(SPHEREX_ENGINE_STORAGE_SLOT)); } /** * Stores a new address in an arbitrary slot * @param slot where to store the address * @param newAddress address to store in given slot */ function _setAddress(bytes32 slot, address newAddress) internal { // solhint-disable-next-line no-inline-assembly // slither-disable-next-line assembly assembly { sstore(slot, newAddress) } } /** * Returns an address from an arbitrary slot. * @param slot to read an address from */ function _getAddress(bytes32 slot) internal view returns (address addr) { // solhint-disable-next-line no-inline-assembly // slither-disable-next-line assembly assembly { addr := sload(slot) } } // ============ Local modifiers ============ modifier onlySphereXAdmin() { require(msg.sender == _getAddress(SPHEREX_ADMIN_STORAGE_SLOT), "SphereX error: admin required"); _; } modifier onlySpherexOperator() { require(msg.sender == _getAddress(SPHEREX_OPERATOR_STORAGE_SLOT), "SphereX error: operator required"); _; } modifier returnsIfNotActivated() { if (address(_sphereXEngine()) == address(0)) { return; } _; } // ============ Management ============ /** * Returns the currently pending admin address, the one that can call acceptSphereXAdminRole to become the admin. * @dev Could not use OZ Ownable2Step because the client's contract might use it. */ function pendingSphereXAdmin() public view returns (address) { return _getAddress(SPHEREX_PENDING_ADMIN_STORAGE_SLOT); } /** * Returns the current admin address, the one that can call acceptSphereXAdminRole to become the admin. * @dev Could not use OZ Ownable2Step because the client's contract might use it. */ function sphereXAdmin() public view returns (address) { return _getAddress(SPHEREX_ADMIN_STORAGE_SLOT); } /** * Returns the current operator address. */ function sphereXOperator() public view returns (address) { return _getAddress(SPHEREX_OPERATOR_STORAGE_SLOT); } /** * Returns the current engine address. */ function sphereXEngine() public view returns (address) { return _getAddress(SPHEREX_ENGINE_STORAGE_SLOT); } /** * Setting the address of the next admin. this address will have to accept the role to become the new admin. * @dev Could not use OZ Ownable2Step because the client's contract might use it. */ function transferSphereXAdminRole(address newAdmin) public virtual onlySphereXAdmin { _setAddress(SPHEREX_PENDING_ADMIN_STORAGE_SLOT, newAdmin); emit SpherexAdminTransferStarted(sphereXAdmin(), newAdmin); } /** * Accepting the admin role and completing the transfer. * @dev Could not use OZ Ownable2Step because the client's contract might use it. */ function acceptSphereXAdminRole() public virtual { require(pendingSphereXAdmin() == msg.sender, "SphereX error: not the pending account"); address oldAdmin = sphereXAdmin(); _setAddress(SPHEREX_ADMIN_STORAGE_SLOT, msg.sender); _setAddress(SPHEREX_PENDING_ADMIN_STORAGE_SLOT, address(0)); emit SpherexAdminTransferCompleted(oldAdmin, msg.sender); } /** * * @param newSphereXOperator new address of the new operator account */ function changeSphereXOperator(address newSphereXOperator) external onlySphereXAdmin { address oldSphereXOperator = _getAddress(SPHEREX_OPERATOR_STORAGE_SLOT); _setAddress(SPHEREX_OPERATOR_STORAGE_SLOT, newSphereXOperator); emit ChangedSpherexOperator(oldSphereXOperator, newSphereXOperator); } /** * Checks the given address implements ISphereXEngine or is address(0) * @param newSphereXEngine new address of the spherex engine */ function _checkSphereXEngine(address newSphereXEngine) private view { require( newSphereXEngine == address(0) || ISphereXEngine(newSphereXEngine).supportsInterface(type(ISphereXEngine).interfaceId), "SphereX error: not a SphereXEngine" ); } /** * * @param newSphereXEngine new address of the spherex engine * @dev this is also used to actually enable the defense * (because as long is this address is 0, the protection is disabled). */ function changeSphereXEngine(address newSphereXEngine) external onlySpherexOperator { _checkSphereXEngine(newSphereXEngine); address oldEngine = _getAddress(SPHEREX_ENGINE_STORAGE_SLOT); _setAddress(SPHEREX_ENGINE_STORAGE_SLOT, newSphereXEngine); emit ChangedSpherexEngineAddress(oldEngine, newSphereXEngine); } // ============ Engine interaction ============ function _addAllowedSenderOnChain(address newSender) internal { ISphereXEngine engine = _sphereXEngine(); if (address(engine) != address(0)) { engine.addAllowedSenderOnChain(newSender); emit NewAllowedSenderOnchain(newSender); } } }
// SPDX-License-Identifier: UNLICENSED // (c) SphereX 2023 Terms&Conditions pragma solidity ^0.8.0; import {SphereXProtectedBase} from "./SphereXProtectedBase.sol"; /** * @title SphereX base Customer contract template * @dev notice this is an abstract */ abstract contract SphereXProtected is SphereXProtectedBase(msg.sender, address(0), address(0)) {}
// SPDX-License-Identifier: UNLICENSED // (c) SphereX 2023 Terms&Conditions pragma solidity ^0.8.0; import {ISphereXEngine, ModifierLocals} from "./ISphereXEngine.sol"; import {SphereXConfiguration} from "./SphereXConfiguration.sol"; /** * @title SphereX base Customer contract template */ /// @custom:oz-upgrades-unsafe-allow constructor abstract contract SphereXProtectedBase is SphereXConfiguration { constructor(address admin, address operator, address engine) SphereXConfiguration(admin, operator, engine) {} // ============ Hooks ============ /** * @dev internal function for engine communication. We use it to reduce contract size. * Should be called before the code of a function. * @param num function identifier * @param isExternalCall set to true if this was called externally * or a 'public' function from another address */ function _sphereXValidatePre(int256 num, bool isExternalCall) private returnsIfNotActivated returns (ModifierLocals memory locals) { ISphereXEngine engine = _sphereXEngine(); if (isExternalCall) { locals.storageSlots = engine.sphereXValidatePre(num, msg.sender, msg.data); } else { locals.storageSlots = engine.sphereXValidateInternalPre(num); } locals.valuesBefore = _readStorage(locals.storageSlots); locals.gas = gasleft(); locals.engine = address(engine); return locals; } /** * @dev internal function for engine communication. We use it to reduce contract size. * Should be called after the code of a function. * @param num function identifier * @param isExternalCall set to true if this was called externally * or a 'public' function from another address */ function _sphereXValidatePost(int256 num, bool isExternalCall, ModifierLocals memory locals) private { ISphereXEngine engine = ISphereXEngine(locals.engine); if (address(engine) == address(0)) { return; } uint256 gas = locals.gas - gasleft(); bytes32[] memory valuesAfter; valuesAfter = _readStorage(locals.storageSlots); if (isExternalCall) { engine.sphereXValidatePost(num, gas, locals.valuesBefore, valuesAfter); } else { engine.sphereXValidateInternalPost(num, gas, locals.valuesBefore, valuesAfter); } } // ============ Modifiers ============ /** * @dev Modifier to be incorporated in all internal protected non-view functions */ modifier sphereXGuardInternal(int256 num) { ModifierLocals memory locals = _sphereXValidatePre(num, false); _; _sphereXValidatePost(-num, false, locals); } /** * @dev Modifier to be incorporated in all external protected non-view functions */ modifier sphereXGuardExternal(int256 num) { ModifierLocals memory locals = _sphereXValidatePre(num, true); _; _sphereXValidatePost(-num, true, locals); } /** * @dev Modifier to be incorporated in all public protected non-view functions */ modifier sphereXGuardPublic(int256 num, bytes4 selector) { ModifierLocals memory locals = _sphereXValidatePre(num, msg.sig == selector); _; _sphereXValidatePost(-num, msg.sig == selector, locals); } // ============ Internal Storage logic ============ /** * Internal function that reads values from given storage slots and returns them * @param storageSlots list of storage slots to read * @return list of values read from the various storage slots */ function _readStorage(bytes32[] memory storageSlots) internal view returns (bytes32[] memory) { uint256 arrayLength = storageSlots.length; bytes32[] memory values = new bytes32[](arrayLength); // create the return array data for (uint256 i = 0; i < arrayLength; i++) { bytes32 slot = storageSlots[i]; bytes32 temp_value; // solhint-disable-next-line no-inline-assembly // slither-disable-next-line assembly assembly { temp_value := sload(slot) } values[i] = temp_value; } return values; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IAsset { // solhint-disable-previous-line no-empty-blocks } interface IBeraVault { struct SingleSwap { bytes32 poolId; SwapKind kind; IAsset assetIn; IAsset assetOut; uint256 amount; bytes userData; } struct BatchSwapStep { bytes32 poolId; uint256 assetInIndex; uint256 assetOutIndex; uint256 amount; bytes userData; } struct FundManagement { address sender; bool fromInternalBalance; address payable recipient; bool toInternalBalance; } struct JoinPoolRequest { IAsset[] assets; uint256[] maxAmountsIn; bytes userData; bool fromInternalBalance; } struct ExitPoolRequest { IAsset[] assets; uint256[] minAmountsOut; bytes userData; bool toInternalBalance; } enum PoolSpecialization { GENERAL, MINIMAL_SWAP_INFO, TWO_TOKEN } enum SwapKind { GIVEN_IN, GIVEN_OUT } function getPoolTokens( bytes32 poolId ) external view returns (IERC20[] memory tokens, uint256[] memory balances, uint256 lastChangeBlock); function getPool(bytes32 poolId) external view returns (address, PoolSpecialization); function swap( SingleSwap memory singleSwap, FundManagement memory funds, uint256 limit, uint256 deadline ) external returns (uint256 amountCalculated); function batchSwap( SwapKind kind, BatchSwapStep[] memory swaps, IAsset[] memory assets, FundManagement memory funds, int256[] memory limits, uint256 deadline ) external payable returns (int256[] memory); function joinPool(bytes32 poolId, address sender, address recipient, JoinPoolRequest memory request) external payable; function exitPool(bytes32 poolId, address sender, address payable recipient, ExitPoolRequest memory request) external; } interface IBeraPool { function getPoolId() external view returns (bytes32); function getVault() external view returns (address); function balanceOf(address account) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IWETH is IERC20 { function name() external view returns (string memory); function approve(address guy, uint256 wad) external returns (bool); function totalSupply() external view returns (uint256); function transferFrom(address src, address dst, uint256 wad) external returns (bool); function withdraw(uint256 wad) external; function withdrawTo(address account, uint256 amount) external; function decimals() external view returns (uint8); function balanceOf(address) external view returns (uint256); function symbol() external view returns (string memory); function transfer(address dst, uint256 wad) external returns (bool); function deposit() external payable; function allowance(address, address) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; interface IDexType { /// @notice Enum representing different DEX types enum DexType { UNISWAP_V2, // 0 UNISWAP_V3, // 1 SUSHISWAP_V2, // 2 SUSHISWAP_V3, // 3 CAMELOT_V3, // 4 BEX, // 5 KODIAK_V3, // 6 KODIAK_V2, // 7 STEER, // 8 GAMMA // 9 } /// @notice Emitted when the default DEX is set /// @param dex The DEX index event SetDefaultDex(uint8 dex); /// @notice Thrown when trying to use an unsupported DEX type error UnsupportedDexType(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {IDexType} from "./IDexType.sol"; interface ILpRouter is IDexType { /// @notice Thrown when router arrays have mismatched lengths error InvalidRouterLength(); /// @notice Thrown when router address is zero error ZeroRouterAddress(); /// @notice Thrown when address is zero error ZeroAddress(); /// @notice Thrown when a function is called by an address that isn't governance error NotGovernance(); /// @notice Thrown when total ratio is zero error TotalRatioZero(); /// @notice Emitted when the governance is updated event GovernanceUpdated(address indexed oldGovernance, address indexed newGovernance); /// @notice Emitted when a router is set for a DEX /// @param dex The DEX index /// @param router The router address event SetRouter(uint8 dex, address indexed router); /// @notice Emitted when a swap router is set /// @param swapRouter The swap router address event SetSwapRouter(address indexed old, address indexed swapRouter); struct LiquidityAddInfo { address lp; address token0; address token1; uint256 amount0; uint256 amount1; } struct LiquidityRemoveInfo { address lp; uint256 lpAmount; address token0; address token1; address recipient; } function addLiquidity( address lp, address tokenIn, uint256 amountIn, address recipient, DexType dexType ) external returns (uint256 lpAmountOut); function removeLiquidity( address lp, uint256 lpAmount, address recipient, address tokenOut, DexType dexType ) external returns (uint256 tokenOutAmount); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {IDexType} from "./IDexType.sol"; import {IBeraPool} from "./exchange/Beraswap.sol"; /** * @title ISwapRouter * @notice Interface for the SwapRouter contract that handles token swaps across multiple DEXes */ interface ISwapRouter is IDexType { // Errors /// @notice Thrown when router arrays have mismatched lengths error InvalidRouterLength(); /// @notice Thrown when router/factory arrays have mismatched lengths error InvalidFactoryLength(); /// @notice Thrown when path length is less than 2 error InvalidPathLength(); /// @notice Thrown when address is zero error ZeroAddress(); /// @notice Thrown when router address is zero error ZeroRouterAddress(); /// @notice Thrown when trying to use an unsupported factory error FactoryNotSupported(); /// @notice Thrown when trying to use an unsupported router error RouterNotSupported(); /// @notice Thrown when no pool is found for a multihop swap error NoPoolFoundForMultihopSwap(); /// @notice Thrown when no pool is found for a multihop quote error NoPoolFoundForMultihopQuote(); /// @notice Thrown when output amount is less than minimum /// @param amountOut Actual output amount /// @param amountOutMinimum Minimum required output amount error InsufficientOutputAmount(uint256 amountOut, uint256 amountOutMinimum); /// @notice Thrown when amount is zero error ZeroAmount(); /// @notice Thrown when a function is called by an address that isn't governance error NotGovernance(); /// @notice Thrown when no swap route is found error NoSwapRouteFound(); /// @notice Thrown when path length exceeds the maximum error PathLengthExceeded(); /// @notice Thrown when no pool is found for a token pair error NoPoolFound(); // Events /// @notice Emitted when the governance is updated event GovernanceUpdated(address indexed oldGovernance, address indexed newGovernance); /// @notice Emitted when a router is set for a DEX /// @param dex The DEX index /// @param router The router address event SetRouter(uint8 dex, address indexed router); /// @notice Emitted when a factory is set for a DEX /// @param dex The DEX index /// @param factory The factory address event SetFactory(uint8 dex, address indexed factory); /// @notice Emitted when a pool is set /// @param tokenIn The input token address /// @param tokenOut The output token address /// @param pool The pool address event SetPool(address indexed tokenIn, address indexed tokenOut, address pool); /// @notice Emitted when a swap route is set /// @param tokenIn The input token address /// @param tokenOut The output token address /// @param path The swap route path /// @param reversePath Whether to set the inverse swap route event SetSwapRoute(address indexed tokenIn, address indexed tokenOut, SwapRoutePath[] path, bool reversePath); /// @notice Struct for a swap route path /// @param tokenIn The input token address /// @param tokenOut The output token address /// @param dex The DEX type /// @param isMultiPath Whether the path is a multi-path swap /// @param pool The pool address struct SwapRoutePath { address tokenIn; address tokenOut; DexType dex; bool isMultiPath; address pool; } // Functions /// @notice Returns the wrapped native token address (e.g. WETH) /// @return The address of the wrapped native token function wrappedNative() external view returns (address); /// @notice Returns the router address for a given DEX /// @param dex The DEX index /// @return The router address function routers(uint8 dex) external view returns (address); /// @notice Returns the factory address for a given DEX /// @param dex The DEX index /// @return The factory address function factories(uint8 dex) external view returns (address); /// @notice Returns the default DEX type used for swaps /// @return The default DexType enum value function defaultDex() external view returns (DexType); /// @notice Swaps tokens using the default DEX /// @param tokenIn The input token address /// @param tokenOut The output token address /// @param amountIn The amount of input tokens /// @param amountOutMinimum The minimum amount of output tokens required /// @param recipient The address that will receive the output tokens /// @return amountOut The amount of output tokens received function swapWithDefaultDex( address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOutMinimum, address recipient ) external returns (uint256 amountOut); /// @notice Swaps tokens using a specified DEX /// @param tokenIn The input token address /// @param tokenOut The output token address /// @param amountIn The amount of input tokens /// @param amountOutMinimum The minimum amount of output tokens required /// @param recipient The address that will receive the output tokens /// @param dex The DEX to use for the swap /// @return amountOut The amount of output tokens received function swap( address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOutMinimum, address recipient, DexType dex ) external returns (uint256 amountOut); /// @notice Performs a multi-hop swap using the default DEX /// @param path Array of token addresses representing the swap path /// @param amountIn The amount of input tokens /// @param amountOutMinimum The minimum amount of output tokens required /// @param recipient The address that will receive the output tokens /// @return amountOut The amount of output tokens received function swapWithPathWithDefaultDex( address[] calldata path, uint256 amountIn, uint256 amountOutMinimum, address recipient ) external returns (uint256 amountOut); /// @notice Performs a multi-hop swap using a specified DEX /// @param path Array of token addresses representing the swap path /// @param amountIn The amount of input tokens /// @param amountOutMinimum The minimum amount of output tokens required /// @param recipient The address that will receive the output tokens /// @param dex The DEX to use for the swap /// @return amountOut The amount of output tokens received function swapWithPath( address[] calldata path, uint256 amountIn, uint256 amountOutMinimum, address recipient, DexType dex ) external returns (uint256 amountOut); /// @notice Gets a quote for a swap using the default DEX /// @param tokenIn The input token address /// @param tokenOut The output token address /// @param amountIn The amount of input tokens /// @return amountOut The expected amount of output tokens function getQuoteWithDefaultDex( address tokenIn, address tokenOut, uint256 amountIn ) external view returns (uint256 amountOut); /// @notice Gets a quote for a swap using a specified DEX /// @param tokenIn The input token address /// @param tokenOut The output token address /// @param amountIn The amount of input tokens /// @param dex The DEX to use for the quote /// @return amountOut The expected amount of output tokens function getQuote( address tokenIn, address tokenOut, uint256 amountIn, DexType dex ) external view returns (uint256 amountOut); /// @notice Gets a quote for a multi-hop swap using the default DEX /// @param path Array of token addresses representing the swap path /// @param amountIn The amount of input tokens /// @return amountOut The expected amount of output tokens function getQuoteWithPathWithDefaultDex( address[] memory path, uint256 amountIn ) external view returns (uint256 amountOut); /// @notice Gets a quote for a multi-hop swap using a specified DEX /// @param path Array of token addresses representing the swap path /// @param amountIn The amount of input tokens /// @param dex The DEX to use for the quote /// @return amountOut The expected amount of output tokens function getQuoteWithPath( address[] memory path, uint256 amountIn, DexType dex ) external view returns (uint256 amountOut); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; /** * @title IVault * @notice Interface for Contrax Vault functionality */ interface IVault is IERC4626 { // Errors /// @notice Thrown when attempting to set a zero address error ZeroAddress(); /// @notice Thrown when a caller is not the governance address error NotGovernance(); /// @notice Thrown when a caller is not the timelock address error NotTimelock(); /// @notice Thrown when a caller is not the controller address error NotController(); /// @notice Thrown when attempting to set min ratio higher than max error MinGreaterThanMax(); /// @notice Thrown when attempting to harvest the vault's underlying asset error CannotHarvestAsset(); /// @notice Thrown when deposit results in fewer shares than minimum specified error InsufficientOutputShares(uint256 shares, uint256 minShares); /// @notice Thrown when redemption results in fewer assets than minimum specified error InsufficientOutputAssets(uint256 assets, uint256 minAssets); /// @notice Thrown when a fee is set that is greater than the maximum allowed error FeeTooHigh(uint16 fee, uint16 maxFee); /// @notice Thrown when there are no funds to earn error NoFundsToEarn(); // Events /// @notice Emitted when the governance address is updated /// @param oldGovernance The old governance address /// @param newGovernance The new governance address event GovernanceChanged(address indexed oldGovernance, address indexed newGovernance); /// @notice Emitted when the timelock address is updated /// @param oldTimelock The old timelock address /// @param newTimelock The new timelock address event TimelockChanged(address indexed oldTimelock, address indexed newTimelock); /// @notice Emitted when the controller address is updated /// @param oldController The old controller address /// @param newController The new controller address event ControllerChanged(address indexed oldController, address indexed newController); /// @notice Emitted when the minimum ratio is updated /// @param oldMin The old minimum ratio /// @param newMin The new minimum ratio event MinChanged(uint256 oldMin, uint256 newMin); /// @notice Emitted when the deposit fee is updated /// @param oldFee The old deposit fee /// @param newFee The new deposit fee event DepositFeeChanged(uint16 oldFee, uint16 newFee); /// @notice Emitted when the withdraw fee is updated /// @param oldFee The old withdraw fee /// @param newFee The new withdraw fee event WithdrawFeeChanged(uint16 oldFee, uint16 newFee); // Functions /// @notice Sends available assets to controller to be invested in strategy function earn() external; /// @notice Calculates amount of assets available to be sent to strategy /// @return uint256 Amount of assets available function available() external view returns (uint256); /// @notice Deposits assets with minimum shares check /// @param assets Amount of assets to deposit /// @param receiver Address receiving the shares /// @param minShares Minimum shares that must be minted /// @return shares Amount of shares minted function deposit(uint256 assets, address receiver, uint256 minShares) external returns (uint256 shares); /// @notice Redeems shares with minimum assets check /// @param shares Amount of shares to redeem /// @param receiver Address receiving the assets /// @param owner Address that owns the shares /// @param minAssets Minimum assets that must be returned /// @return assets Amount of assets returned function redeem(uint256 shares, address receiver, address owner, uint256 minAssets) external returns (uint256 assets); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {IWETH} from "../interfaces/exchange/IWETH.sol"; import {ISwapRouter} from "../interfaces/ISwapRouter.sol"; import {IVault} from "../interfaces/IVault.sol"; /** * @title IZapper Interface * @notice Interface for contracts that enable deposits/withdrawals from vaults using any token * @dev Implements functionality for converting tokens and interacting with vaults */ interface IZapper { // Structs /** * @notice Struct to track leftover tokens returned to users * @param tokens Address of the token * @param amounts Amount of tokens returned */ struct ReturnedAsset { address tokens; uint256 amounts; } // Errors /// @notice Thrown when a non-governance address calls a governance-only function error NotGovernance(); /// @notice Thrown when a zero address is provided error ZeroAddress(); /// @notice Thrown when input amount is below minimum required error InsufficientInputAmount(address token, uint256 provided, uint256 minimum); /// @notice Thrown when token approval is missing error TokenNotApproved(); /// @notice Thrown when ETH transfer fails error ETHTransferFailed(); /// @notice Thrown when output amount is below minimum required error InsufficientOutputAmount(address token, uint256 received, uint256 minimum); /// @notice Thrown when fee percentage is too high error FeeTooHigh(uint16 fee, uint16 maxFee); /// @notice Thrown when total ratio is zero error TotalRatioZero(); // Events /// @notice Emitted when swap router address is updated /// @param newSwapRouter Address of the new swap router /// @param oldSwapRouter Address of the previous swap router event SwapRouterChanged(address indexed newSwapRouter, address indexed oldSwapRouter); /// @notice Emitted when stablecoin address is updated /// @param newStableCoin Address of the new stablecoin /// @param oldStableCoin Address of the previous stablecoin event StableCoinChanged(address indexed newStableCoin, address indexed oldStableCoin); /// @notice Emitted when governance address is updated /// @param newGovernance Address of the new governance /// @param oldGovernance Address of the previous governance event GovernanceChanged(address indexed newGovernance, address indexed oldGovernance); /// @notice Emitted when lp router address is updated /// @param newLpRouter Address of the new lp router /// @param oldLpRouter Address of the previous lp router event LpRouterChanged(address indexed newLpRouter, address indexed oldLpRouter); /// @notice Emitted when zapIn fee is updated /// @param oldFee Previous fee percentage in basis points /// @param newFee New fee percentage in basis points event ZapInFeeChanged(uint16 oldFee, uint16 newFee); /// @notice Emitted when zapOut fee is updated /// @param oldFee Previous fee percentage in basis points /// @param newFee New fee percentage in basis points event ZapOutFeeChanged(uint16 oldFee, uint16 newFee); /// @notice Emitted when fee recipient is updated /// @param oldRecipient Address of the previous fee recipient /// @param newRecipient Address of the new fee recipient event FeeRecipientChanged(address indexed oldRecipient, address indexed newRecipient); /// @notice Emitted when tokens are deposited into a vault /// @param user Address of the depositor /// @param vault Address of the target vault /// @param tokenIn Address of the input token /// @param tokenInAmount Amount of input tokens /// @param assetsIn Amount of assets deposited /// @param shares Amount of vault shares received /// @param fee Amount of fee paid /// @param returnedAssets Array of any remaining tokens returned to caller event ZapIn( address indexed user, address indexed vault, address tokenIn, uint256 tokenInAmount, uint256 assetsIn, uint256 shares, uint256 fee, ReturnedAsset[] returnedAssets ); /// @notice Emitted when tokens are withdrawn from a vault /// @param user Address of the withdrawer /// @param vault Address of the source vault /// @param tokenOut Address of the output token /// @param tokenOutAmount Amount of output tokens /// @param assetsOut Amount of assets withdrawn /// @param shares Amount of vault shares withdrawn /// @param fee Amount of fee paid /// @param returnedAssets Array of any remaining tokens returned to caller event ZapOut( address indexed user, address indexed vault, address tokenOut, uint256 tokenOutAmount, uint256 assetsOut, uint256 shares, uint256 fee, ReturnedAsset[] returnedAssets ); /** * @notice Converts input token balance of address(this) to vault's desired token * @param vault The vault to deposit into * @param tokenIn The input token to convert * @return assetsOut Amount of converted assets * @return returnedAssets Array of any remaining tokens returned to caller */ function swapToAssets( address vault, address tokenIn, uint256 tokenInAmount, address recipient ) external returns (uint256 assetsOut, ReturnedAsset[] memory returnedAssets); /** * @notice Converts vault's desired token balance to output token * @param vault The vault to withdraw from * @param tokenOut The output token to convert * @return tokenOutAmount Amount of converted tokens * @return returnedAssets Array of any remaining tokens returned to caller */ function swapFromAssets( address vault, address tokenOut, uint256 assetsInAmount, address recipient ) external returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets); /// @notice Deposits tokens into a vault after converting them if necessary /// @param vault Target vault /// @param tokenIn Input token address /// @param tokenInAmount Amount of input tokens /// @param minShares Minimum amount of vault shares to receive /// @return shares Number of vault shares received /// @return returnedAssets Array of any remaining tokens returned to caller function zapIn( IVault vault, address tokenIn, uint256 tokenInAmount, uint256 minShares ) external payable returns (uint256 shares, ReturnedAsset[] memory returnedAssets); /// @notice Withdraws from vault and converts to desired token /// @param vault Source vault /// @param withdrawAmount Amount of vault shares to withdraw /// @param tokenOut Desired output token /// @param minTokenOutAmount Minimum amount of desired tokens to receive /// @return tokenOutAmount Amount of output tokens received /// @return returnedAssets Array of any remaining tokens returned to caller function zapOut( IVault vault, uint256 withdrawAmount, address tokenOut, uint256 minTokenOutAmount ) external returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {IWETH} from "../interfaces/exchange/IWETH.sol"; import {ISwapRouter} from "../interfaces/ISwapRouter.sol"; import {ILpRouter} from "../interfaces/ILpRouter.sol"; import {IVault} from "../interfaces/IVault.sol"; import {IZapper} from "../interfaces/IZapper.sol"; import {SphereXProtected} from "@spherex-xyz/contracts/src/SphereXProtected.sol"; import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; /** * @title ZapperBase * @notice Base contract for implementing zapper functionality that allows users to deposit/withdraw * from vaults using any token through automated swaps * @dev This is an abstract contract that should be inherited by specific zapper implementations */ abstract contract ZapperBase is SphereXProtected, ReentrancyGuard, IZapper { using Address for address; using SafeERC20 for IERC20; using SafeERC20 for IVault; /// @notice Minimum token amount required for zap operations to prevent dust transactions uint16 public constant MINIMUM_AMOUNT = 1000; /// @notice Maximum fee that can be set (10% = 1000 basis points) uint16 public constant MAX_FEE = 1000; /// @notice Maximum fee that can be set in basis points (100% = 10000 basis points) uint16 public constant MAX_FEE_BPS = 10000; /// @notice The wrapped version of the native token (e.g., WBERA) IWETH public immutable wrappedNative; /// @notice The fee percentage for zapIn operations in basis points (1/10000) uint16 public zapInFee; /// @notice The fee percentage for zapOut operations in basis points (1/10000) uint16 public zapOutFee; /// @notice The stablecoin token contract used for price calculations and intermediate swaps IERC20 public stablecoin; /// @notice Address of the contract administrator with special privileges address public governance; /// @notice Router contract used for token swaps ISwapRouter public swapRouter; /// @notice Router contract used for add or remove Liquidity ILpRouter public lpRouter; /// @notice Address that receives the fees address public feeRecipient; /** * @notice Constructs the ZapperBase contract * @param devAddress Address of the contract administrator * @param wrappedNativeAddress Address of the wrapped native token (e.g. WBERA) * @param stablecoinAddress Address of the stablecoin token * @param swapRouterAddress Address of the swap router contract * @param lpRouterAddress Address of the lp router contract * @param feeRecipientAddress Address that receives the fees * @param initialZapInFee Initial zapIn fee percentage in basis points * @param initialZapOutFee Initial zapOut fee percentage in basis points */ constructor( address devAddress, address wrappedNativeAddress, address stablecoinAddress, address swapRouterAddress, address lpRouterAddress, address feeRecipientAddress, uint16 initialZapInFee, uint16 initialZapOutFee ) { if ( devAddress == address(0) || wrappedNativeAddress == address(0) || stablecoinAddress == address(0) || swapRouterAddress == address(0) || lpRouterAddress == address(0) || feeRecipientAddress == address(0) ) revert ZeroAddress(); governance = devAddress; wrappedNative = IWETH(wrappedNativeAddress); wrappedNative.deposit{value: 0}(); wrappedNative.withdraw(0); stablecoin = IERC20(stablecoinAddress); swapRouter = ISwapRouter(swapRouterAddress); lpRouter = ILpRouter(lpRouterAddress); if (initialZapInFee > MAX_FEE) revert FeeTooHigh(initialZapInFee, MAX_FEE); if (initialZapOutFee > MAX_FEE) revert FeeTooHigh(initialZapOutFee, MAX_FEE); feeRecipient = feeRecipientAddress; zapInFee = initialZapInFee; zapOutFee = initialZapOutFee; } /// @notice Restricts function access to only the governance address modifier onlyGovernance() { if (msg.sender != governance) revert NotGovernance(); _; } /** * @notice Updates the governance address, only callable by governance * @param governanceAddress New governance address */ function setGovernance(address governanceAddress) external onlyGovernance { _revertAddressZero(governanceAddress); governance = governanceAddress; emit GovernanceChanged(governanceAddress, governance); } /** * @notice Updates the swap router address, only callable by governance * @param routerAddress New swap router address */ function setSwapRouter(address routerAddress) external onlyGovernance sphereXGuardExternal(0xd473ef3c) { _revertAddressZero(routerAddress); address old = address(swapRouter); swapRouter = ISwapRouter(routerAddress); emit SwapRouterChanged(old, routerAddress); } /** * @notice Updates the lp router address, only callable by governance * @param routerAddress New lp router address */ function setLpRouter(address routerAddress) external onlyGovernance sphereXGuardExternal(0x26b2eef4) { _revertAddressZero(routerAddress); address old = address(lpRouter); lpRouter = ILpRouter(routerAddress); emit LpRouterChanged(old, routerAddress); } /** * @notice Updates the stablecoin address, only callable by governance * @param stablecoinAddress New stablecoin address */ function setStableCoin(address stablecoinAddress) external onlyGovernance sphereXGuardExternal(0x5b9fdae4) { _revertAddressZero(stablecoinAddress); stablecoin = IERC20(stablecoinAddress); emit StableCoinChanged(address(stablecoin), stablecoinAddress); } /** * @notice Updates the zapIn fee percentage, only callable by governance * @param newFee New fee percentage in basis points */ function setZapInFee(uint16 newFee) external onlyGovernance { if (newFee > MAX_FEE) revert FeeTooHigh(newFee, MAX_FEE); uint16 oldFee = zapInFee; zapInFee = newFee; emit ZapInFeeChanged(oldFee, newFee); } /** * @notice Updates the zapOut fee percentage, only callable by governance * @param newFee New fee percentage in basis points */ function setZapOutFee(uint16 newFee) external onlyGovernance { if (newFee > MAX_FEE) revert FeeTooHigh(newFee, MAX_FEE); uint16 oldFee = zapOutFee; zapOutFee = newFee; emit ZapOutFeeChanged(oldFee, newFee); } /** * @notice Updates the fee recipient address, only callable by governance * @param newRecipient New address to receive fees */ function setFeeRecipient(address newRecipient) external onlyGovernance { _revertAddressZero(newRecipient); address oldRecipient = feeRecipient; feeRecipient = newRecipient; emit FeeRecipientChanged(oldRecipient, newRecipient); } receive() external payable { assert(msg.sender == address(wrappedNative)); } /** Internal functions */ function _revertAddressZero(address addressToCheck) internal pure { if (addressToCheck == address(0)) revert ZeroAddress(); } /** * @notice Approves spending of a token if not already approved * @param tokenAddress Token to approve * @param spenderAddress Address to approve spending for */ function _approveTokenIfNeeded( address tokenAddress, address spenderAddress ) internal sphereXGuardInternal(0x367a5b5d) { if (IERC20(tokenAddress).allowance(address(this), spenderAddress) == 0) { IERC20(tokenAddress).approve(spenderAddress, type(uint256).max); } } function _safeTransferFromTokens( address token, uint256 amount ) internal sphereXGuardInternal(0x9ffc4661) returns (uint256) { if (IERC20(token).allowance(msg.sender, address(this)) < amount) revert TokenNotApproved(); uint256 balanceBefore = IERC20(token).balanceOf(address(this)); IERC20(token).safeTransferFrom(msg.sender, address(this), amount); uint256 balanceAfter = IERC20(token).balanceOf(address(this)); return balanceAfter - balanceBefore; } /** * @notice Divides an amount between two tokens based on their ratio * @dev Used to split a single token amount into two token amounts while maintaining their ratio * @param amount The total amount to divide * @param ratio0 The ratio for the first token * @param ratio1 The ratio for the second token * @return amount0 The amount allocated to the first token * @return amount1 The amount allocated to the second token */ function _divideAmountInRatio( uint256 amount, uint256 ratio0, uint256 ratio1 ) internal pure returns (uint256, uint256) { uint256 totalRatio = ratio0 + ratio1; if (totalRatio == 0) revert TotalRatioZero(); uint256 amount0 = (amount * ratio0) / totalRatio; uint256 amount1 = amount - amount0; return (amount0, amount1); } /** * @notice Returns any remaining tokens to the caller * @param tokens Array of token addresses to check and return * @return returnedAssets Array of ReturnedAsset structs containing token addresses and amounts returned */ function _returnAssets( address[] memory tokens ) internal sphereXGuardInternal(0x65afacc1) returns (ReturnedAsset[] memory returnedAssets) { uint256 balance; returnedAssets = new ReturnedAsset[](tokens.length); for (uint256 i = 0; i < tokens.length; i++) { if (tokens[i] == address(0)) continue; balance = IERC20(tokens[i]).balanceOf(address(this)); returnedAssets[i] = ReturnedAsset({tokens: tokens[i], amounts: balance}); if (balance > 0) { if (tokens[i] == address(wrappedNative)) { wrappedNative.withdraw(balance); (bool success, ) = msg.sender.call{value: balance}(new bytes(0)); if (!success) revert ETHTransferFailed(); } else { IERC20(tokens[i]).safeTransfer(msg.sender, balance); } } } } /** * @notice Returns any remaining tokens to the caller * @param token The token to return * @param recipient The address to return the token to * @return amount The amount of tokens returned */ function _returnAsset( address token, address recipient ) internal sphereXGuardInternal(0xf45372f8) returns (uint256 amount) { amount = IERC20(token).balanceOf(address(this)); _returnAssetWithAmount(token, recipient, amount); } /** * @notice Returns the amount of tokens to the caller, if the token is wrappedNative, it will be converted to native token * @param token The token to return * @param recipient The address to return the token to * @param amount The amount of tokens to return */ function _returnAssetWithAmount(address token, address recipient, uint256 amount) internal { if (amount > 0) { if (token == address(wrappedNative)) { wrappedNative.withdraw(amount); (bool success, ) = recipient.call{value: amount}(new bytes(0)); if (!success) revert ETHTransferFailed(); } else { IERC20(token).safeTransfer(recipient, amount); } } } /** * @notice Transfers the fee to the fee recipient * @param token The token to transfer * @param fee The fee percentage in basis points * @param amount The amount of tokens to transfer * @return amount The amount of tokens after the fee is transferred */ function _transferFee(address token, uint16 fee, uint256 amount) internal returns (uint256, uint256 feeAmount) { if (fee > 0) { feeAmount = (amount * fee) / MAX_FEE_BPS; _returnAssetWithAmount(token, feeRecipient, feeAmount); amount -= feeAmount; } return (amount, feeAmount); } /** * @notice Converts input token balance of address(this) to vault's desired token * @param asset The asset to convert * @param tokenIn The input token to convert * @return assetsOut Amount of converted assets * @return returnedAssets Array of any remaining tokens returned to caller */ function swapToAssets( address asset, address tokenIn, uint256 tokenInAmount, address recipient ) public virtual returns (uint256 assetsOut, ReturnedAsset[] memory returnedAssets); /** * @notice Converts vault's desired token balance to output token * @param asset The asset to convert * @param tokenOut The output token to convert * @return tokenOutAmount Amount of converted tokens * @return returnedAssets Array of any remaining tokens returned to caller */ function swapFromAssets( address asset, address tokenOut, uint256 assetsInAmount, address recipient ) public virtual returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets); /** * @notice Deposits tokens into a vault after converting them if necessary * @param vault Target vault * @param tokenIn Input token address * @param tokenInAmount Amount of input tokens * @param minShares Minimum amount of vault shares to receive * @return shares Number of vault shares received * @return returnedAssets Array of any remaining tokens returned to caller */ function zapIn( IVault vault, address tokenIn, uint256 tokenInAmount, uint256 minShares ) external payable virtual nonReentrant sphereXGuardExternal(0x621b094a) returns (uint256 shares, ReturnedAsset[] memory returnedAssets) { // if eth is the tokenIn, we need to convert it to the wrappedNative if (tokenIn == address(0)) { if (msg.value < MINIMUM_AMOUNT) revert InsufficientInputAmount(address(0), msg.value, MINIMUM_AMOUNT); wrappedNative.deposit{value: msg.value}(); tokenIn = address(wrappedNative); tokenInAmount = msg.value; } else { if (tokenInAmount < MINIMUM_AMOUNT) revert InsufficientInputAmount(tokenIn, tokenInAmount, MINIMUM_AMOUNT); tokenInAmount = _safeTransferFromTokens(tokenIn, tokenInAmount); } // transfer the fee uint256 feeAmount; (tokenInAmount, feeAmount) = _transferFee(tokenIn, zapInFee, tokenInAmount); // convert the input token to the vault's asset if needed uint256 assetsIn = tokenInAmount; if (vault.asset() != tokenIn) { (assetsIn, returnedAssets) = swapToAssets(vault.asset(), tokenIn, tokenInAmount, address(this)); } // approve the asset to the vault IERC20(vault.asset()).forceApprove(address(vault), assetsIn); // deposit the asset to the vault shares = vault.deposit(assetsIn, msg.sender, minShares); emit ZapIn(msg.sender, address(vault), tokenIn, tokenInAmount, assetsIn, shares, feeAmount, returnedAssets); } /** * @notice Withdraws from vault and converts to desired token * @param vault Source vault * @param sharesAmount Amount of vault shares to withdraw * @param tokenOut Desired output token * @param minTokenOutAmount Minimum amount of desired tokens to receive * @return tokenOutAmount Amount of output tokens received * @return returnedAssets Array of any remaining tokens returned to caller */ function zapOut( IVault vault, uint256 sharesAmount, address tokenOut, uint256 minTokenOutAmount ) external virtual nonReentrant sphereXGuardExternal(0xaf73b205) returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets) { uint256 assetsOut = IVault(vault).redeem(sharesAmount, address(this), msg.sender); // if eth is the desiredToken, we need to convert it to the wrappedNative if (tokenOut == address(0)) { tokenOut = address(wrappedNative); } // convert the asset to the desired token if needed if (vault.asset() == tokenOut) { tokenOutAmount = assetsOut; } else { (tokenOutAmount, returnedAssets) = swapFromAssets(vault.asset(), tokenOut, assetsOut, address(this)); } // transfer the fee uint256 feeAmount; (tokenOutAmount, feeAmount) = _transferFee(tokenOut, zapOutFee, tokenOutAmount); // return the token _returnAsset(tokenOut, msg.sender); if (tokenOutAmount < minTokenOutAmount) revert InsufficientOutputAmount(tokenOut, tokenOutAmount, minTokenOutAmount); emit ZapOut( msg.sender, address(vault), tokenOut, tokenOutAmount, assetsOut, sharesAmount, feeAmount, returnedAssets ); } }
{ "optimizer": { "enabled": true, "runs": 100 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"devAddress","type":"address"},{"internalType":"address","name":"wrappedNative","type":"address"},{"internalType":"address","name":"stablecoin","type":"address"},{"internalType":"address","name":"swapRouter","type":"address"},{"internalType":"address","name":"lpRouter","type":"address"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"uint16","name":"zapInFee","type":"uint16"},{"internalType":"uint16","name":"zapOutFee","type":"uint16"}],"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":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"uint16","name":"fee","type":"uint16"},{"internalType":"uint16","name":"maxFee","type":"uint16"}],"name":"FeeTooHigh","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"provided","type":"uint256"},{"internalType":"uint256","name":"minimum","type":"uint256"}],"name":"InsufficientInputAmount","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"received","type":"uint256"},{"internalType":"uint256","name":"minimum","type":"uint256"}],"name":"InsufficientOutputAmount","type":"error"},{"inputs":[],"name":"NotGovernance","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TokenNotApproved","type":"error"},{"inputs":[],"name":"TotalRatioZero","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"bool","name":"isSingleToken","type":"bool"},{"indexed":false,"internalType":"enum IDexType.DexType","name":"dex","type":"uint8"}],"name":"AssetInfoSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldEngineAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newEngineAddress","type":"address"}],"name":"ChangedSpherexEngineAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldSphereXAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newSphereXAdmin","type":"address"}],"name":"ChangedSpherexOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"newRecipient","type":"address"}],"name":"FeeRecipientChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"oldGovernance","type":"address"}],"name":"GovernanceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newLpRouter","type":"address"},{"indexed":true,"internalType":"address","name":"oldLpRouter","type":"address"}],"name":"LpRouterChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"NewAllowedSenderOnchain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"SpherexAdminTransferCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"currentAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"pendingAdmin","type":"address"}],"name":"SpherexAdminTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newStableCoin","type":"address"},{"indexed":true,"internalType":"address","name":"oldStableCoin","type":"address"}],"name":"StableCoinChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newSwapRouter","type":"address"},{"indexed":true,"internalType":"address","name":"oldSwapRouter","type":"address"}],"name":"SwapRouterChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenInAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetsIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"components":[{"internalType":"address","name":"tokens","type":"address"},{"internalType":"uint256","name":"amounts","type":"uint256"}],"indexed":false,"internalType":"struct IZapper.ReturnedAsset[]","name":"returnedAssets","type":"tuple[]"}],"name":"ZapIn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"oldFee","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"newFee","type":"uint16"}],"name":"ZapInFeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenOutAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetsOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"components":[{"internalType":"address","name":"tokens","type":"address"},{"internalType":"uint256","name":"amounts","type":"uint256"}],"indexed":false,"internalType":"struct IZapper.ReturnedAsset[]","name":"returnedAssets","type":"tuple[]"}],"name":"ZapOut","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"oldFee","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"newFee","type":"uint16"}],"name":"ZapOutFeeChanged","type":"event"},{"inputs":[],"name":"MAX_FEE","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE_BPS","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_AMOUNT","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptSphereXAdminRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assetDex","outputs":[{"internalType":"enum IDexType.DexType","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newSphereXEngine","type":"address"}],"name":"changeSphereXEngine","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSphereXOperator","type":"address"}],"name":"changeSphereXOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isAssetSingleToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpRouter","outputs":[{"internalType":"contract ILpRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingSphereXAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"bool","name":"isSingleToken","type":"bool"},{"internalType":"enum IDexType.DexType","name":"dex","type":"uint8"}],"name":"setAssetInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"governanceAddress","type":"address"}],"name":"setGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"routerAddress","type":"address"}],"name":"setLpRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stablecoinAddress","type":"address"}],"name":"setStableCoin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"routerAddress","type":"address"}],"name":"setSwapRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newFee","type":"uint16"}],"name":"setZapInFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newFee","type":"uint16"}],"name":"setZapOutFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sphereXAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sphereXEngine","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sphereXOperator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stablecoin","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"assetsInAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"swapFromAssets","outputs":[{"internalType":"uint256","name":"tokenOutAmount","type":"uint256"},{"components":[{"internalType":"address","name":"tokens","type":"address"},{"internalType":"uint256","name":"amounts","type":"uint256"}],"internalType":"struct IZapper.ReturnedAsset[]","name":"returnedAssets","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"contract ISwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"tokenInAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"swapToAssets","outputs":[{"internalType":"uint256","name":"tokenOutAmount","type":"uint256"},{"components":[{"internalType":"address","name":"tokens","type":"address"},{"internalType":"uint256","name":"amounts","type":"uint256"}],"internalType":"struct IZapper.ReturnedAsset[]","name":"returnedAssets","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"transferSphereXAdminRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrappedNative","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IVault","name":"vault","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"tokenInAmount","type":"uint256"},{"internalType":"uint256","name":"minShares","type":"uint256"}],"name":"zapIn","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"components":[{"internalType":"address","name":"tokens","type":"address"},{"internalType":"uint256","name":"amounts","type":"uint256"}],"internalType":"struct IZapper.ReturnedAsset[]","name":"returnedAssets","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"zapInFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IVault","name":"vault","type":"address"},{"internalType":"uint256","name":"sharesAmount","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"minTokenOutAmount","type":"uint256"}],"name":"zapOut","outputs":[{"internalType":"uint256","name":"tokenOutAmount","type":"uint256"},{"components":[{"internalType":"address","name":"tokens","type":"address"},{"internalType":"uint256","name":"amounts","type":"uint256"}],"internalType":"struct IZapper.ReturnedAsset[]","name":"returnedAssets","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"zapOutFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a06040523480156200001157600080fd5b50604051620037e8380380620037e8833981016040819052620000349162000566565b87878787878787873360008082818062000050838280620002de565b50506001600055505050506001600160a01b03881615806200007957506001600160a01b038716155b806200008c57506001600160a01b038616155b806200009f57506001600160a01b038516155b80620000b257506001600160a01b038416155b80620000c557506001600160a01b038316155b15620000e45760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b038a8116919091179091558716608081905260408051630d0e30db60e41b8152905163d0e30db0916000916004808301928492919082900301818388803b1580156200014457600080fd5b505af115801562000159573d6000803e3d6000fd5b5050608051604051632e1a7d4d60e01b8152600060048201526001600160a01b039091169350632e1a7d4d92506024019050600060405180830381600087803b158015620001a657600080fd5b505af1158015620001bb573d6000803e3d6000fd5b5050600180546001600160a01b03808b1664010000000002600160201b600160c01b031990921691909117909155600380548983166001600160a01b031991821617909155600480549289169290911691909117905550506103e861ffff831611156200024e57604051633c057d7b60e01b815261ffff831660048201526103e860248201526044015b60405180910390fd5b6103e861ffff821611156200028557604051633c057d7b60e01b815261ffff821660048201526103e8602482015260440162000245565b600580546001600160a01b039094166001600160a01b0319909416939093179092556001805461ffff938416620100000263ffffffff19909116939092169290921717905550620006619b505050505050505050505050565b620003146200030f60017fca334bf49ef20e9cbff039feda3bc1c2a853aff17b1b5187e4aa1380ec55829d6200060e565b849055565b60408051600081526001600160a01b03851660208201527f67ebaebcd2ca5a91a404e898110f221747e8d15567f2388a34794aab151cf3e6910160405180910390a16200038c6200038760017fadf90d75f0f2d657d5a22fa0f6e4dabb83c4598b77158eb4119cb38f1d8644636200060e565b839055565b60408051600081526001600160a01b03841660208201527f2ac55ae7ba47db34b5334622acafeb34a65daf143b47019273185d64c73a35a5910160405180910390a1620003d98162000456565b6200040f6200040a60017f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d66200060e565b829055565b60408051600081526001600160a01b03831660208201527ff33499cccaa0611882086224cc48cd82ef54b66a4d2edf4ed67108dd516896d5910160405180910390a1505050565b6001600160a01b0381161580620004da57506040516301ffc9a760e01b81526329f20dd560e11b60048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa158015620004b4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004da919062000636565b620005335760405162461bcd60e51b815260206004820152602260248201527f53706865726558206572726f723a206e6f7420612053706865726558456e67696044820152616e6560f01b606482015260840162000245565b50565b80516001600160a01b03811681146200054e57600080fd5b919050565b805161ffff811681146200054e57600080fd5b600080600080600080600080610100898b0312156200058457600080fd5b6200058f8962000536565b97506200059f60208a0162000536565b9650620005af60408a0162000536565b9550620005bf60608a0162000536565b9450620005cf60808a0162000536565b9350620005df60a08a0162000536565b9250620005ef60c08a0162000553565b9150620005ff60e08a0162000553565b90509295985092959890939650565b818103818111156200063057634e487b7160e01b600052601160045260246000fd5b92915050565b6000602082840312156200064957600080fd5b815180151581146200065a57600080fd5b9392505050565b608051613133620006b5600039600081816101c2015281816105a8015281816109c501528181610a390152818161120401528181611ef401528181611f5a015281816126a601526126f301526131336000f3fe6080604052600436106101b25760003560e01c80639aa9019e116100ed578063cda5873e11610090578063cda5873e146104e3578063d55be8c614610503578063daba7ef714610519578063e74b981b14610539578063e7e5db4f14610559578063e9cbd8221461056e578063eb6d3a1114610596578063f99e6387146105ca578063fecc657c146105ea57600080fd5b80639aa9019e146103f6578063a863ff2f1461040b578063a89635bc1461042b578063ab033ea914610446578063afb44e3714610466578063bc063e1a1461026c578063c31c9c0714610486578063c64e74e2146104a657600080fd5b80634690484011610155578063469048401461030b5780634c6c848f1461032b5780634ee8f8581461034b5780635aa6e6751461036b5780638426b9681461038b5780638f0af424146103a05780639739c03e146103c057806399e80f3b146103e157600080fd5b80630c8106dc146101f657806315a292031461022c57806323af4e171461024c578063257d9bb81461026c5780633218e83a146102955780633c231166146102c35780633c3b1ef6146102d857806341273657146102eb57600080fd5b366101f157336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101ef576101ef6129ce565b005b600080fd5b34801561020257600080fd5b50600454610216906001600160a01b031681565b60405161022391906129e4565b60405180910390f35b34801561023857600080fd5b506101ef610247366004612a0d565b61062a565b34801561025857600080fd5b506101ef610267366004612a0d565b6106da565b34801561027857600080fd5b506102826103e881565b60405161ffff9091168152602001610223565b3480156102a157600080fd5b506102b56102b0366004612a2a565b61078d565b604051610223929190612acc565b3480156102cf57600080fd5b50610216610939565b6102b56102e6366004612aed565b610960565b3480156102f757600080fd5b506101ef610306366004612a0d565b610d13565b34801561031757600080fd5b50600554610216906001600160a01b031681565b34801561033757600080fd5b506101ef610346366004612a0d565b610db6565b34801561035757600080fd5b506101ef610366366004612a0d565b610eb9565b34801561037757600080fd5b50600254610216906001600160a01b031681565b34801561039757600080fd5b506101ef610f72565b3480156103ac57600080fd5b506101ef6103bb366004612b33565b61106b565b3480156103cc57600080fd5b506001546102829062010000900461ffff1681565b3480156103ed57600080fd5b5061021661111b565b34801561040257600080fd5b50610216611139565b34801561041757600080fd5b506102b5610426366004612b57565b611157565b34801561043757600080fd5b506001546102829061ffff1681565b34801561045257600080fd5b506101ef610461366004612a0d565b6113cf565b34801561047257600080fd5b506101ef610481366004612b33565b61144f565b34801561049257600080fd5b50600354610216906001600160a01b031681565b3480156104b257600080fd5b506104d66104c1366004612a0d565b60076020526000908152604090205460ff1681565b6040516102239190612bd7565b3480156104ef57600080fd5b506101ef6104fe366004612bf3565b61150b565b34801561050f57600080fd5b5061028261271081565b34801561052557600080fd5b506101ef610534366004612a0d565b6115cf565b34801561054557600080fd5b506101ef610554366004612a0d565b611674565b34801561056557600080fd5b506102166116fa565b34801561057a57600080fd5b506001546102169064010000000090046001600160a01b031681565b3480156105a257600080fd5b506102167f000000000000000000000000000000000000000000000000000000000000000081565b3480156105d657600080fd5b506102b56105e5366004612a2a565b611718565b3480156105f657600080fd5b5061061a610605366004612a0d565b60066020526000908152604090205460ff1681565b6040519015158152602001610223565b6002546001600160a01b0316331461065557604051632d5be4cb60e21b815260040160405180910390fd5b6326b2eef4600061066782600161186d565b9050610672836119e9565b600480546001600160a01b038581166001600160a01b0319831681179093556040519116919082907f82c52d8aa62200dfc997bdf1100b1c2ed614580941b2b8637d10b8ca0428eeec90600090a3506106d56106cd83612c58565b600183611a13565b505050565b6002546001600160a01b0316331461070557604051632d5be4cb60e21b815260040160405180910390fd5b635b9fdae4600061071782600161186d565b9050610722836119e9565b60018054640100000000600160c01b0319166401000000006001600160a01b03868116828102939093179384905560405192939190910416907f497b8419a37c8014b1a755ec707f25d11ae4bade591d379f9a4095f37edaf76e90600090a36106d56106cd83612c58565b600060606307c1e85d63190c741d60e11b836107b68382356001600160e01b031916841461186d565b90506001600160a01b03861630146107d5576107d28888611b35565b96505b6001600160a01b03891660009081526006602052604090205460609060ff16156108f657600354610813906001600160a01b038b811691168a611cfe565b6003546040516305c13d4360e11b81526001600160a01b0390911690630b827a869061084c908c908e908d906000908e90600401612c74565b6020604051808303816000875af115801561086b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088f9190612ca4565b6040805160018082528183019092529197506020808301908036833701905050905088816000815181106108c5576108c5612cd3565b60200260200101906001600160a01b031690816001600160a01b0316815250506108ee81611d56565b945050610908565b6109028a8a8a8a6120a7565b95509550505b61092d61091484612c58565b6000356001600160e01b03199081169085161483611a13565b50505094509492505050565b600061095b61095760016000805160206130de833981519152612ce9565b5490565b905090565b6000606061096c6121c8565b63621b094a600061097e82600161186d565b90506001600160a01b038716610a62576103e83410156109c3576000346103e8604051630b722aef60e21b81526004016109ba93929190612cfc565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610a1e57600080fd5b505af1158015610a32573d6000803e3d6000fd5b50505050507f00000000000000000000000000000000000000000000000000000000000000009650349550610a9a565b6103e8861015610a8d5786866103e8604051630b722aef60e21b81526004016109ba93929190612cfc565b610a978787611b35565b95505b600154600090610ab090899061ffff16896121f2565b80925081985050506000879050886001600160a01b03168a6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b299190612d21565b6001600160a01b031614610ba957610ba48a6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9c9190612d21565b8a8a3061078d565b955090505b610c208a828c6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c109190612d21565b6001600160a01b0316919061224d565b60405163bc157ac160e01b815260048101829052336024820152604481018890526001600160a01b038b169063bc157ac1906064016020604051808303816000875af1158015610c74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c989190612ca4565b9550896001600160a01b0316336001600160a01b03167f87640c2e40d67703e350e7d24d4e416e5c4f1e1550e1285b1bf667440d36bdcf8b8b858b888c604051610ce796959493929190612d3e565b60405180910390a35050610cfe826106cd90612c58565b5050610d0a6001600055565b94509492505050565b6002546001600160a01b03163314610d3e57604051632d5be4cb60e21b815260040160405180910390fd5b63d473ef3c6000610d5082600161186d565b9050610d5b836119e9565b600380546001600160a01b038581166001600160a01b0319831681179093556040519116919082907f5c5b0bb5085481c320dc523e3b3f829eaa807936f615add0077fa213f345090e90600090a3506106d56106cd83612c58565b610dd2610957600160008051602061307e833981519152612ce9565b6001600160a01b0316336001600160a01b031614610e325760405162461bcd60e51b815260206004820181905260248201527f53706865726558206572726f723a206f70657261746f7220726571756972656460448201526064016109ba565b610e3b816122e5565b6000610e5961095760016000805160206130de833981519152612ce9565b9050610e7c610e7760016000805160206130de833981519152612ce9565b839055565b7ff33499cccaa0611882086224cc48cd82ef54b66a4d2edf4ed67108dd516896d58183604051610ead929190612d83565b60405180910390a15050565b610ed561095760016000805160206130be833981519152612ce9565b6001600160a01b0316336001600160a01b031614610f055760405162461bcd60e51b81526004016109ba90612d9d565b6000610f23610957600160008051602061307e833981519152612ce9565b9050610f41610e77600160008051602061307e833981519152612ce9565b7f2ac55ae7ba47db34b5334622acafeb34a65daf143b47019273185d64c73a35a58183604051610ead929190612d83565b33610f7b611139565b6001600160a01b031614610fe05760405162461bcd60e51b815260206004820152602660248201527f53706865726558206572726f723a206e6f74207468652070656e64696e67206160448201526518d8dbdd5b9d60d21b60648201526084016109ba565b6000610fea61111b565b905061100d61100860016000805160206130be833981519152612ce9565b339055565b61102f611029600160008051602061309e833981519152612ce9565b60009055565b7f67ebaebcd2ca5a91a404e898110f221747e8d15567f2388a34794aab151cf3e68133604051611060929190612d83565b60405180910390a150565b6002546001600160a01b0316331461109657604051632d5be4cb60e21b815260040160405180910390fd5b6103e861ffff821611156110cb57604051633c057d7b60e01b815261ffff821660048201526103e860248201526044016109ba565b6001805461ffff83811661ffff1983168117909355604080519190921680825260208201939093527fcd5c26e400cb366bdac1d1cbdec4b428f15bc14a133ecbda85bc6f11f7acb9f19101610ead565b600061095b61095760016000805160206130be833981519152612ce9565b600061095b610957600160008051602061309e833981519152612ce9565b600060606111636121c8565b63af73b205600061117582600161186d565b604051635d043b2960e11b8152600481018990523060248201523360448201529091506000906001600160a01b038a169063ba087652906064016020604051808303816000875af11580156111ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f29190612ca4565b90506001600160a01b038716611226577f000000000000000000000000000000000000000000000000000000000000000096505b866001600160a01b0316896001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561126e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112929190612d21565b6001600160a01b0316036112a85780945061131b565b611315896001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130d9190612d21565b888330611718565b90955093505b600061133888600160029054906101000a900461ffff16886121f2565b909650905061134788336123bc565b508686101561138257604051632752fb4960e11b81526001600160a01b038916600482015260248101879052604481018890526064016109ba565b896001600160a01b0316336001600160a01b03167f0bc6c5ccdba0b566b3adbb7c24c419a1b872218cd487d145a4e4eb70b2c8bfb38a89868e878c604051610ce796959493929190612d3e565b6002546001600160a01b031633146113fa57604051632d5be4cb60e21b815260040160405180910390fd5b611403816119e9565b600280546001600160a01b0319166001600160a01b03831690811790915560405181907f3aaaebeb4821d6a7e5c77ece53cff0afcc56c82add2c978dbbb7f73e84cbcfd290600090a350565b6002546001600160a01b0316331461147a57604051632d5be4cb60e21b815260040160405180910390fd5b6103e861ffff821611156114af57604051633c057d7b60e01b815261ffff821660048201526103e860248201526044016109ba565b6001805461ffff8381166201000081810263ffff00001985161790945560408051949093049091168084526020840191909152917febcac71ae552a15ae4d23c933603e1a71f47ff8371bdd98194f037156b73a7199101610ead565b6002546001600160a01b0316331461153657604051632d5be4cb60e21b815260040160405180910390fd5b61153f836119e9565b6001600160a01b0383166000908152600660209081526040808320805486151560ff199182161790915560079092529091208054839216600183600981111561158a5761158a612b9f565b02179055507f3b79c840859aa9e93d93ccb4f7a8b6c425621929bcc61a03194f607a53d0f4ab8383836040516115c293929190612dd4565b60405180910390a1505050565b6115eb61095760016000805160206130be833981519152612ce9565b6001600160a01b0316336001600160a01b03161461161b5760405162461bcd60e51b81526004016109ba90612d9d565b61163c611637600160008051602061309e833981519152612ce9565b829055565b7f5778f1547abbbb86090a43c32aec38334b31df4beeb6f8f3fa063f593b53a52661166561111b565b82604051611060929190612d83565b6002546001600160a01b0316331461169f57604051632d5be4cb60e21b815260040160405180910390fd5b6116a8816119e9565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f0bc21fe5c3ab742ff1d15b5c4477ffbacf1167e618228078fa625edebe7f331d90600090a35050565b600061095b610957600160008051602061307e833981519152612ce9565b6000606063362279f763f99e638760e01b836117418382356001600160e01b031916841461186d565b90506001600160a01b03861630146117605761175d8988611b35565b96505b6001600160a01b03891660009081526006602052604090205460ff16156118515760035461179b906001600160a01b038b8116911689611cfe565b6003546040516305c13d4360e11b81526001600160a01b0390911690630b827a86906117d4908c908c908c906000908d90600401612c74565b6020604051808303816000875af11580156117f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118179190612ca4565b604080516001808252818301909252919650600091906020808301908036833701905050905089816000815181106108c5576108c5612cd3565b61185d8989898961244d565b9450945061092d61091484612c58565b6118a1604051806080016040528060608152602001606081526020016000815260200160006001600160a01b031681525090565b60006118ab610939565b6001600160a01b0316146119e35760006118c3610939565b9050821561194c57604051634492e52d60e11b81526001600160a01b03821690638925ca5a906118fe90879033906000903690600401612df9565b6000604051808303816000875af115801561191d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119459190810190612e40565b82526119be565b604051633e88494360e01b8152600481018590526001600160a01b03821690633e884943906024016000604051808303816000875af1158015611993573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119bb9190810190612e40565b82525b81516119c990612554565b60208301525a60408301526001600160a01b031660608201525b92915050565b6001600160a01b038116611a105760405163d92e233d60e01b815260040160405180910390fd5b50565b60608101516001600160a01b038116611a2c5750505050565b60005a8360400151611a3e9190612ce9565b90506060611a4f8460000151612554565b90508415611ac4576020840151604051631e17b28d60e31b81526001600160a01b0385169163f0bd946891611a8d918a918791908790600401612f22565b600060405180830381600087803b158015611aa757600080fd5b505af1158015611abb573d6000803e3d6000fd5b50505050611b2d565b602084015160405163027313cd60e11b81526001600160a01b038516916304e6279a91611afa918a918791908790600401612f22565b600060405180830381600087803b158015611b1457600080fd5b505af1158015611b28573d6000803e3d6000fd5b505050505b505050505050565b6000639ffc46616000611b4982600061186d565b905083856001600160a01b031663dd62ed3e33306040518363ffffffff1660e01b8152600401611b7a929190612d83565b602060405180830381865afa158015611b97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bbb9190612ca4565b1015611bda576040516332da96a360e01b815260040160405180910390fd5b6040516370a0823160e01b81526000906001600160a01b038716906370a0823190611c099030906004016129e4565b602060405180830381865afa158015611c26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4a9190612ca4565b9050611c616001600160a01b03871633308861260b565b6040516370a0823160e01b81526000906001600160a01b038816906370a0823190611c909030906004016129e4565b602060405180830381865afa158015611cad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cd19190612ca4565b9050611cdd8282612ce9565b945050505b611cf6611cee83612c58565b600083611a13565b505092915050565b6106d583846001600160a01b031663a9059cbb8585604051602401611d24929190612f5e565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050612644565b60606365afacc16000611d6a82600061186d565b90506000845167ffffffffffffffff811115611d8857611d88612cbd565b604051908082528060200260200182016040528015611dcd57816020015b6040805180820190915260008082526020820152815260200190600190039081611da65790505b50935060005b85518110156120915760006001600160a01b0316868281518110611df957611df9612cd3565b60200260200101516001600160a01b0316031561207f57858181518110611e2257611e22612cd3565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611e5591906129e4565b602060405180830381865afa158015611e72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e969190612ca4565b91506040518060400160405280878381518110611eb557611eb5612cd3565b60200260200101516001600160a01b0316815260200183815250858281518110611ee157611ee1612cd3565b6020908102919091010152811561207f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316868281518110611f2e57611f2e612cd3565b60200260200101516001600160a01b03160361204857604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611fa657600080fd5b505af1158015611fba573d6000803e3d6000fd5b5050604080516000808252602082019283905293503392508591611fde9190612f77565b60006040518083038185875af1925050503d806000811461201b576040519150601f19603f3d011682016040523d82523d6000602084013e612020565b606091505b50509050806120425760405163b12d13eb60e01b815260040160405180910390fd5b5061207f565b61207f338388848151811061205f5761205f612cd3565b60200260200101516001600160a01b0316611cfe9092919063ffffffff16565b8061208981612fa6565b915050611dd3565b50506120a082611cee90612c58565b5050919050565b6004546000906060906120c7906001600160a01b03878116911686611cfe565b600480546001600160a01b038881166000908152600760205260409081902054905163190a4d4960e01b8152919092169263190a4d4992612116928b928b928b928b9260ff9092169101612fbf565b6020604051808303816000875af1158015612135573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121599190612ca4565b6040805160018082528183019092529193506000919060208083019080368337019050509050858160008151811061219357612193612cd3565b60200260200101906001600160a01b031690816001600160a01b0316815250506121bc81611d56565b91505094509492505050565b6002600054036121eb57604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b60008061ffff8416156122425761271061221061ffff861685612ff3565b61221a919061300a565b6005549091506122359086906001600160a01b03168361269e565b61223f8184612ce9565b92505b829150935093915050565b6000836001600160a01b031663095ea7b38484604051602401612271929190612f5e565b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505090506122aa84826127f8565b6122df576122d584856001600160a01b031663095ea7b3866000604051602401611d24929190612f5e565b6122df8482612644565b50505050565b6001600160a01b038116158061236557506040516301ffc9a760e01b81526329f20dd560e11b60048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa158015612341573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612365919061302c565b611a105760405162461bcd60e51b815260206004820152602260248201527f53706865726558206572726f723a206e6f7420612053706865726558456e67696044820152616e6560f01b60648201526084016109ba565b600063f45372f860006123d082600061186d565b6040516370a0823160e01b81529091506001600160a01b038616906370a08231906123ff9030906004016129e4565b602060405180830381865afa15801561241c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124409190612ca4565b9250611ce285858561269e565b60045460009060609061246d906001600160a01b03888116911686611cfe565b600480546001600160a01b038881166000908152600760205260409081902054905163616a3dbd60e11b8152919092169263c2d47b7a926124bc928b928a928a928d9260ff9092169101613049565b6020604051808303816000875af11580156124db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124ff9190612ca4565b91506001600160a01b038316301461251d5761251b85846123bc565b505b6040805160018082528183019092526000916020808301908036833701905050905060008160008151811061219357612193612cd3565b805160609060008167ffffffffffffffff81111561257457612574612cbd565b60405190808252806020026020018201604052801561259d578160200160208202803683370190505b50905060005b828110156126035760008582815181106125bf576125bf612cd3565b60200260200101519050600081549050808484815181106125e2576125e2612cd3565b602002602001018181525050505080806125fb90612fa6565b9150506125a3565b509392505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526122df9186918216906323b872dd90608401611d24565b60006126596001600160a01b038416836128a0565b9050805160001415801561267e57508080602001905181019061267c919061302c565b155b156106d55782604051635274afe760e01b81526004016109ba91906129e4565b80156106d5577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316036127e457604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561273f57600080fd5b505af1158015612753573d6000803e3d6000fd5b5050604080516000808252602082019283905293506001600160a01b038616925084916127809190612f77565b60006040518083038185875af1925050503d80600081146127bd576040519150601f19603f3d011682016040523d82523d6000602084013e6127c2565b606091505b50509050806122df5760405163b12d13eb60e01b815260040160405180910390fd5b6106d56001600160a01b0384168383611cfe565b6000806000846001600160a01b0316846040516128159190612f77565b6000604051808303816000865af19150503d8060008114612852576040519150601f19603f3d011682016040523d82523d6000602084013e612857565b606091505b5091509150818015612881575080511580612881575080806020019051810190612881919061302c565b801561289757506000856001600160a01b03163b115b95945050505050565b60606128ae838360006128b5565b9392505050565b6060814710156128da573060405163cd78605960e01b81526004016109ba91906129e4565b600080856001600160a01b031684866040516128f69190612f77565b60006040518083038185875af1925050503d8060008114612933576040519150601f19603f3d011682016040523d82523d6000602084013e612938565b606091505b5091509150612948868383612952565b9695505050505050565b60608261296757612962826129a5565b6128ae565b815115801561297e57506001600160a01b0384163b155b1561299e5783604051639996b31560e01b81526004016109ba91906129e4565b50806128ae565b8051156129b55780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b600052600160045260246000fd5b6001600160a01b0391909116815260200190565b6001600160a01b0381168114611a1057600080fd5b600060208284031215612a1f57600080fd5b81356128ae816129f8565b60008060008060808587031215612a4057600080fd5b8435612a4b816129f8565b93506020850135612a5b816129f8565b9250604085013591506060850135612a72816129f8565b939692955090935050565b600081518084526020808501945080840160005b83811015612ac157815180516001600160a01b031688528301518388015260409096019590820190600101612a91565b509495945050505050565b828152604060208201526000612ae56040830184612a7d565b949350505050565b60008060008060808587031215612b0357600080fd5b8435612b0e816129f8565b93506020850135612b1e816129f8565b93969395505050506040820135916060013590565b600060208284031215612b4557600080fd5b813561ffff811681146128ae57600080fd5b60008060008060808587031215612b6d57600080fd5b8435612b78816129f8565b9350602085013592506040850135612b8f816129f8565b9396929550929360600135925050565b634e487b7160e01b600052602160045260246000fd5b600a8110612bd357634e487b7160e01b600052602160045260246000fd5b9052565b602081016119e38284612bb5565b8015158114611a1057600080fd5b600080600060608486031215612c0857600080fd5b8335612c13816129f8565b92506020840135612c2381612be5565b91506040840135600a8110612c3757600080fd5b809150509250925092565b634e487b7160e01b600052601160045260246000fd5b6000600160ff1b8201612c6d57612c6d612c42565b5060000390565b6001600160a01b039586168152938516602085015260408401929092526060830152909116608082015260a00190565b600060208284031215612cb657600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b818103818111156119e3576119e3612c42565b6001600160a01b03939093168352602083019190915261ffff16604082015260600190565b600060208284031215612d3357600080fd5b81516128ae816129f8565b60018060a01b038716815285602082015284604082015283606082015282608082015260c060a08201526000612d7760c0830184612a7d565b98975050505050505050565b6001600160a01b0392831681529116602082015260400190565b6020808252601d908201527f53706865726558206572726f723a2061646d696e207265717569726564000000604082015260600190565b6001600160a01b0384168152821515602082015260608101612ae56040830184612bb5565b8481526001600160a01b03841660208201526060604082018190528101829052818360808301376000818301608090810191909152601f909201601f191601019392505050565b60006020808385031215612e5357600080fd5b825167ffffffffffffffff80821115612e6b57600080fd5b818501915085601f830112612e7f57600080fd5b815181811115612e9157612e91612cbd565b8060051b604051601f19603f83011681018181108582111715612eb657612eb6612cbd565b604052918252848201925083810185019188831115612ed457600080fd5b938501935b82851015612d7757845184529385019392850192612ed9565b600081518084526020808501945080840160005b83811015612ac157815187529582019590820190600101612f06565b848152836020820152608060408201526000612f416080830185612ef2565b8281036060840152612f538185612ef2565b979650505050505050565b6001600160a01b03929092168252602082015260400190565b6000825160005b81811015612f985760208186018101518583015201612f7e565b506000920191825250919050565b600060018201612fb857612fb8612c42565b5060010190565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a081016129486080830184612bb5565b80820281158282048414176119e3576119e3612c42565b60008261302757634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561303e57600080fd5b81516128ae81612be5565b6001600160a01b0386811682526020820186905284811660408301528316606082015260a081016129486080830184612bb556feadf90d75f0f2d657d5a22fa0f6e4dabb83c4598b77158eb4119cb38f1d8644633a517dd736309b905c692160a21b5439bdc56db1dc77d6982b66d44814e3fa97ca334bf49ef20e9cbff039feda3bc1c2a853aff17b1b5187e4aa1380ec55829d1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d6a2646970667358221220e0aee4aeb6db0c3f61c43ffb68da9dd25134753dde08db7a00f10990d2d97ec164736f6c6343000814003300000000000000000000000062137cec7754aa3f530c98866a86dba36d2687170000000000000000000000006969696969696969696969696969696969696969000000000000000000000000fcbd14dc51f0a4d49d5e53c2e0950e0bc26d0dce000000000000000000000000252e9b9dd86aad41166e682712b75a45bb779433000000000000000000000000944e034b1e3ff30becb3661b4960f47ddf14af3d0000000000000000000000001cfe31bfa1ac9b28588c91bb4300a1ed032f069f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106101b25760003560e01c80639aa9019e116100ed578063cda5873e11610090578063cda5873e146104e3578063d55be8c614610503578063daba7ef714610519578063e74b981b14610539578063e7e5db4f14610559578063e9cbd8221461056e578063eb6d3a1114610596578063f99e6387146105ca578063fecc657c146105ea57600080fd5b80639aa9019e146103f6578063a863ff2f1461040b578063a89635bc1461042b578063ab033ea914610446578063afb44e3714610466578063bc063e1a1461026c578063c31c9c0714610486578063c64e74e2146104a657600080fd5b80634690484011610155578063469048401461030b5780634c6c848f1461032b5780634ee8f8581461034b5780635aa6e6751461036b5780638426b9681461038b5780638f0af424146103a05780639739c03e146103c057806399e80f3b146103e157600080fd5b80630c8106dc146101f657806315a292031461022c57806323af4e171461024c578063257d9bb81461026c5780633218e83a146102955780633c231166146102c35780633c3b1ef6146102d857806341273657146102eb57600080fd5b366101f157336001600160a01b037f000000000000000000000000696969696969696969696969696969696969696916146101ef576101ef6129ce565b005b600080fd5b34801561020257600080fd5b50600454610216906001600160a01b031681565b60405161022391906129e4565b60405180910390f35b34801561023857600080fd5b506101ef610247366004612a0d565b61062a565b34801561025857600080fd5b506101ef610267366004612a0d565b6106da565b34801561027857600080fd5b506102826103e881565b60405161ffff9091168152602001610223565b3480156102a157600080fd5b506102b56102b0366004612a2a565b61078d565b604051610223929190612acc565b3480156102cf57600080fd5b50610216610939565b6102b56102e6366004612aed565b610960565b3480156102f757600080fd5b506101ef610306366004612a0d565b610d13565b34801561031757600080fd5b50600554610216906001600160a01b031681565b34801561033757600080fd5b506101ef610346366004612a0d565b610db6565b34801561035757600080fd5b506101ef610366366004612a0d565b610eb9565b34801561037757600080fd5b50600254610216906001600160a01b031681565b34801561039757600080fd5b506101ef610f72565b3480156103ac57600080fd5b506101ef6103bb366004612b33565b61106b565b3480156103cc57600080fd5b506001546102829062010000900461ffff1681565b3480156103ed57600080fd5b5061021661111b565b34801561040257600080fd5b50610216611139565b34801561041757600080fd5b506102b5610426366004612b57565b611157565b34801561043757600080fd5b506001546102829061ffff1681565b34801561045257600080fd5b506101ef610461366004612a0d565b6113cf565b34801561047257600080fd5b506101ef610481366004612b33565b61144f565b34801561049257600080fd5b50600354610216906001600160a01b031681565b3480156104b257600080fd5b506104d66104c1366004612a0d565b60076020526000908152604090205460ff1681565b6040516102239190612bd7565b3480156104ef57600080fd5b506101ef6104fe366004612bf3565b61150b565b34801561050f57600080fd5b5061028261271081565b34801561052557600080fd5b506101ef610534366004612a0d565b6115cf565b34801561054557600080fd5b506101ef610554366004612a0d565b611674565b34801561056557600080fd5b506102166116fa565b34801561057a57600080fd5b506001546102169064010000000090046001600160a01b031681565b3480156105a257600080fd5b506102167f000000000000000000000000696969696969696969696969696969696969696981565b3480156105d657600080fd5b506102b56105e5366004612a2a565b611718565b3480156105f657600080fd5b5061061a610605366004612a0d565b60066020526000908152604090205460ff1681565b6040519015158152602001610223565b6002546001600160a01b0316331461065557604051632d5be4cb60e21b815260040160405180910390fd5b6326b2eef4600061066782600161186d565b9050610672836119e9565b600480546001600160a01b038581166001600160a01b0319831681179093556040519116919082907f82c52d8aa62200dfc997bdf1100b1c2ed614580941b2b8637d10b8ca0428eeec90600090a3506106d56106cd83612c58565b600183611a13565b505050565b6002546001600160a01b0316331461070557604051632d5be4cb60e21b815260040160405180910390fd5b635b9fdae4600061071782600161186d565b9050610722836119e9565b60018054640100000000600160c01b0319166401000000006001600160a01b03868116828102939093179384905560405192939190910416907f497b8419a37c8014b1a755ec707f25d11ae4bade591d379f9a4095f37edaf76e90600090a36106d56106cd83612c58565b600060606307c1e85d63190c741d60e11b836107b68382356001600160e01b031916841461186d565b90506001600160a01b03861630146107d5576107d28888611b35565b96505b6001600160a01b03891660009081526006602052604090205460609060ff16156108f657600354610813906001600160a01b038b811691168a611cfe565b6003546040516305c13d4360e11b81526001600160a01b0390911690630b827a869061084c908c908e908d906000908e90600401612c74565b6020604051808303816000875af115801561086b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061088f9190612ca4565b6040805160018082528183019092529197506020808301908036833701905050905088816000815181106108c5576108c5612cd3565b60200260200101906001600160a01b031690816001600160a01b0316815250506108ee81611d56565b945050610908565b6109028a8a8a8a6120a7565b95509550505b61092d61091484612c58565b6000356001600160e01b03199081169085161483611a13565b50505094509492505050565b600061095b61095760016000805160206130de833981519152612ce9565b5490565b905090565b6000606061096c6121c8565b63621b094a600061097e82600161186d565b90506001600160a01b038716610a62576103e83410156109c3576000346103e8604051630b722aef60e21b81526004016109ba93929190612cfc565b60405180910390fd5b7f00000000000000000000000069696969696969696969696969696969696969696001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015610a1e57600080fd5b505af1158015610a32573d6000803e3d6000fd5b50505050507f00000000000000000000000069696969696969696969696969696969696969699650349550610a9a565b6103e8861015610a8d5786866103e8604051630b722aef60e21b81526004016109ba93929190612cfc565b610a978787611b35565b95505b600154600090610ab090899061ffff16896121f2565b80925081985050506000879050886001600160a01b03168a6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b299190612d21565b6001600160a01b031614610ba957610ba48a6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b78573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9c9190612d21565b8a8a3061078d565b955090505b610c208a828c6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bec573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c109190612d21565b6001600160a01b0316919061224d565b60405163bc157ac160e01b815260048101829052336024820152604481018890526001600160a01b038b169063bc157ac1906064016020604051808303816000875af1158015610c74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c989190612ca4565b9550896001600160a01b0316336001600160a01b03167f87640c2e40d67703e350e7d24d4e416e5c4f1e1550e1285b1bf667440d36bdcf8b8b858b888c604051610ce796959493929190612d3e565b60405180910390a35050610cfe826106cd90612c58565b5050610d0a6001600055565b94509492505050565b6002546001600160a01b03163314610d3e57604051632d5be4cb60e21b815260040160405180910390fd5b63d473ef3c6000610d5082600161186d565b9050610d5b836119e9565b600380546001600160a01b038581166001600160a01b0319831681179093556040519116919082907f5c5b0bb5085481c320dc523e3b3f829eaa807936f615add0077fa213f345090e90600090a3506106d56106cd83612c58565b610dd2610957600160008051602061307e833981519152612ce9565b6001600160a01b0316336001600160a01b031614610e325760405162461bcd60e51b815260206004820181905260248201527f53706865726558206572726f723a206f70657261746f7220726571756972656460448201526064016109ba565b610e3b816122e5565b6000610e5961095760016000805160206130de833981519152612ce9565b9050610e7c610e7760016000805160206130de833981519152612ce9565b839055565b7ff33499cccaa0611882086224cc48cd82ef54b66a4d2edf4ed67108dd516896d58183604051610ead929190612d83565b60405180910390a15050565b610ed561095760016000805160206130be833981519152612ce9565b6001600160a01b0316336001600160a01b031614610f055760405162461bcd60e51b81526004016109ba90612d9d565b6000610f23610957600160008051602061307e833981519152612ce9565b9050610f41610e77600160008051602061307e833981519152612ce9565b7f2ac55ae7ba47db34b5334622acafeb34a65daf143b47019273185d64c73a35a58183604051610ead929190612d83565b33610f7b611139565b6001600160a01b031614610fe05760405162461bcd60e51b815260206004820152602660248201527f53706865726558206572726f723a206e6f74207468652070656e64696e67206160448201526518d8dbdd5b9d60d21b60648201526084016109ba565b6000610fea61111b565b905061100d61100860016000805160206130be833981519152612ce9565b339055565b61102f611029600160008051602061309e833981519152612ce9565b60009055565b7f67ebaebcd2ca5a91a404e898110f221747e8d15567f2388a34794aab151cf3e68133604051611060929190612d83565b60405180910390a150565b6002546001600160a01b0316331461109657604051632d5be4cb60e21b815260040160405180910390fd5b6103e861ffff821611156110cb57604051633c057d7b60e01b815261ffff821660048201526103e860248201526044016109ba565b6001805461ffff83811661ffff1983168117909355604080519190921680825260208201939093527fcd5c26e400cb366bdac1d1cbdec4b428f15bc14a133ecbda85bc6f11f7acb9f19101610ead565b600061095b61095760016000805160206130be833981519152612ce9565b600061095b610957600160008051602061309e833981519152612ce9565b600060606111636121c8565b63af73b205600061117582600161186d565b604051635d043b2960e11b8152600481018990523060248201523360448201529091506000906001600160a01b038a169063ba087652906064016020604051808303816000875af11580156111ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f29190612ca4565b90506001600160a01b038716611226577f000000000000000000000000696969696969696969696969696969696969696996505b866001600160a01b0316896001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561126e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112929190612d21565b6001600160a01b0316036112a85780945061131b565b611315896001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156112e9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130d9190612d21565b888330611718565b90955093505b600061133888600160029054906101000a900461ffff16886121f2565b909650905061134788336123bc565b508686101561138257604051632752fb4960e11b81526001600160a01b038916600482015260248101879052604481018890526064016109ba565b896001600160a01b0316336001600160a01b03167f0bc6c5ccdba0b566b3adbb7c24c419a1b872218cd487d145a4e4eb70b2c8bfb38a89868e878c604051610ce796959493929190612d3e565b6002546001600160a01b031633146113fa57604051632d5be4cb60e21b815260040160405180910390fd5b611403816119e9565b600280546001600160a01b0319166001600160a01b03831690811790915560405181907f3aaaebeb4821d6a7e5c77ece53cff0afcc56c82add2c978dbbb7f73e84cbcfd290600090a350565b6002546001600160a01b0316331461147a57604051632d5be4cb60e21b815260040160405180910390fd5b6103e861ffff821611156114af57604051633c057d7b60e01b815261ffff821660048201526103e860248201526044016109ba565b6001805461ffff8381166201000081810263ffff00001985161790945560408051949093049091168084526020840191909152917febcac71ae552a15ae4d23c933603e1a71f47ff8371bdd98194f037156b73a7199101610ead565b6002546001600160a01b0316331461153657604051632d5be4cb60e21b815260040160405180910390fd5b61153f836119e9565b6001600160a01b0383166000908152600660209081526040808320805486151560ff199182161790915560079092529091208054839216600183600981111561158a5761158a612b9f565b02179055507f3b79c840859aa9e93d93ccb4f7a8b6c425621929bcc61a03194f607a53d0f4ab8383836040516115c293929190612dd4565b60405180910390a1505050565b6115eb61095760016000805160206130be833981519152612ce9565b6001600160a01b0316336001600160a01b03161461161b5760405162461bcd60e51b81526004016109ba90612d9d565b61163c611637600160008051602061309e833981519152612ce9565b829055565b7f5778f1547abbbb86090a43c32aec38334b31df4beeb6f8f3fa063f593b53a52661166561111b565b82604051611060929190612d83565b6002546001600160a01b0316331461169f57604051632d5be4cb60e21b815260040160405180910390fd5b6116a8816119e9565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f0bc21fe5c3ab742ff1d15b5c4477ffbacf1167e618228078fa625edebe7f331d90600090a35050565b600061095b610957600160008051602061307e833981519152612ce9565b6000606063362279f763f99e638760e01b836117418382356001600160e01b031916841461186d565b90506001600160a01b03861630146117605761175d8988611b35565b96505b6001600160a01b03891660009081526006602052604090205460ff16156118515760035461179b906001600160a01b038b8116911689611cfe565b6003546040516305c13d4360e11b81526001600160a01b0390911690630b827a86906117d4908c908c908c906000908d90600401612c74565b6020604051808303816000875af11580156117f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118179190612ca4565b604080516001808252818301909252919650600091906020808301908036833701905050905089816000815181106108c5576108c5612cd3565b61185d8989898961244d565b9450945061092d61091484612c58565b6118a1604051806080016040528060608152602001606081526020016000815260200160006001600160a01b031681525090565b60006118ab610939565b6001600160a01b0316146119e35760006118c3610939565b9050821561194c57604051634492e52d60e11b81526001600160a01b03821690638925ca5a906118fe90879033906000903690600401612df9565b6000604051808303816000875af115801561191d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119459190810190612e40565b82526119be565b604051633e88494360e01b8152600481018590526001600160a01b03821690633e884943906024016000604051808303816000875af1158015611993573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119bb9190810190612e40565b82525b81516119c990612554565b60208301525a60408301526001600160a01b031660608201525b92915050565b6001600160a01b038116611a105760405163d92e233d60e01b815260040160405180910390fd5b50565b60608101516001600160a01b038116611a2c5750505050565b60005a8360400151611a3e9190612ce9565b90506060611a4f8460000151612554565b90508415611ac4576020840151604051631e17b28d60e31b81526001600160a01b0385169163f0bd946891611a8d918a918791908790600401612f22565b600060405180830381600087803b158015611aa757600080fd5b505af1158015611abb573d6000803e3d6000fd5b50505050611b2d565b602084015160405163027313cd60e11b81526001600160a01b038516916304e6279a91611afa918a918791908790600401612f22565b600060405180830381600087803b158015611b1457600080fd5b505af1158015611b28573d6000803e3d6000fd5b505050505b505050505050565b6000639ffc46616000611b4982600061186d565b905083856001600160a01b031663dd62ed3e33306040518363ffffffff1660e01b8152600401611b7a929190612d83565b602060405180830381865afa158015611b97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bbb9190612ca4565b1015611bda576040516332da96a360e01b815260040160405180910390fd5b6040516370a0823160e01b81526000906001600160a01b038716906370a0823190611c099030906004016129e4565b602060405180830381865afa158015611c26573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4a9190612ca4565b9050611c616001600160a01b03871633308861260b565b6040516370a0823160e01b81526000906001600160a01b038816906370a0823190611c909030906004016129e4565b602060405180830381865afa158015611cad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cd19190612ca4565b9050611cdd8282612ce9565b945050505b611cf6611cee83612c58565b600083611a13565b505092915050565b6106d583846001600160a01b031663a9059cbb8585604051602401611d24929190612f5e565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050612644565b60606365afacc16000611d6a82600061186d565b90506000845167ffffffffffffffff811115611d8857611d88612cbd565b604051908082528060200260200182016040528015611dcd57816020015b6040805180820190915260008082526020820152815260200190600190039081611da65790505b50935060005b85518110156120915760006001600160a01b0316868281518110611df957611df9612cd3565b60200260200101516001600160a01b0316031561207f57858181518110611e2257611e22612cd3565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611e5591906129e4565b602060405180830381865afa158015611e72573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e969190612ca4565b91506040518060400160405280878381518110611eb557611eb5612cd3565b60200260200101516001600160a01b0316815260200183815250858281518110611ee157611ee1612cd3565b6020908102919091010152811561207f577f00000000000000000000000069696969696969696969696969696969696969696001600160a01b0316868281518110611f2e57611f2e612cd3565b60200260200101516001600160a01b03160361204857604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000069696969696969696969696969696969696969696001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015611fa657600080fd5b505af1158015611fba573d6000803e3d6000fd5b5050604080516000808252602082019283905293503392508591611fde9190612f77565b60006040518083038185875af1925050503d806000811461201b576040519150601f19603f3d011682016040523d82523d6000602084013e612020565b606091505b50509050806120425760405163b12d13eb60e01b815260040160405180910390fd5b5061207f565b61207f338388848151811061205f5761205f612cd3565b60200260200101516001600160a01b0316611cfe9092919063ffffffff16565b8061208981612fa6565b915050611dd3565b50506120a082611cee90612c58565b5050919050565b6004546000906060906120c7906001600160a01b03878116911686611cfe565b600480546001600160a01b038881166000908152600760205260409081902054905163190a4d4960e01b8152919092169263190a4d4992612116928b928b928b928b9260ff9092169101612fbf565b6020604051808303816000875af1158015612135573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121599190612ca4565b6040805160018082528183019092529193506000919060208083019080368337019050509050858160008151811061219357612193612cd3565b60200260200101906001600160a01b031690816001600160a01b0316815250506121bc81611d56565b91505094509492505050565b6002600054036121eb57604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b60008061ffff8416156122425761271061221061ffff861685612ff3565b61221a919061300a565b6005549091506122359086906001600160a01b03168361269e565b61223f8184612ce9565b92505b829150935093915050565b6000836001600160a01b031663095ea7b38484604051602401612271929190612f5e565b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505090506122aa84826127f8565b6122df576122d584856001600160a01b031663095ea7b3866000604051602401611d24929190612f5e565b6122df8482612644565b50505050565b6001600160a01b038116158061236557506040516301ffc9a760e01b81526329f20dd560e11b60048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa158015612341573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612365919061302c565b611a105760405162461bcd60e51b815260206004820152602260248201527f53706865726558206572726f723a206e6f7420612053706865726558456e67696044820152616e6560f01b60648201526084016109ba565b600063f45372f860006123d082600061186d565b6040516370a0823160e01b81529091506001600160a01b038616906370a08231906123ff9030906004016129e4565b602060405180830381865afa15801561241c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124409190612ca4565b9250611ce285858561269e565b60045460009060609061246d906001600160a01b03888116911686611cfe565b600480546001600160a01b038881166000908152600760205260409081902054905163616a3dbd60e11b8152919092169263c2d47b7a926124bc928b928a928a928d9260ff9092169101613049565b6020604051808303816000875af11580156124db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124ff9190612ca4565b91506001600160a01b038316301461251d5761251b85846123bc565b505b6040805160018082528183019092526000916020808301908036833701905050905060008160008151811061219357612193612cd3565b805160609060008167ffffffffffffffff81111561257457612574612cbd565b60405190808252806020026020018201604052801561259d578160200160208202803683370190505b50905060005b828110156126035760008582815181106125bf576125bf612cd3565b60200260200101519050600081549050808484815181106125e2576125e2612cd3565b602002602001018181525050505080806125fb90612fa6565b9150506125a3565b509392505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526122df9186918216906323b872dd90608401611d24565b60006126596001600160a01b038416836128a0565b9050805160001415801561267e57508080602001905181019061267c919061302c565b155b156106d55782604051635274afe760e01b81526004016109ba91906129e4565b80156106d5577f00000000000000000000000069696969696969696969696969696969696969696001600160a01b0316836001600160a01b0316036127e457604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000069696969696969696969696969696969696969696001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561273f57600080fd5b505af1158015612753573d6000803e3d6000fd5b5050604080516000808252602082019283905293506001600160a01b038616925084916127809190612f77565b60006040518083038185875af1925050503d80600081146127bd576040519150601f19603f3d011682016040523d82523d6000602084013e6127c2565b606091505b50509050806122df5760405163b12d13eb60e01b815260040160405180910390fd5b6106d56001600160a01b0384168383611cfe565b6000806000846001600160a01b0316846040516128159190612f77565b6000604051808303816000865af19150503d8060008114612852576040519150601f19603f3d011682016040523d82523d6000602084013e612857565b606091505b5091509150818015612881575080511580612881575080806020019051810190612881919061302c565b801561289757506000856001600160a01b03163b115b95945050505050565b60606128ae838360006128b5565b9392505050565b6060814710156128da573060405163cd78605960e01b81526004016109ba91906129e4565b600080856001600160a01b031684866040516128f69190612f77565b60006040518083038185875af1925050503d8060008114612933576040519150601f19603f3d011682016040523d82523d6000602084013e612938565b606091505b5091509150612948868383612952565b9695505050505050565b60608261296757612962826129a5565b6128ae565b815115801561297e57506001600160a01b0384163b155b1561299e5783604051639996b31560e01b81526004016109ba91906129e4565b50806128ae565b8051156129b55780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b600052600160045260246000fd5b6001600160a01b0391909116815260200190565b6001600160a01b0381168114611a1057600080fd5b600060208284031215612a1f57600080fd5b81356128ae816129f8565b60008060008060808587031215612a4057600080fd5b8435612a4b816129f8565b93506020850135612a5b816129f8565b9250604085013591506060850135612a72816129f8565b939692955090935050565b600081518084526020808501945080840160005b83811015612ac157815180516001600160a01b031688528301518388015260409096019590820190600101612a91565b509495945050505050565b828152604060208201526000612ae56040830184612a7d565b949350505050565b60008060008060808587031215612b0357600080fd5b8435612b0e816129f8565b93506020850135612b1e816129f8565b93969395505050506040820135916060013590565b600060208284031215612b4557600080fd5b813561ffff811681146128ae57600080fd5b60008060008060808587031215612b6d57600080fd5b8435612b78816129f8565b9350602085013592506040850135612b8f816129f8565b9396929550929360600135925050565b634e487b7160e01b600052602160045260246000fd5b600a8110612bd357634e487b7160e01b600052602160045260246000fd5b9052565b602081016119e38284612bb5565b8015158114611a1057600080fd5b600080600060608486031215612c0857600080fd5b8335612c13816129f8565b92506020840135612c2381612be5565b91506040840135600a8110612c3757600080fd5b809150509250925092565b634e487b7160e01b600052601160045260246000fd5b6000600160ff1b8201612c6d57612c6d612c42565b5060000390565b6001600160a01b039586168152938516602085015260408401929092526060830152909116608082015260a00190565b600060208284031215612cb657600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b818103818111156119e3576119e3612c42565b6001600160a01b03939093168352602083019190915261ffff16604082015260600190565b600060208284031215612d3357600080fd5b81516128ae816129f8565b60018060a01b038716815285602082015284604082015283606082015282608082015260c060a08201526000612d7760c0830184612a7d565b98975050505050505050565b6001600160a01b0392831681529116602082015260400190565b6020808252601d908201527f53706865726558206572726f723a2061646d696e207265717569726564000000604082015260600190565b6001600160a01b0384168152821515602082015260608101612ae56040830184612bb5565b8481526001600160a01b03841660208201526060604082018190528101829052818360808301376000818301608090810191909152601f909201601f191601019392505050565b60006020808385031215612e5357600080fd5b825167ffffffffffffffff80821115612e6b57600080fd5b818501915085601f830112612e7f57600080fd5b815181811115612e9157612e91612cbd565b8060051b604051601f19603f83011681018181108582111715612eb657612eb6612cbd565b604052918252848201925083810185019188831115612ed457600080fd5b938501935b82851015612d7757845184529385019392850192612ed9565b600081518084526020808501945080840160005b83811015612ac157815187529582019590820190600101612f06565b848152836020820152608060408201526000612f416080830185612ef2565b8281036060840152612f538185612ef2565b979650505050505050565b6001600160a01b03929092168252602082015260400190565b6000825160005b81811015612f985760208186018101518583015201612f7e565b506000920191825250919050565b600060018201612fb857612fb8612c42565b5060010190565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a081016129486080830184612bb5565b80820281158282048414176119e3576119e3612c42565b60008261302757634e487b7160e01b600052601260045260246000fd5b500490565b60006020828403121561303e57600080fd5b81516128ae81612be5565b6001600160a01b0386811682526020820186905284811660408301528316606082015260a081016129486080830184612bb556feadf90d75f0f2d657d5a22fa0f6e4dabb83c4598b77158eb4119cb38f1d8644633a517dd736309b905c692160a21b5439bdc56db1dc77d6982b66d44814e3fa97ca334bf49ef20e9cbff039feda3bc1c2a853aff17b1b5187e4aa1380ec55829d1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d6a2646970667358221220e0aee4aeb6db0c3f61c43ffb68da9dd25134753dde08db7a00f10990d2d97ec164736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000062137cec7754aa3f530c98866a86dba36d2687170000000000000000000000006969696969696969696969696969696969696969000000000000000000000000fcbd14dc51f0a4d49d5e53c2e0950e0bc26d0dce000000000000000000000000252e9b9dd86aad41166e682712b75a45bb779433000000000000000000000000944e034b1e3ff30becb3661b4960f47ddf14af3d0000000000000000000000001cfe31bfa1ac9b28588c91bb4300a1ed032f069f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : devAddress (address): 0x62137cEc7754aA3f530c98866a86dba36d268717
Arg [1] : wrappedNative (address): 0x6969696969696969696969696969696969696969
Arg [2] : stablecoin (address): 0xFCBD14DC51f0A4d49d5E53C2E0950e0bC26d0Dce
Arg [3] : swapRouter (address): 0x252E9B9Dd86AAD41166e682712B75A45Bb779433
Arg [4] : lpRouter (address): 0x944e034B1E3fF30BeCb3661b4960f47DdF14Af3D
Arg [5] : feeRecipient (address): 0x1cfe31Bfa1Ac9b28588C91BB4300A1ED032F069F
Arg [6] : zapInFee (uint16): 0
Arg [7] : zapOutFee (uint16): 0
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 00000000000000000000000062137cec7754aa3f530c98866a86dba36d268717
Arg [1] : 0000000000000000000000006969696969696969696969696969696969696969
Arg [2] : 000000000000000000000000fcbd14dc51f0a4d49d5e53c2e0950e0bc26d0dce
Arg [3] : 000000000000000000000000252e9b9dd86aad41166e682712b75a45bb779433
Arg [4] : 000000000000000000000000944e034b1e3ff30becb3661b4960f47ddf14af3d
Arg [5] : 0000000000000000000000001cfe31bfa1ac9b28588c91bb4300a1ed032f069f
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.