Overview
BERA Balance
BERA Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 816 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Zap In | 4088121 | 5 mins ago | IN | 0 BERA | 0 | ||||
Zap Out | 4087865 | 14 mins ago | IN | 0 BERA | 0.00013984 | ||||
Zap In | 4086144 | 1 hr ago | IN | 0 BERA | 0.00000185 | ||||
Zap Out | 4085102 | 1 hr ago | IN | 0 BERA | 0.00033407 | ||||
Zap Out | 4084292 | 2 hrs ago | IN | 0 BERA | 0 | ||||
Zap Out | 4084223 | 2 hrs ago | IN | 0 BERA | 0.00031958 | ||||
Zap In | 4082629 | 3 hrs ago | IN | 0 BERA | 0.00002652 | ||||
Zap Out | 4080371 | 4 hrs ago | IN | 0 BERA | 0.00032077 | ||||
Zap Out | 4077391 | 5 hrs ago | IN | 0 BERA | 0 | ||||
Zap Out | 4077375 | 5 hrs ago | IN | 0 BERA | 0 | ||||
Zap Out | 4077357 | 5 hrs ago | IN | 0 BERA | 0 | ||||
Zap Out | 4077344 | 5 hrs ago | IN | 0 BERA | 0 | ||||
Zap Out | 4076499 | 6 hrs ago | IN | 0 BERA | 0.00032997 | ||||
Zap In | 4076117 | 6 hrs ago | IN | 0 BERA | 0 | ||||
Zap In | 4075777 | 6 hrs ago | IN | 0 BERA | 0 | ||||
Zap Out | 4075236 | 7 hrs ago | IN | 0 BERA | 0.00000276 | ||||
Zap In | 4072087 | 8 hrs ago | IN | 0.00002619 BERA | 0 | ||||
Zap Out | 4071892 | 8 hrs ago | IN | 0 BERA | 0 | ||||
Zap In | 4071825 | 9 hrs ago | IN | 0.15499999 BERA | 0 | ||||
Zap In | 4071792 | 9 hrs ago | IN | 0.00030392 BERA | 0 | ||||
Zap In | 4071791 | 9 hrs ago | IN | 0.15499999 BERA | 0 | ||||
Zap In | 4071443 | 9 hrs ago | IN | 0 BERA | 0.00001221 | ||||
Zap In | 4071075 | 9 hrs ago | IN | 7.47979026 BERA | 0 | ||||
Zap Out | 4069629 | 10 hrs ago | IN | 0 BERA | 0.00000011 | ||||
Zap Out | 4068639 | 10 hrs ago | IN | 0 BERA | 0 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
4085102 | 1 hr ago | 17.15338595 BERA | ||||
4085102 | 1 hr ago | 17.15338595 BERA | ||||
4084292 | 2 hrs ago | 70.11935048 BERA | ||||
4084292 | 2 hrs ago | 70.11935048 BERA | ||||
4084223 | 2 hrs ago | 94.83124387 BERA | ||||
4084223 | 2 hrs ago | 94.83124387 BERA | ||||
4080371 | 4 hrs ago | 40.04120825 BERA | ||||
4080371 | 4 hrs ago | 40.04120825 BERA | ||||
4077391 | 5 hrs ago | 0.04078295 BERA | ||||
4077391 | 5 hrs ago | 0.04078295 BERA | ||||
4077375 | 5 hrs ago | 0.01023044 BERA | ||||
4077375 | 5 hrs ago | 0.01023044 BERA | ||||
4077357 | 5 hrs ago | 0.02936785 BERA | ||||
4077357 | 5 hrs ago | 0.02936785 BERA | ||||
4077344 | 5 hrs ago | 0.0602096 BERA | ||||
4077344 | 5 hrs ago | 0.0602096 BERA | ||||
4076499 | 6 hrs ago | 112.38976737 BERA | ||||
4076499 | 6 hrs ago | 112.38976737 BERA | ||||
4072087 | 8 hrs ago | 0.00000029 BERA | ||||
4072087 | 8 hrs ago | 0.00000029 BERA | ||||
4072087 | 8 hrs ago | 0.00002619 BERA | ||||
4071892 | 8 hrs ago | 0.00007446 BERA | ||||
4071892 | 8 hrs ago | 0.00007446 BERA | ||||
4071825 | 9 hrs ago | 0.00174606 BERA | ||||
4071825 | 9 hrs ago | 0.00174606 BERA |
Loading...
Loading
Contract Name:
KodiakZapper
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 {IKodiakVaultV1, IKodiakV1RouterStaking} from "../interfaces/kodiak/IKodiak.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.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 {ISwapRouter} from "../interfaces/ISwapRouter.sol"; import {IDexType} from "../interfaces/IDexType.sol"; /** * @title KodiakZapper * @notice A zapper contract that enables single-token deposits and withdrawals for Kodiak vaults * @dev This contract handles the conversion between a single input token and the token pair required by Kodiak vaults. * It manages the optimal ratio calculation and token swaps to match Kodiak's deposit requirements. * * Key features: * - Single token deposits: Users can deposit a single token which gets converted to the required token pair * - Optimal ratio calculation: Automatically determines the best token ratio for deposits * - Withdrawal to single token: Converts withdrawn token pairs back to a single desired token * - Supports both native token and ERC20 deposits */ contract KodiakZapper is ZapperBase { using SafeERC20 for IERC20; constructor( address governanceAddress, address wrappedNative, address stableCoin, address swapRouter, address lpRouter, address feeRecipient, uint16 zapInFee, uint16 zapOutFee ) ZapperBase(governanceAddress, 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 returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets) { if (recipient != address(this)) { tokenInAmount = _safeTransferFromTokens(tokenIn, tokenInAmount); } IERC20(tokenIn).safeTransfer(address(lpRouter), tokenInAmount); tokenOutAmount = lpRouter.addLiquidity(asset, tokenIn, tokenInAmount, recipient, IDexType.DexType.KODIAK_V3); returnedAssets = _returnAsset(tokenIn, msg.sender); } /** * @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 returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets) { if (recipient != address(this)) { assetsInAmount = _safeTransferFromTokens(asset, assetsInAmount); } //send assetsIn to lpRouter IERC20(asset).safeTransfer(address(lpRouter), assetsInAmount); tokenOutAmount = lpRouter.removeLiquidity( asset, assetsInAmount, address(this), tokenOut, IDexType.DexType.KODIAK_V3 ); if (recipient != address(this)) { returnedAssets = _returnAsset(tokenOut, recipient); } } }
// 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: 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); function version() external view returns (string memory); }
// 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: GPL-2.0-or-later pragma solidity 0.8.20; interface IUniswapV3Router { struct ExactInputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; uint160 sqrtPriceLimitX96; } /// @notice Swaps `amountIn` of one token for as much as possible of another token /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata /// @return amountOut The amount of the received token function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut); struct ExactInputParams { bytes path; address recipient; uint256 deadline; uint256 amountIn; uint256 amountOutMinimum; } /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata /// @return amountOut The amount of the received token function exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut); struct ExactOutputSingleParams { address tokenIn; address tokenOut; uint24 fee; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; uint160 sqrtPriceLimitX96; } /// @notice Swaps as little as possible of one token for `amountOut` of another token /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata /// @return amountIn The amount of the input token function exactOutputSingle(ExactOutputSingleParams calldata params) external payable returns (uint256 amountIn); struct ExactOutputParams { bytes path; address recipient; uint256 deadline; uint256 amountOut; uint256 amountInMaximum; } /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata /// @return amountIn The amount of the input token function exactOutput(ExactOutputParams calldata params) external payable returns (uint256 amountIn); } /// @title QuoterV2 Interface /// @notice Supports quoting the calculated amounts from exact input or exact output swaps. /// @notice For each pool also tells you the number of initialized ticks crossed and the sqrt price of the pool after the swap. /// @dev These functions are not marked view because they rely on calling non-view functions and reverting /// to compute the result. They are also not gas efficient and should not be called on-chain. interface IQuoterV2 { /// @notice Returns the amount out received for a given exact input swap without executing the swap /// @param path The path of the swap, i.e. each token pair and the pool fee /// @param amountIn The amount of the first token to swap /// @return amountOut The amount of the last token that would be received /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path /// @return gasEstimate The estimate of the gas that the swap consumes function quoteExactInput( bytes memory path, uint256 amountIn ) external returns ( uint256 amountOut, uint160[] memory sqrtPriceX96AfterList, uint32[] memory initializedTicksCrossedList, uint256 gasEstimate ); struct QuoteExactInputSingleParams { address tokenIn; address tokenOut; uint256 amountIn; uint24 fee; uint160 sqrtPriceLimitX96; } /// @notice Returns the amount out received for a given exact input but for a swap of a single pool /// @param params The params for the quote, encoded as `QuoteExactInputSingleParams` /// tokenIn The token being swapped in /// tokenOut The token being swapped out /// fee The fee of the token pool to consider for the pair /// amountIn The desired input amount /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap /// @return amountOut The amount of `tokenOut` that would be received /// @return sqrtPriceX96After The sqrt price of the pool after the swap /// @return initializedTicksCrossed The number of initialized ticks that the swap crossed /// @return gasEstimate The estimate of the gas that the swap consumes function quoteExactInputSingle( QuoteExactInputSingleParams memory params ) external returns (uint256 amountOut, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate); /// @notice Returns the amount in required for a given exact output swap without executing the swap /// @param path The path of the swap, i.e. each token pair and the pool fee. Path must be provided in reverse order /// @param amountOut The amount of the last token to receive /// @return amountIn The amount of first token required to be paid /// @return sqrtPriceX96AfterList List of the sqrt price after the swap for each pool in the path /// @return initializedTicksCrossedList List of the initialized ticks that the swap crossed for each pool in the path /// @return gasEstimate The estimate of the gas that the swap consumes function quoteExactOutput( bytes memory path, uint256 amountOut ) external returns ( uint256 amountIn, uint160[] memory sqrtPriceX96AfterList, uint32[] memory initializedTicksCrossedList, uint256 gasEstimate ); struct QuoteExactOutputSingleParams { address tokenIn; address tokenOut; uint256 amount; uint24 fee; uint160 sqrtPriceLimitX96; } /// @notice Returns the amount in required to receive the given exact output amount but for a swap of a single pool /// @param params The params for the quote, encoded as `QuoteExactOutputSingleParams` /// tokenIn The token being swapped in /// tokenOut The token being swapped out /// fee The fee of the token pool to consider for the pair /// amountOut The desired output amount /// sqrtPriceLimitX96 The price limit of the pool that cannot be exceeded by the swap /// @return amountIn The amount required as the input for the swap in order to receive `amountOut` /// @return sqrtPriceX96After The sqrt price of the pool after the swap /// @return initializedTicksCrossed The number of initialized ticks that the swap crossed /// @return gasEstimate The estimate of the gas that the swap consumes function quoteExactOutputSingle( QuoteExactOutputSingleParams memory params ) external returns (uint256 amountIn, uint160 sqrtPriceX96After, uint32 initializedTicksCrossed, uint256 gasEstimate); } /// @title The interface for the Uniswap V3 Factory /// @notice The Uniswap V3 Factory facilitates creation of Uniswap V3 pools and control over the protocol fees interface IUniswapV3Factory { /// @notice Emitted when the owner of the factory is changed /// @param oldOwner The owner before the owner was changed /// @param newOwner The owner after the owner was changed event OwnerChanged(address indexed oldOwner, address indexed newOwner); /// @notice Emitted when a pool is created /// @param token0 The first token of the pool by address sort order /// @param token1 The second token of the pool by address sort order /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip /// @param tickSpacing The minimum number of ticks between initialized ticks /// @param pool The address of the created pool event PoolCreated( address indexed token0, address indexed token1, uint24 indexed fee, int24 tickSpacing, address pool ); /// @notice Emitted when a new fee amount is enabled for pool creation via the factory /// @param fee The enabled fee, denominated in hundredths of a bip /// @param tickSpacing The minimum number of ticks between initialized ticks for pools created with the given fee event FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing); /// @notice Returns the current owner of the factory /// @dev Can be changed by the current owner via setOwner /// @return The address of the factory owner function owner() external view returns (address); /// @notice Returns the tick spacing for a given fee amount, if enabled, or 0 if not enabled /// @dev A fee amount can never be removed, so this value should be hard coded or cached in the calling context /// @param fee The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled fee /// @return The tick spacing function feeAmountTickSpacing(uint24 fee) external view returns (int24); /// @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist /// @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order /// @param tokenA The contract address of either token0 or token1 /// @param tokenB The contract address of the other token /// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip /// @return pool The pool address function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool); /// @notice Creates a pool for the given two tokens and fee /// @param tokenA One of the two tokens in the desired pool /// @param tokenB The other of the two tokens in the desired pool /// @param fee The desired fee for the pool /// @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. tickSpacing is retrieved /// from the fee. The call will revert if the pool already exists, the fee is invalid, or the token arguments /// are invalid. /// @return pool The address of the newly created pool function createPool(address tokenA, address tokenB, uint24 fee) external returns (address pool); /// @notice Updates the owner of the factory /// @dev Must be called by the current owner /// @param _owner The new owner of the factory function setOwner(address _owner) external; /// @notice Enables a fee amount with the given tickSpacing /// @dev Fee amounts may never be removed once enabled /// @param fee The fee amount to enable, denominated in hundredths of a bip (i.e. 1e-6) /// @param tickSpacing The spacing between ticks to be enforced for all pools created with the given fee amount function enableFeeAmount(uint24 fee, int24 tickSpacing) external; } /** * @title The interface for the Algebra Factory * @dev Credit to Uniswap Labs under GPL-2.0-or-later license: * https://github.com/Uniswap/v3-core/tree/main/contracts/interfaces */ interface IAlgebraFactory { /** * @notice Emitted when the owner of the factory is changed * @param newOwner The owner after the owner was changed */ event Owner(address indexed newOwner); /** * @notice Emitted when the vault address is changed * @param newVaultAddress The vault address after the address was changed */ event VaultAddress(address indexed newVaultAddress); /** * @notice Emitted when a pool is created * @param token0 The first token of the pool by address sort order * @param token1 The second token of the pool by address sort order * @param pool The address of the created pool */ event Pool(address indexed token0, address indexed token1, address pool); /** * @notice Emitted when the farming address is changed * @param newFarmingAddress The farming address after the address was changed */ event FarmingAddress(address indexed newFarmingAddress); /** * @notice Emitted when the default community fee is changed * @param newDefaultCommunityFee The new default community fee value */ event DefaultCommunityFee(uint8 newDefaultCommunityFee); event FeeConfiguration( uint16 alpha1, uint16 alpha2, uint32 beta1, uint32 beta2, uint16 gamma1, uint16 gamma2, uint32 volumeBeta, uint16 volumeGamma, uint16 baseFee ); /** * @notice Returns the current owner of the factory * @dev Can be changed by the current owner via setOwner * @return The address of the factory owner */ function owner() external view returns (address); /** * @notice Returns the current poolDeployerAddress * @return The address of the poolDeployer */ function poolDeployer() external view returns (address); /** * @dev Is retrieved from the pools to restrict calling * certain functions not by a tokenomics contract * @return The tokenomics contract address */ function farmingAddress() external view returns (address); /** * @notice Returns the default community fee * @return Fee which will be set at the creation of the pool */ function defaultCommunityFee() external view returns (uint8); function vaultAddress() external view returns (address); /** * @notice Returns the pool address for a given pair of tokens and a fee, or address 0 if it does not exist * @dev tokenA and tokenB may be passed in either token0/token1 or token1/token0 order * @param tokenA The contract address of either token0 or token1 * @param tokenB The contract address of the other token * @return pool The pool address */ function poolByPair(address tokenA, address tokenB) external view returns (address pool); /** * @notice Creates a pool for the given two tokens and fee * @param tokenA One of the two tokens in the desired pool * @param tokenB The other of the two tokens in the desired pool * @dev tokenA and tokenB may be passed in either order: token0/token1 or token1/token0. tickSpacing is retrieved * from the fee. The call will revert if the pool already exists, the fee is invalid, or the token arguments * are invalid. * @return pool The address of the newly created pool */ function createPool(address tokenA, address tokenB) external returns (address pool); } /// @title Pool state that never changes /// @notice These parameters are fixed for a pool forever, i.e., the methods will always return the same values interface IUniswapV3PoolImmutables { /// @notice The contract that deployed the pool, which must adhere to the IUniswapV3Factory interface /// @return The contract address function factory() external view returns (address); /// @notice The first of the two tokens of the pool, sorted by address /// @return The token contract address function token0() external view returns (address); /// @notice The second of the two tokens of the pool, sorted by address /// @return The token contract address function token1() external view returns (address); /// @notice The pool's fee in hundredths of a bip, i.e. 1e-6 /// @return The fee function fee() external view returns (uint24); /// @notice The pool tick spacing /// @dev Ticks can only be used at multiples of this value, minimum of 1 and always positive /// e.g.: a tickSpacing of 3 means ticks can be initialized every 3rd tick, i.e., ..., -6, -3, 0, 3, 6, ... /// This value is an int24 to avoid casting even though it is always positive. /// @return The tick spacing function tickSpacing() external view returns (int24); /// @notice The maximum amount of position liquidity that can use any tick in the range /// @dev This parameter is enforced per tick to prevent liquidity from overflowing a uint128 at any point, and /// also prevents out-of-range liquidity from being used to prevent adding in-range liquidity to a pool /// @return The max amount of liquidity per tick function maxLiquidityPerTick() external view returns (uint128); } /// @title Pool state that can change /// @notice These methods compose the pool's state, and can change with any frequency including multiple times /// per transaction interface IUniswapV3PoolState { /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas /// when accessed externally. /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value /// tick The current tick of the pool, i.e. according to the last tick transition that was run. /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick /// boundary. /// observationIndex The index of the last oracle observation that was written, /// observationCardinality The current maximum number of observations stored in the pool, /// observationCardinalityNext The next maximum number of observations, to be updated when the observation. /// feeProtocol The protocol fee for both tokens of the pool. /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0 /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee. /// unlocked Whether the pool is currently locked to reentrancy function slot0() external view returns ( uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked ); /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool /// @dev This value can overflow the uint256 function feeGrowthGlobal0X128() external view returns (uint256); /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool /// @dev This value can overflow the uint256 function feeGrowthGlobal1X128() external view returns (uint256); /// @notice The amounts of token0 and token1 that are owed to the protocol /// @dev Protocol fees will never exceed uint128 max in either token function protocolFees() external view returns (uint128 token0, uint128 token1); /// @notice The currently in range liquidity available to the pool /// @dev This value has no relationship to the total liquidity across all ticks function liquidity() external view returns (uint128); /// @notice Look up information about a specific tick in the pool /// @param tick The tick to look up /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or /// tick upper, /// liquidityNet how much liquidity changes when the pool price crosses the tick, /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0, /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1, /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick, /// secondsOutside the seconds spent on the other side of the tick from the current tick, /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false. /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0. /// In addition, these values are only relative and must be used only in comparison to previous snapshots for /// a specific position. function ticks( int24 tick ) external view returns ( uint128 liquidityGross, int128 liquidityNet, uint256 feeGrowthOutside0X128, uint256 feeGrowthOutside1X128, int56 tickCumulativeOutside, uint160 secondsPerLiquidityOutsideX128, uint32 secondsOutside, bool initialized ); /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information function tickBitmap(int16 wordPosition) external view returns (uint256); /// @notice Returns the information about a position by the position's key /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper /// @return _liquidity The amount of liquidity in the position, /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke, /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke, /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke, /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke function positions( bytes32 key ) external view returns ( uint128 _liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1 ); /// @notice Returns data about a specific observation index /// @param index The element of the observations array to fetch /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time /// ago, rather than at a specific index in the array. /// @return blockTimestamp The timestamp of the observation, /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp, /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp, /// Returns initialized whether the observation has been initialized and the values are safe to use function observations( uint256 index ) external view returns (uint32 blockTimestamp, int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128, bool initialized); } interface IKodiakswapV3PoolState { /// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas /// when accessed externally. /// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value /// tick The current tick of the pool, i.e. according to the last tick transition that was run. /// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick /// boundary. /// observationIndex The index of the last oracle observation that was written, /// observationCardinality The current maximum number of observations stored in the pool, /// observationCardinalityNext The next maximum number of observations, to be updated when the observation. /// feeProtocol The protocol fee for both tokens of the pool. /// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0 /// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee. /// unlocked Whether the pool is currently locked to reentrancy function slot0() external view returns ( uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint32 feeProtocol, bool unlocked ); /// @notice The fee growth as a Q128.128 fees of token0 collected per unit of liquidity for the entire life of the pool /// @dev This value can overflow the uint256 function feeGrowthGlobal0X128() external view returns (uint256); /// @notice The fee growth as a Q128.128 fees of token1 collected per unit of liquidity for the entire life of the pool /// @dev This value can overflow the uint256 function feeGrowthGlobal1X128() external view returns (uint256); /// @notice The amounts of token0 and token1 that are owed to the protocol /// @dev Protocol fees will never exceed uint128 max in either token function protocolFees() external view returns (uint128 token0, uint128 token1); /// @notice The currently in range liquidity available to the pool /// @dev This value has no relationship to the total liquidity across all ticks function liquidity() external view returns (uint128); /// @notice Look up information about a specific tick in the pool /// @param tick The tick to look up /// @return liquidityGross the total amount of position liquidity that uses the pool either as tick lower or /// tick upper, /// liquidityNet how much liquidity changes when the pool price crosses the tick, /// feeGrowthOutside0X128 the fee growth on the other side of the tick from the current tick in token0, /// feeGrowthOutside1X128 the fee growth on the other side of the tick from the current tick in token1, /// tickCumulativeOutside the cumulative tick value on the other side of the tick from the current tick /// secondsPerLiquidityOutsideX128 the seconds spent per liquidity on the other side of the tick from the current tick, /// secondsOutside the seconds spent on the other side of the tick from the current tick, /// initialized Set to true if the tick is initialized, i.e. liquidityGross is greater than 0, otherwise equal to false. /// Outside values can only be used if the tick is initialized, i.e. if liquidityGross is greater than 0. /// In addition, these values are only relative and must be used only in comparison to previous snapshots for /// a specific position. function ticks( int24 tick ) external view returns ( uint128 liquidityGross, int128 liquidityNet, uint256 feeGrowthOutside0X128, uint256 feeGrowthOutside1X128, int56 tickCumulativeOutside, uint160 secondsPerLiquidityOutsideX128, uint32 secondsOutside, bool initialized ); /// @notice Returns 256 packed tick initialized boolean values. See TickBitmap for more information function tickBitmap(int16 wordPosition) external view returns (uint256); /// @notice Returns the information about a position by the position's key /// @param key The position's key is a hash of a preimage composed by the owner, tickLower and tickUpper /// @return _liquidity The amount of liquidity in the position, /// Returns feeGrowthInside0LastX128 fee growth of token0 inside the tick range as of the last mint/burn/poke, /// Returns feeGrowthInside1LastX128 fee growth of token1 inside the tick range as of the last mint/burn/poke, /// Returns tokensOwed0 the computed amount of token0 owed to the position as of the last mint/burn/poke, /// Returns tokensOwed1 the computed amount of token1 owed to the position as of the last mint/burn/poke function positions( bytes32 key ) external view returns ( uint128 _liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128, uint128 tokensOwed0, uint128 tokensOwed1 ); /// @notice Returns data about a specific observation index /// @param index The element of the observations array to fetch /// @dev You most likely want to use #observe() instead of this method to get an observation as of some amount of time /// ago, rather than at a specific index in the array. /// @return blockTimestamp The timestamp of the observation, /// Returns tickCumulative the tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp, /// Returns secondsPerLiquidityCumulativeX128 the seconds per in range liquidity for the life of the pool as of the observation timestamp, /// Returns initialized whether the observation has been initialized and the values are safe to use function observations( uint256 index ) external view returns (uint32 blockTimestamp, int56 tickCumulative, uint160 secondsPerLiquidityCumulativeX128, bool initialized); } /// @title Pool state that is not stored /// @notice Contains view functions to provide information about the pool that is computed rather than stored on the /// blockchain. The functions here may have variable gas costs. interface IUniswapV3PoolDerivedState { /// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp /// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing /// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick, /// you must call it with secondsAgos = [3600, 0]. /// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in /// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio. /// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned /// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp /// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block /// timestamp function observe( uint32[] calldata secondsAgos ) external view returns (int56[] memory tickCumulatives, uint160[] memory secondsPerLiquidityCumulativeX128s); /// @notice Returns a snapshot of the tick cumulative, seconds per liquidity and seconds inside a tick range /// @dev Snapshots must only be compared to other snapshots, taken over a period for which a position existed. /// I.e., snapshots cannot be compared if a position is not held for the entire period between when the first /// snapshot is taken and the second snapshot is taken. /// @param tickLower The lower tick of the range /// @param tickUpper The upper tick of the range /// @return tickCumulativeInside The snapshot of the tick accumulator for the range /// @return secondsPerLiquidityInsideX128 The snapshot of seconds per liquidity for the range /// @return secondsInside The snapshot of seconds per liquidity for the range function snapshotCumulativesInside( int24 tickLower, int24 tickUpper ) external view returns (int56 tickCumulativeInside, uint160 secondsPerLiquidityInsideX128, uint32 secondsInside); } /// @title The interface for a Uniswap V3 Pool /// @notice A Uniswap pool facilitates swapping and automated market making between any two assets that strictly conform /// to the ERC20 specification /// @dev The pool interface is broken up into many smaller pieces interface IUniswapV3Pool is IUniswapV3PoolImmutables, IUniswapV3PoolState, IUniswapV3PoolDerivedState { } interface IUniswapV3PoolWithUint32FeeProtocol is IUniswapV3PoolImmutables, IUniswapV3PoolDerivedState { function slot0() external view returns ( uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint32 feeProtocol, bool unlocked ); }
// 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 Thrown when pool type is not supported error UnsupportedBexPoolType(); /// @notice Thrown when failed to parse pool type error FailedToParsePoolType(); /// @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 Emitted when a DEX pool fee denominator is set /// @param dex The DEX index /// @param feeDenominator The pool fee denominator event SetDexFeeDenominator(uint8 dex, uint256 feeDenominator); /// @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 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 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 fee recipient address is updated /// @param oldFeeRecipient The old fee recipient address /// @param newFeeRecipient The new fee recipient address event FeeRecipientChanged(address indexed oldFeeRecipient, address indexed newFeeRecipient); /// @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: GPL-3.0 pragma solidity 0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IUniswapV3Pool} from "../exchange/UniswapV3.sol"; interface IKodiakVaultV1 { function mint( uint256 mintAmount, address receiver ) external returns (uint256 amount0, uint256 amount1, uint128 liquidityMinted); function burn( uint256 burnAmount, address receiver ) external returns (uint256 amount0, uint256 amount1, uint128 liquidityBurned); function getMintAmounts( uint256 amount0Max, uint256 amount1Max ) external view returns (uint256 amount0, uint256 amount1, uint256 mintAmount); function getUnderlyingBalances() external view returns (uint256 amount0, uint256 amount1); function getPositionID() external view returns (bytes32 positionID); function token0() external view returns (address); function token1() external view returns (address); function upperTick() external view returns (int24); function lowerTick() external view returns (int24); function pool() external view returns (IUniswapV3Pool); function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); } interface IGauge { function deposit(uint256 amount, address account) external; function withdraw(uint256 amount) external; // solhint-disable-next-line func-name-mixedcase function claim_rewards(address account) external; // solhint-disable-next-line func-name-mixedcase function staking_token() external returns (address); } interface IXKdkTokenUsage { function allocate(address userAddress, uint256 amount, bytes calldata data) external; function deallocate(address userAddress, uint256 amount, bytes calldata data) external; } interface IxKodiak { struct RedeemInfo { uint256 kdkAmount; // KDK amount to receive when vesting has ended uint256 xKodiakAmount; // xKDK amount to redeem uint256 endTime; IXKdkTokenUsage rewardsAddress; uint256 rewardsAllocation; // Share of redeeming xKDK to allocate to the Rewards Usage contract } function getUserRedeemsLength(address userAddress) external view returns (uint256); function redeem(uint256 xKdkAmount, uint256 duration) external; function finalizeRedeem(uint256 redeemIndex) external; function getUserRedeem( address userAddress, uint256 redeemIndex ) external view returns ( uint256 kdkAmount, uint256 xKdkAmount, uint256 endTime, address rewardsContract, uint256 rewardsAllocation ); } interface IKodiakV1RouterStaking { function addLiquidity( IKodiakVaultV1 pool, uint256 amount0Max, uint256 amount1Max, uint256 amount0Min, uint256 amount1Min, uint256 amountSharesMin, address receiver ) external returns (uint256 amount0, uint256 amount1, uint256 mintAmount); function addLiquidityETH( IKodiakVaultV1 pool, uint256 amount0Max, uint256 amount1Max, uint256 amount0Min, uint256 amount1Min, uint256 amountSharesMin, address receiver ) external payable returns (uint256 amount0, uint256 amount1, uint256 mintAmount); function addLiquidityAndStake( IGauge gauge, uint256 amount0Max, uint256 amount1Max, uint256 amount0Min, uint256 amount1Min, uint256 amountSharesMin, address receiver ) external returns (uint256 amount0, uint256 amount1, uint256 mintAmount); function addLiquidityETHAndStake( IGauge gauge, uint256 amount0Max, uint256 amount1Max, uint256 amount0Min, uint256 amount1Min, uint256 amountSharesMin, address receiver ) external payable returns (uint256 amount0, uint256 amount1, uint256 mintAmount); function removeLiquidity( IKodiakVaultV1 pool, uint256 burnAmount, uint256 amount0Min, uint256 amount1Min, address receiver ) external returns (uint256 amount0, uint256 amount1, uint128 liquidityBurned); function removeLiquidityETH( IKodiakVaultV1 pool, uint256 burnAmount, uint256 amount0Min, uint256 amount1Min, address payable receiver ) external returns (uint256 amount0, uint256 amount1, uint128 liquidityBurned); function removeLiquidityAndUnstake( IGauge gauge, uint256 burnAmount, uint256 amount0Min, uint256 amount1Min, address receiver ) external returns (uint256 amount0, uint256 amount1, uint128 liquidityBurned); function removeLiquidityETHAndUnstake( IGauge gauge, uint256 burnAmount, uint256 amount0Min, uint256 amount1Min, address payable receiver ) external returns (uint256 amount0, uint256 amount1, uint128 liquidityBurned); }
// 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 {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 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 { _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 { _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 { _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 { if (IERC20(tokenAddress).allowance(address(this), spenderAddress) == 0) { IERC20(tokenAddress).approve(spenderAddress, type(uint256).max); } } function _safeTransferFromTokens(address token, uint256 amount) internal 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, address recipient ) internal 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, ) = recipient.call{value: balance}(new bytes(0)); if (!success) revert ETHTransferFailed(); } else { IERC20(tokens[i]).safeTransfer(recipient, 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 returnedAssets Array of ReturnedAsset structs containing token addresses and amounts returned */ function _returnAsset(address token, address recipient) internal returns (ReturnedAsset[] memory returnedAssets) { address[] memory tokens = new address[](1); tokens[0] = token; returnedAssets = _returnAssets(tokens, recipient); } /** * @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 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 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":"governanceAddress","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":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":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":"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":[],"name":"lpRouter","outputs":[{"internalType":"contract ILpRouter","name":"","type":"address"}],"stateMutability":"view","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":"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":[],"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
60a06040523480156200001157600080fd5b50604051620022c9380380620022c98339810160408190526200003491620002f4565b600160005587878787878787876001600160a01b03881615806200005f57506001600160a01b038716155b806200007257506001600160a01b038616155b806200008557506001600160a01b038516155b806200009857506001600160a01b038416155b80620000ab57506001600160a01b038316155b15620000ca5760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b038a8116919091179091558716608081905260408051630d0e30db60e41b8152905163d0e30db0916000916004808301928492919082900301818388803b1580156200012a57600080fd5b505af11580156200013f573d6000803e3d6000fd5b5050608051604051632e1a7d4d60e01b8152600060048201526001600160a01b039091169350632e1a7d4d92506024019050600060405180830381600087803b1580156200018c57600080fd5b505af1158015620001a1573d6000803e3d6000fd5b5050600180546001600160a01b03808b1664010000000002600160201b600160c01b031990921691909117909155600380548983166001600160a01b031991821617909155600480549289169290911691909117905550506103e861ffff831611156200023457604051633c057d7b60e01b815261ffff831660048201526103e860248201526044015b60405180910390fd5b6103e861ffff821611156200026b57604051633c057d7b60e01b815261ffff821660048201526103e860248201526044016200022b565b600580546001600160a01b039094166001600160a01b0319909416939093179092556001805461ffff938416620100000263ffffffff199091169390921692909217179055506200039c9b505050505050505050505050565b80516001600160a01b0381168114620002dc57600080fd5b919050565b805161ffff81168114620002dc57600080fd5b600080600080600080600080610100898b0312156200031257600080fd5b6200031d89620002c4565b97506200032d60208a01620002c4565b96506200033d60408a01620002c4565b95506200034d60608a01620002c4565b94506200035d60808a01620002c4565b93506200036d60a08a01620002c4565b92506200037d60c08a01620002e1565b91506200038d60e08a01620002e1565b90509295985092959890939650565b608051611ed9620003f0600039600081816101490152818161040901528181610685015281816106f901528181610b9a015281816115c60152818161162c0152818161177c01526117c90152611ed96000f3fe6080604052600436106101395760003560e01c8063a863ff2f116100ab578063c31c9c071161006f578063c31c9c0714610379578063d55be8c614610399578063e74b981b146103af578063e9cbd822146103cf578063eb6d3a11146103f7578063f99e63871461042b57600080fd5b8063a863ff2f146102fe578063a89635bc1461031e578063ab033ea914610339578063afb44e3714610359578063bc063e1a146101f357600080fd5b80633c3b1ef6116100fd5780633c3b1ef61461024a578063412736571461025d578063469048401461027d5780635aa6e6751461029d5780638f0af424146102bd5780639739c03e146102dd57600080fd5b80630c8106dc1461017d57806315a29203146101b357806323af4e17146101d3578063257d9bb8146101f35780633218e83a1461021c57600080fd5b3661017857336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461017657610176611a9f565b005b600080fd5b34801561018957600080fd5b5060045461019d906001600160a01b031681565b6040516101aa9190611ab5565b60405180910390f35b3480156101bf57600080fd5b506101766101ce366004611ade565b61044b565b3480156101df57600080fd5b506101766101ee366004611ade565b6104d1565b3480156101ff57600080fd5b506102096103e881565b60405161ffff90911681526020016101aa565b34801561022857600080fd5b5061023c610237366004611afb565b610567565b6040516101aa929190611b9d565b61023c610258366004611bb6565b610634565b34801561026957600080fd5b50610176610278366004611ade565b6109c4565b34801561028957600080fd5b5060055461019d906001600160a01b031681565b3480156102a957600080fd5b5060025461019d906001600160a01b031681565b3480156102c957600080fd5b506101766102d8366004611bfc565b610a4a565b3480156102e957600080fd5b506001546102099062010000900461ffff1681565b34801561030a57600080fd5b5061023c610319366004611c20565b610b02565b34801561032a57600080fd5b506001546102099061ffff1681565b34801561034557600080fd5b50610176610354366004611ade565b610d65565b34801561036557600080fd5b50610176610374366004611bfc565b610de5565b34801561038557600080fd5b5060035461019d906001600160a01b031681565b3480156103a557600080fd5b5061020961271081565b3480156103bb57600080fd5b506101766103ca366004611ade565b610ea1565b3480156103db57600080fd5b5060015461019d9064010000000090046001600160a01b031681565b34801561040357600080fd5b5061019d7f000000000000000000000000000000000000000000000000000000000000000081565b34801561043757600080fd5b5061023c610446366004611afb565b610f27565b6002546001600160a01b0316331461047657604051632d5be4cb60e21b815260040160405180910390fd5b61047f81610ff9565b600480546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f82c52d8aa62200dfc997bdf1100b1c2ed614580941b2b8637d10b8ca0428eeec90600090a35050565b6002546001600160a01b031633146104fc57604051632d5be4cb60e21b815260040160405180910390fd5b61050581610ff9565b60018054640100000000600160c01b0319166401000000006001600160a01b03848116828102939093179384905560405192939190910416907f497b8419a37c8014b1a755ec707f25d11ae4bade591d379f9a4095f37edaf76e90600090a350565b600060606001600160a01b0383163014610588576105858585611023565b93505b6004546105a2906001600160a01b038781169116866111c3565b6004805460405163190a4d4960e01b81526001600160a01b039091169163190a4d49916105da918a918a918a918a9160069101611c8a565b6020604051808303816000875af11580156105f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061d9190611cbe565b91506106298533611220565b905094509492505050565b6000606061064061128c565b6001600160a01b038516610722576103e8341015610683576000346103e8604051630b722aef60e21b815260040161067a93929190611cd7565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156106de57600080fd5b505af11580156106f2573d6000803e3d6000fd5b50505050507f0000000000000000000000000000000000000000000000000000000000000000945034935061075a565b6103e884101561074d5784846103e8604051630b722aef60e21b815260040161067a93929190611cd7565b6107578585611023565b93505b60015460009061077090879061ffff16876112b6565b80925081965050506000859050866001600160a01b0316886001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e99190611cfc565b6001600160a01b03161461086957610864886001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610838573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085c9190611cfc565b888830610567565b935090505b6108e088828a6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d09190611cfc565b6001600160a01b03169190611311565b60405163bc157ac160e01b815260048101829052336024820152604481018690526001600160a01b0389169063bc157ac1906064016020604051808303816000875af1158015610934573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109589190611cbe565b9350876001600160a01b0316336001600160a01b03167f87640c2e40d67703e350e7d24d4e416e5c4f1e1550e1285b1bf667440d36bdcf89898589888a6040516109a796959493929190611d19565b60405180910390a350506109bb6001600055565b94509492505050565b6002546001600160a01b031633146109ef57604051632d5be4cb60e21b815260040160405180910390fd5b6109f881610ff9565b600380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f5c5b0bb5085481c320dc523e3b3f829eaa807936f615add0077fa213f345090e90600090a35050565b6002546001600160a01b03163314610a7557604051632d5be4cb60e21b815260040160405180910390fd5b6103e861ffff82161115610aaa57604051633c057d7b60e01b815261ffff821660048201526103e8602482015260440161067a565b6001805461ffff83811661ffff1983168117909355604080519190921680825260208201939093527fcd5c26e400cb366bdac1d1cbdec4b428f15bc14a133ecbda85bc6f11f7acb9f191015b60405180910390a15050565b60006060610b0e61128c565b604051635d043b2960e11b8152600481018690523060248201523360448201526000906001600160a01b0388169063ba087652906064016020604051808303816000875af1158015610b64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b889190611cbe565b90506001600160a01b038516610bbc577f000000000000000000000000000000000000000000000000000000000000000094505b846001600160a01b0316876001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c289190611cfc565b6001600160a01b031603610c3e57809250610cb1565b610cab876001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca39190611cfc565b868330610f27565b90935091505b6000610cce86600160029054906101000a900461ffff16866112b6565b9094509050610cdd8633611220565b5084841015610d1857604051632752fb4960e11b81526001600160a01b0387166004820152602481018590526044810186905260640161067a565b876001600160a01b0316336001600160a01b03167f0bc6c5ccdba0b566b3adbb7c24c419a1b872218cd487d145a4e4eb70b2c8bfb38887868c878a6040516109a796959493929190611d19565b6002546001600160a01b03163314610d9057604051632d5be4cb60e21b815260040160405180910390fd5b610d9981610ff9565b600280546001600160a01b0319166001600160a01b03831690811790915560405181907f3aaaebeb4821d6a7e5c77ece53cff0afcc56c82add2c978dbbb7f73e84cbcfd290600090a350565b6002546001600160a01b03163314610e1057604051632d5be4cb60e21b815260040160405180910390fd5b6103e861ffff82161115610e4557604051633c057d7b60e01b815261ffff821660048201526103e8602482015260440161067a565b6001805461ffff8381166201000081810263ffff00001985161790945560408051949093049091168084526020840191909152917febcac71ae552a15ae4d23c933603e1a71f47ff8371bdd98194f037156b73a7199101610af6565b6002546001600160a01b03163314610ecc57604051632d5be4cb60e21b815260040160405180910390fd5b610ed581610ff9565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f0bc21fe5c3ab742ff1d15b5c4477ffbacf1167e618228078fa625edebe7f331d90600090a35050565b600060606001600160a01b0383163014610f4857610f458685611023565b93505b600454610f62906001600160a01b038881169116866111c3565b6004805460405163616a3dbd60e11b81526001600160a01b039091169163c2d47b7a91610f9a918a91899130918c9160069101611d5e565b6020604051808303816000875af1158015610fb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fdd9190611cbe565b91506001600160a01b03831630146109bb576106298584611220565b6001600160a01b0381166110205760405163d92e233d60e01b815260040160405180910390fd5b50565b604051636eb1769f60e11b815233600482015230602482015260009082906001600160a01b0385169063dd62ed3e90604401602060405180830381865afa158015611072573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110969190611cbe565b10156110b5576040516332da96a360e01b815260040160405180910390fd5b6040516370a0823160e01b81526000906001600160a01b038516906370a08231906110e4903090600401611ab5565b602060405180830381865afa158015611101573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111259190611cbe565b905061113c6001600160a01b0385163330866113a9565b6040516370a0823160e01b81526000906001600160a01b038616906370a082319061116b903090600401611ab5565b602060405180830381865afa158015611188573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ac9190611cbe565b90506111b88282611da8565b925050505b92915050565b61121b83846001600160a01b031663a9059cbb85856040516024016111e9929190611dbb565b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506113e2565b505050565b6040805160018082528183019092526060916000919060208083019080368337019050509050838160008151811061125a5761125a611dea565b60200260200101906001600160a01b031690816001600160a01b031681525050611284818461143c565b949350505050565b6002600054036112af57604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b60008061ffff841615611306576127106112d461ffff861685611e00565b6112de9190611e17565b6005549091506112f99086906001600160a01b031683611774565b6113038184611da8565b92505b829150935093915050565b6000836001600160a01b031663095ea7b38484604051602401611335929190611dbb565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050905061136e84826118ce565b6113a35761139984856001600160a01b031663095ea7b38660006040516024016111e9929190611dbb565b6113a384826113e2565b50505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526113a39186918216906323b872dd906084016111e9565b60006113f76001600160a01b03841683611971565b9050805160001415801561141c57508080602001905181019061141a9190611e39565b155b1561121b5782604051635274afe760e01b815260040161067a9190611ab5565b60606000835167ffffffffffffffff81111561145a5761145a611dd4565b60405190808252806020026020018201604052801561149f57816020015b60408051808201909152600080825260208201528152602001906001900390816114785790505b50915060005b845181101561176c5760006001600160a01b03168582815181106114cb576114cb611dea565b60200260200101516001600160a01b0316031561175a578481815181106114f4576114f4611dea565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016115279190611ab5565b602060405180830381865afa158015611544573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115689190611cbe565b9150604051806040016040528086838151811061158757611587611dea565b60200260200101516001600160a01b03168152602001838152508382815181106115b3576115b3611dea565b6020908102919091010152811561175a577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031685828151811061160057611600611dea565b60200260200101516001600160a01b03160361172357604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561167857600080fd5b505af115801561168c573d6000803e3d6000fd5b5050604080516000808252602082019283905293506001600160a01b038816925085916116b99190611e5b565b60006040518083038185875af1925050503d80600081146116f6576040519150601f19603f3d011682016040523d82523d6000602084013e6116fb565b606091505b505090508061171d5760405163b12d13eb60e01b815260040160405180910390fd5b5061175a565b61175a848387848151811061173a5761173a611dea565b60200260200101516001600160a01b03166111c39092919063ffffffff16565b8061176481611e8a565b9150506114a5565b505092915050565b801561121b577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316036118ba57604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561181557600080fd5b505af1158015611829573d6000803e3d6000fd5b5050604080516000808252602082019283905293506001600160a01b038616925084916118569190611e5b565b60006040518083038185875af1925050503d8060008114611893576040519150601f19603f3d011682016040523d82523d6000602084013e611898565b606091505b50509050806113a35760405163b12d13eb60e01b815260040160405180910390fd5b61121b6001600160a01b03841683836111c3565b6000806000846001600160a01b0316846040516118eb9190611e5b565b6000604051808303816000865af19150503d8060008114611928576040519150601f19603f3d011682016040523d82523d6000602084013e61192d565b606091505b50915091508180156119575750805115806119575750808060200190518101906119579190611e39565b80156111b85750505050506001600160a01b03163b151590565b606061197f83836000611986565b9392505050565b6060814710156119ab573060405163cd78605960e01b815260040161067a9190611ab5565b600080856001600160a01b031684866040516119c79190611e5b565b60006040518083038185875af1925050503d8060008114611a04576040519150601f19603f3d011682016040523d82523d6000602084013e611a09565b606091505b5091509150611a19868383611a23565b9695505050505050565b606082611a3857611a3382611a76565b61197f565b8151158015611a4f57506001600160a01b0384163b155b15611a6f5783604051639996b31560e01b815260040161067a9190611ab5565b508061197f565b805115611a865780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b600052600160045260246000fd5b6001600160a01b0391909116815260200190565b6001600160a01b038116811461102057600080fd5b600060208284031215611af057600080fd5b813561197f81611ac9565b60008060008060808587031215611b1157600080fd5b8435611b1c81611ac9565b93506020850135611b2c81611ac9565b9250604085013591506060850135611b4381611ac9565b939692955090935050565b600081518084526020808501945080840160005b83811015611b9257815180516001600160a01b031688528301518388015260409096019590820190600101611b62565b509495945050505050565b8281526040602082015260006112846040830184611b4e565b60008060008060808587031215611bcc57600080fd5b8435611bd781611ac9565b93506020850135611be781611ac9565b93969395505050506040820135916060013590565b600060208284031215611c0e57600080fd5b813561ffff8116811461197f57600080fd5b60008060008060808587031215611c3657600080fd5b8435611c4181611ac9565b9350602085013592506040850135611c5881611ac9565b9396929550929360600135925050565b600a8110611c8657634e487b7160e01b600052602160045260246000fd5b9052565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a08101611a196080830184611c68565b600060208284031215611cd057600080fd5b5051919050565b6001600160a01b03939093168352602083019190915261ffff16604082015260600190565b600060208284031215611d0e57600080fd5b815161197f81611ac9565b60018060a01b038716815285602082015284604082015283606082015282608082015260c060a08201526000611d5260c0830184611b4e565b98975050505050505050565b6001600160a01b0386811682526020820186905284811660408301528316606082015260a08101611a196080830184611c68565b634e487b7160e01b600052601160045260246000fd5b818103818111156111bd576111bd611d92565b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b80820281158282048414176111bd576111bd611d92565b600082611e3457634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215611e4b57600080fd5b8151801515811461197f57600080fd5b6000825160005b81811015611e7c5760208186018101518583015201611e62565b506000920191825250919050565b600060018201611e9c57611e9c611d92565b506001019056fea2646970667358221220a3aa4be3533f21a6e26311cd954b0f508c1871c08deacb9e90b2a2207ad83c0e64736f6c6343000814003300000000000000000000000062137cec7754aa3f530c98866a86dba36d2687170000000000000000000000006969696969696969696969696969696969696969000000000000000000000000fcbd14dc51f0a4d49d5e53c2e0950e0bc26d0dce000000000000000000000000b8ba8721a5bfcf828a46c5f839c559988d8d5ead000000000000000000000000609e7b64a2970157789ae6e396de1b0b8e393b050000000000000000000000001cfe31bfa1ac9b28588c91bb4300a1ed032f069f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106101395760003560e01c8063a863ff2f116100ab578063c31c9c071161006f578063c31c9c0714610379578063d55be8c614610399578063e74b981b146103af578063e9cbd822146103cf578063eb6d3a11146103f7578063f99e63871461042b57600080fd5b8063a863ff2f146102fe578063a89635bc1461031e578063ab033ea914610339578063afb44e3714610359578063bc063e1a146101f357600080fd5b80633c3b1ef6116100fd5780633c3b1ef61461024a578063412736571461025d578063469048401461027d5780635aa6e6751461029d5780638f0af424146102bd5780639739c03e146102dd57600080fd5b80630c8106dc1461017d57806315a29203146101b357806323af4e17146101d3578063257d9bb8146101f35780633218e83a1461021c57600080fd5b3661017857336001600160a01b037f0000000000000000000000006969696969696969696969696969696969696969161461017657610176611a9f565b005b600080fd5b34801561018957600080fd5b5060045461019d906001600160a01b031681565b6040516101aa9190611ab5565b60405180910390f35b3480156101bf57600080fd5b506101766101ce366004611ade565b61044b565b3480156101df57600080fd5b506101766101ee366004611ade565b6104d1565b3480156101ff57600080fd5b506102096103e881565b60405161ffff90911681526020016101aa565b34801561022857600080fd5b5061023c610237366004611afb565b610567565b6040516101aa929190611b9d565b61023c610258366004611bb6565b610634565b34801561026957600080fd5b50610176610278366004611ade565b6109c4565b34801561028957600080fd5b5060055461019d906001600160a01b031681565b3480156102a957600080fd5b5060025461019d906001600160a01b031681565b3480156102c957600080fd5b506101766102d8366004611bfc565b610a4a565b3480156102e957600080fd5b506001546102099062010000900461ffff1681565b34801561030a57600080fd5b5061023c610319366004611c20565b610b02565b34801561032a57600080fd5b506001546102099061ffff1681565b34801561034557600080fd5b50610176610354366004611ade565b610d65565b34801561036557600080fd5b50610176610374366004611bfc565b610de5565b34801561038557600080fd5b5060035461019d906001600160a01b031681565b3480156103a557600080fd5b5061020961271081565b3480156103bb57600080fd5b506101766103ca366004611ade565b610ea1565b3480156103db57600080fd5b5060015461019d9064010000000090046001600160a01b031681565b34801561040357600080fd5b5061019d7f000000000000000000000000696969696969696969696969696969696969696981565b34801561043757600080fd5b5061023c610446366004611afb565b610f27565b6002546001600160a01b0316331461047657604051632d5be4cb60e21b815260040160405180910390fd5b61047f81610ff9565b600480546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f82c52d8aa62200dfc997bdf1100b1c2ed614580941b2b8637d10b8ca0428eeec90600090a35050565b6002546001600160a01b031633146104fc57604051632d5be4cb60e21b815260040160405180910390fd5b61050581610ff9565b60018054640100000000600160c01b0319166401000000006001600160a01b03848116828102939093179384905560405192939190910416907f497b8419a37c8014b1a755ec707f25d11ae4bade591d379f9a4095f37edaf76e90600090a350565b600060606001600160a01b0383163014610588576105858585611023565b93505b6004546105a2906001600160a01b038781169116866111c3565b6004805460405163190a4d4960e01b81526001600160a01b039091169163190a4d49916105da918a918a918a918a9160069101611c8a565b6020604051808303816000875af11580156105f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061d9190611cbe565b91506106298533611220565b905094509492505050565b6000606061064061128c565b6001600160a01b038516610722576103e8341015610683576000346103e8604051630b722aef60e21b815260040161067a93929190611cd7565b60405180910390fd5b7f00000000000000000000000069696969696969696969696969696969696969696001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156106de57600080fd5b505af11580156106f2573d6000803e3d6000fd5b50505050507f0000000000000000000000006969696969696969696969696969696969696969945034935061075a565b6103e884101561074d5784846103e8604051630b722aef60e21b815260040161067a93929190611cd7565b6107578585611023565b93505b60015460009061077090879061ffff16876112b6565b80925081965050506000859050866001600160a01b0316886001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e99190611cfc565b6001600160a01b03161461086957610864886001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610838573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085c9190611cfc565b888830610567565b935090505b6108e088828a6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108d09190611cfc565b6001600160a01b03169190611311565b60405163bc157ac160e01b815260048101829052336024820152604481018690526001600160a01b0389169063bc157ac1906064016020604051808303816000875af1158015610934573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109589190611cbe565b9350876001600160a01b0316336001600160a01b03167f87640c2e40d67703e350e7d24d4e416e5c4f1e1550e1285b1bf667440d36bdcf89898589888a6040516109a796959493929190611d19565b60405180910390a350506109bb6001600055565b94509492505050565b6002546001600160a01b031633146109ef57604051632d5be4cb60e21b815260040160405180910390fd5b6109f881610ff9565b600380546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f5c5b0bb5085481c320dc523e3b3f829eaa807936f615add0077fa213f345090e90600090a35050565b6002546001600160a01b03163314610a7557604051632d5be4cb60e21b815260040160405180910390fd5b6103e861ffff82161115610aaa57604051633c057d7b60e01b815261ffff821660048201526103e8602482015260440161067a565b6001805461ffff83811661ffff1983168117909355604080519190921680825260208201939093527fcd5c26e400cb366bdac1d1cbdec4b428f15bc14a133ecbda85bc6f11f7acb9f191015b60405180910390a15050565b60006060610b0e61128c565b604051635d043b2960e11b8152600481018690523060248201523360448201526000906001600160a01b0388169063ba087652906064016020604051808303816000875af1158015610b64573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b889190611cbe565b90506001600160a01b038516610bbc577f000000000000000000000000696969696969696969696969696969696969696994505b846001600160a01b0316876001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c289190611cfc565b6001600160a01b031603610c3e57809250610cb1565b610cab876001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c7f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ca39190611cfc565b868330610f27565b90935091505b6000610cce86600160029054906101000a900461ffff16866112b6565b9094509050610cdd8633611220565b5084841015610d1857604051632752fb4960e11b81526001600160a01b0387166004820152602481018590526044810186905260640161067a565b876001600160a01b0316336001600160a01b03167f0bc6c5ccdba0b566b3adbb7c24c419a1b872218cd487d145a4e4eb70b2c8bfb38887868c878a6040516109a796959493929190611d19565b6002546001600160a01b03163314610d9057604051632d5be4cb60e21b815260040160405180910390fd5b610d9981610ff9565b600280546001600160a01b0319166001600160a01b03831690811790915560405181907f3aaaebeb4821d6a7e5c77ece53cff0afcc56c82add2c978dbbb7f73e84cbcfd290600090a350565b6002546001600160a01b03163314610e1057604051632d5be4cb60e21b815260040160405180910390fd5b6103e861ffff82161115610e4557604051633c057d7b60e01b815261ffff821660048201526103e8602482015260440161067a565b6001805461ffff8381166201000081810263ffff00001985161790945560408051949093049091168084526020840191909152917febcac71ae552a15ae4d23c933603e1a71f47ff8371bdd98194f037156b73a7199101610af6565b6002546001600160a01b03163314610ecc57604051632d5be4cb60e21b815260040160405180910390fd5b610ed581610ff9565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f0bc21fe5c3ab742ff1d15b5c4477ffbacf1167e618228078fa625edebe7f331d90600090a35050565b600060606001600160a01b0383163014610f4857610f458685611023565b93505b600454610f62906001600160a01b038881169116866111c3565b6004805460405163616a3dbd60e11b81526001600160a01b039091169163c2d47b7a91610f9a918a91899130918c9160069101611d5e565b6020604051808303816000875af1158015610fb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fdd9190611cbe565b91506001600160a01b03831630146109bb576106298584611220565b6001600160a01b0381166110205760405163d92e233d60e01b815260040160405180910390fd5b50565b604051636eb1769f60e11b815233600482015230602482015260009082906001600160a01b0385169063dd62ed3e90604401602060405180830381865afa158015611072573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110969190611cbe565b10156110b5576040516332da96a360e01b815260040160405180910390fd5b6040516370a0823160e01b81526000906001600160a01b038516906370a08231906110e4903090600401611ab5565b602060405180830381865afa158015611101573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111259190611cbe565b905061113c6001600160a01b0385163330866113a9565b6040516370a0823160e01b81526000906001600160a01b038616906370a082319061116b903090600401611ab5565b602060405180830381865afa158015611188573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ac9190611cbe565b90506111b88282611da8565b925050505b92915050565b61121b83846001600160a01b031663a9059cbb85856040516024016111e9929190611dbb565b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506113e2565b505050565b6040805160018082528183019092526060916000919060208083019080368337019050509050838160008151811061125a5761125a611dea565b60200260200101906001600160a01b031690816001600160a01b031681525050611284818461143c565b949350505050565b6002600054036112af57604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b60008061ffff841615611306576127106112d461ffff861685611e00565b6112de9190611e17565b6005549091506112f99086906001600160a01b031683611774565b6113038184611da8565b92505b829150935093915050565b6000836001600160a01b031663095ea7b38484604051602401611335929190611dbb565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050905061136e84826118ce565b6113a35761139984856001600160a01b031663095ea7b38660006040516024016111e9929190611dbb565b6113a384826113e2565b50505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526113a39186918216906323b872dd906084016111e9565b60006113f76001600160a01b03841683611971565b9050805160001415801561141c57508080602001905181019061141a9190611e39565b155b1561121b5782604051635274afe760e01b815260040161067a9190611ab5565b60606000835167ffffffffffffffff81111561145a5761145a611dd4565b60405190808252806020026020018201604052801561149f57816020015b60408051808201909152600080825260208201528152602001906001900390816114785790505b50915060005b845181101561176c5760006001600160a01b03168582815181106114cb576114cb611dea565b60200260200101516001600160a01b0316031561175a578481815181106114f4576114f4611dea565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b81526004016115279190611ab5565b602060405180830381865afa158015611544573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115689190611cbe565b9150604051806040016040528086838151811061158757611587611dea565b60200260200101516001600160a01b03168152602001838152508382815181106115b3576115b3611dea565b6020908102919091010152811561175a577f00000000000000000000000069696969696969696969696969696969696969696001600160a01b031685828151811061160057611600611dea565b60200260200101516001600160a01b03160361172357604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000069696969696969696969696969696969696969696001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561167857600080fd5b505af115801561168c573d6000803e3d6000fd5b5050604080516000808252602082019283905293506001600160a01b038816925085916116b99190611e5b565b60006040518083038185875af1925050503d80600081146116f6576040519150601f19603f3d011682016040523d82523d6000602084013e6116fb565b606091505b505090508061171d5760405163b12d13eb60e01b815260040160405180910390fd5b5061175a565b61175a848387848151811061173a5761173a611dea565b60200260200101516001600160a01b03166111c39092919063ffffffff16565b8061176481611e8a565b9150506114a5565b505092915050565b801561121b577f00000000000000000000000069696969696969696969696969696969696969696001600160a01b0316836001600160a01b0316036118ba57604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000069696969696969696969696969696969696969696001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561181557600080fd5b505af1158015611829573d6000803e3d6000fd5b5050604080516000808252602082019283905293506001600160a01b038616925084916118569190611e5b565b60006040518083038185875af1925050503d8060008114611893576040519150601f19603f3d011682016040523d82523d6000602084013e611898565b606091505b50509050806113a35760405163b12d13eb60e01b815260040160405180910390fd5b61121b6001600160a01b03841683836111c3565b6000806000846001600160a01b0316846040516118eb9190611e5b565b6000604051808303816000865af19150503d8060008114611928576040519150601f19603f3d011682016040523d82523d6000602084013e61192d565b606091505b50915091508180156119575750805115806119575750808060200190518101906119579190611e39565b80156111b85750505050506001600160a01b03163b151590565b606061197f83836000611986565b9392505050565b6060814710156119ab573060405163cd78605960e01b815260040161067a9190611ab5565b600080856001600160a01b031684866040516119c79190611e5b565b60006040518083038185875af1925050503d8060008114611a04576040519150601f19603f3d011682016040523d82523d6000602084013e611a09565b606091505b5091509150611a19868383611a23565b9695505050505050565b606082611a3857611a3382611a76565b61197f565b8151158015611a4f57506001600160a01b0384163b155b15611a6f5783604051639996b31560e01b815260040161067a9190611ab5565b508061197f565b805115611a865780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b600052600160045260246000fd5b6001600160a01b0391909116815260200190565b6001600160a01b038116811461102057600080fd5b600060208284031215611af057600080fd5b813561197f81611ac9565b60008060008060808587031215611b1157600080fd5b8435611b1c81611ac9565b93506020850135611b2c81611ac9565b9250604085013591506060850135611b4381611ac9565b939692955090935050565b600081518084526020808501945080840160005b83811015611b9257815180516001600160a01b031688528301518388015260409096019590820190600101611b62565b509495945050505050565b8281526040602082015260006112846040830184611b4e565b60008060008060808587031215611bcc57600080fd5b8435611bd781611ac9565b93506020850135611be781611ac9565b93969395505050506040820135916060013590565b600060208284031215611c0e57600080fd5b813561ffff8116811461197f57600080fd5b60008060008060808587031215611c3657600080fd5b8435611c4181611ac9565b9350602085013592506040850135611c5881611ac9565b9396929550929360600135925050565b600a8110611c8657634e487b7160e01b600052602160045260246000fd5b9052565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a08101611a196080830184611c68565b600060208284031215611cd057600080fd5b5051919050565b6001600160a01b03939093168352602083019190915261ffff16604082015260600190565b600060208284031215611d0e57600080fd5b815161197f81611ac9565b60018060a01b038716815285602082015284604082015283606082015282608082015260c060a08201526000611d5260c0830184611b4e565b98975050505050505050565b6001600160a01b0386811682526020820186905284811660408301528316606082015260a08101611a196080830184611c68565b634e487b7160e01b600052601160045260246000fd5b818103818111156111bd576111bd611d92565b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b80820281158282048414176111bd576111bd611d92565b600082611e3457634e487b7160e01b600052601260045260246000fd5b500490565b600060208284031215611e4b57600080fd5b8151801515811461197f57600080fd5b6000825160005b81811015611e7c5760208186018101518583015201611e62565b506000920191825250919050565b600060018201611e9c57611e9c611d92565b506001019056fea2646970667358221220a3aa4be3533f21a6e26311cd954b0f508c1871c08deacb9e90b2a2207ad83c0e64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000062137cec7754aa3f530c98866a86dba36d2687170000000000000000000000006969696969696969696969696969696969696969000000000000000000000000fcbd14dc51f0a4d49d5e53c2e0950e0bc26d0dce000000000000000000000000b8ba8721a5bfcf828a46c5f839c559988d8d5ead000000000000000000000000609e7b64a2970157789ae6e396de1b0b8e393b050000000000000000000000001cfe31bfa1ac9b28588c91bb4300a1ed032f069f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : governanceAddress (address): 0x62137cEc7754aA3f530c98866a86dba36d268717
Arg [1] : wrappedNative (address): 0x6969696969696969696969696969696969696969
Arg [2] : stableCoin (address): 0xFCBD14DC51f0A4d49d5E53C2E0950e0bC26d0Dce
Arg [3] : swapRouter (address): 0xb8bA8721A5bFcF828A46C5F839c559988d8d5eaD
Arg [4] : lpRouter (address): 0x609E7b64a2970157789AE6E396de1b0b8E393b05
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] : 000000000000000000000000b8ba8721a5bfcf828a46c5f839c559988d8d5ead
Arg [4] : 000000000000000000000000609e7b64a2970157789ae6e396de1b0b8e393b05
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.