Overview
BERA Balance
BERA Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 363 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Zap In | 3705827 | 8 days ago | IN | 0.00000043 BERA | 0 | ||||
Zap In | 3705770 | 8 days ago | IN | 0 BERA | 0 | ||||
Zap Out | 3704372 | 8 days ago | IN | 0 BERA | 0.00000062 | ||||
Zap In | 3700552 | 8 days ago | IN | 0 BERA | 0.00000094 | ||||
Zap In | 3697544 | 8 days ago | IN | 17 BERA | 0.00006719 | ||||
Zap In | 3683847 | 9 days ago | IN | 0 BERA | 0.00000023 | ||||
Zap In | 3683482 | 9 days ago | IN | 0 BERA | 0.00000026 | ||||
Zap Out | 3675514 | 9 days ago | IN | 0 BERA | 0.00000068 | ||||
Zap In | 3673359 | 9 days ago | IN | 0.00000077 BERA | 0 | ||||
Zap In | 3647113 | 10 days ago | IN | 29.33435453 BERA | 0.00000045 | ||||
Zap Out | 3638277 | 10 days ago | IN | 0 BERA | 0 | ||||
Zap In | 3638260 | 10 days ago | IN | 0 BERA | 0 | ||||
Zap Out | 3638208 | 10 days ago | IN | 0 BERA | 0 | ||||
Zap Out | 3623425 | 10 days ago | IN | 0 BERA | 0 | ||||
Zap In | 3623100 | 10 days ago | IN | 0 BERA | 0.00000001 | ||||
Zap In | 3618970 | 10 days ago | IN | 0.00000172 BERA | 0.00000021 | ||||
Zap In | 3618486 | 10 days ago | IN | 0 BERA | 0.00000036 | ||||
Zap Out | 3578096 | 11 days ago | IN | 0 BERA | 0.00000001 | ||||
Zap In | 3578025 | 11 days ago | IN | 0.23881396 BERA | 0 | ||||
Zap In | 3574780 | 11 days ago | IN | 0 BERA | 0 | ||||
Zap In | 3565361 | 11 days ago | IN | 0.49164844 BERA | 0 | ||||
Zap Out | 3541890 | 12 days ago | IN | 0 BERA | 0.0000006 | ||||
Zap Out | 3532482 | 12 days ago | IN | 0 BERA | 0.00000001 | ||||
Zap Out | 3520739 | 12 days ago | IN | 0 BERA | 0.0000005 | ||||
Zap Out | 3509791 | 13 days ago | IN | 0 BERA | 0.00000752 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
3705827 | 8 days ago | 0.00000043 BERA | ||||
3704372 | 8 days ago | 0.49538346 BERA | ||||
3704372 | 8 days ago | 0.49538346 BERA | ||||
3697544 | 8 days ago | 17 BERA | ||||
3675514 | 9 days ago | 22.45391983 BERA | ||||
3675514 | 9 days ago | 22.45391983 BERA | ||||
3673359 | 9 days ago | 0.00000077 BERA | ||||
3647113 | 10 days ago | 29.33435453 BERA | ||||
3638277 | 10 days ago | 0.26662868 BERA | ||||
3638277 | 10 days ago | 0.26662868 BERA | ||||
3623425 | 10 days ago | 230.56651858 BERA | ||||
3623425 | 10 days ago | 230.56651858 BERA | ||||
3618970 | 10 days ago | 0.00000172 BERA | ||||
3578096 | 11 days ago | 0.23875152 BERA | ||||
3578096 | 11 days ago | 0.23875152 BERA | ||||
3578025 | 11 days ago | 0.23881396 BERA | ||||
3565361 | 11 days ago | 0.49164844 BERA | ||||
3541890 | 12 days ago | 65.3215437 BERA | ||||
3541890 | 12 days ago | 65.3215437 BERA | ||||
3532482 | 12 days ago | 1.22310769 BERA | ||||
3532482 | 12 days ago | 1.22310769 BERA | ||||
3520739 | 12 days ago | 13.23550155 BERA | ||||
3520739 | 12 days ago | 13.23550155 BERA | ||||
3509791 | 13 days ago | 60.61660767 BERA | ||||
3509791 | 13 days ago | 60.61660767 BERA |
Loading...
Loading
Contract Name:
BurrBearZapper
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 100 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {ZapperBase} from "./ZapperBase.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {IDexType} from "../interfaces/IDexType.sol"; import {ILpRouter} from "../interfaces/ILpRouter.sol"; import {SphereXProtected} from "@spherex-xyz/contracts/src/SphereXProtected.sol"; /** * @title BurrBearZapper * @notice A zapper contract that enables single-token deposits and withdrawals for BurrBear Strategy */ contract BurrBearZapper is ZapperBase { using SafeERC20 for IERC20; constructor( address devAddress, address wrappedNative, address stablecoin, address swapRouter, address lpRouter, address feeRecipient, uint16 zapInFee, uint16 zapOutFee ) ZapperBase(devAddress, wrappedNative, stablecoin, swapRouter, lpRouter, feeRecipient, zapInFee, zapOutFee) {} /** * @notice Converts input token amount to vault's asset * @param asset The vault's asset * @param tokenIn The token being deposited * @param tokenInAmount The amount of tokens being deposited * @param recipient The address to receive the asset * @return tokenOutAmount Amount of asset received * @return returnedAssets Array of remaining token balances to be returned to the user */ function swapToAssets( address asset, address tokenIn, uint256 tokenInAmount, address recipient ) public override sphereXGuardPublic(0x07c1e85d, 0x3218e83a) returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets) { // Transfer tokens if needed if (recipient != address(this)) { tokenInAmount = _safeTransferFromTokens(tokenIn, tokenInAmount); } return _swapToAssetsLp(asset, tokenIn, tokenInAmount, recipient); } /** * @notice Converts input token amount to vault's asset * @param asset The vault's asset * @param tokenIn The token being deposited * @param tokenInAmount The amount of tokens being deposited * @param recipient The address to receive the asset * @return tokenOutAmount Amount of asset received * @return returnedAssets Array of remaining token balances to be returned to the user */ function _swapToAssetsLp( address asset, address tokenIn, uint256 tokenInAmount, address recipient ) internal returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets) { // Add liquidity IERC20(tokenIn).safeTransfer(address(lpRouter), tokenInAmount); tokenOutAmount = lpRouter.addLiquidity(asset, tokenIn, tokenInAmount, recipient, IDexType.DexType.BEX); // Return assets address[] memory tokens = new address[](1); tokens[0] = tokenIn; returnedAssets = _returnAssets(tokens); } /** * @notice Converts vault's asset to output token * @param asset The vault's asset * @param tokenOut The token the user wants to receive * @param assetsInAmount The amount of LP tokens being withdrawn * @param recipient The address to receive the output token * @return tokenOutAmount The amount of desired tokens received * @return returnedAssets Array of remaining token balances to be returned to the user */ function swapFromAssets( address asset, address tokenOut, uint256 assetsInAmount, address recipient ) public override sphereXGuardPublic(0x362279f7, 0xf99e6387) returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets) { // Transfer tokens if needed if (recipient != address(this)) { assetsInAmount = _safeTransferFromTokens(asset, assetsInAmount); } return _swapFromAssetsLp(asset, tokenOut, assetsInAmount, recipient); } /** * @notice Converts vault's asset to output token * @param asset The vault's asset * @param tokenOut The token the user wants to receive * @param assetsInAmount The amount of LP tokens being withdrawn * @param recipient The address to receive the output token * @return tokenOutAmount The amount of desired tokens received * @return returnedAssets Array of remaining token balances to be returned to the user */ function _swapFromAssetsLp( address asset, address tokenOut, uint256 assetsInAmount, address recipient ) internal returns (uint256 tokenOutAmount, ReturnedAsset[] memory) { // Remove liquidity IERC20(asset).safeTransfer(address(lpRouter), assetsInAmount); tokenOutAmount = lpRouter.removeLiquidity(asset, assetsInAmount, recipient, tokenOut, IDexType.DexType.BEX); if (recipient != address(this)) { _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: UNLICENSED // (c) SphereX 2023 Terms&Conditions pragma solidity ^0.8.0; /** * @title Interface for SphereXEngine - definitions of core functionality * @author SphereX Technologies ltd * @notice This interface is imported by SphereXProtected, so that SphereXProtected can call functions from SphereXEngine * @dev Full docs of these functions can be found in SphereXEngine */ interface ISphereXEngine { function sphereXValidatePre(int256 num, address sender, bytes calldata data) external returns (bytes32[] memory); function sphereXValidatePost( int256 num, uint256 gas, bytes32[] calldata valuesBefore, bytes32[] calldata valuesAfter ) external; function sphereXValidateInternalPre(int256 num) external returns (bytes32[] memory); function sphereXValidateInternalPost( int256 num, uint256 gas, bytes32[] calldata valuesBefore, bytes32[] calldata valuesAfter ) external; function addAllowedSenderOnChain(address sender) external; /** * This function is taken as is from OZ IERC165, we don't inherit from OZ * to avoid collisions with the customer OZ version. * * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } /** * @dev this struct is used to reduce the stack usage of the modifiers. */ struct ModifierLocals { bytes32[] storageSlots; bytes32[] valuesBefore; uint256 gas; address engine; }
// SPDX-License-Identifier: UNLICENSED // (c) SphereX 2023 Terms&Conditions pragma solidity ^0.8.0; import {ISphereXEngine, ModifierLocals} from "./ISphereXEngine.sol"; /** * @title SphereX base Customer contract template */ /// @custom:oz-upgrades-unsafe-allow constructor abstract contract SphereXConfiguration { /** * @dev we would like to avoid occupying storage slots * @dev to easily incorporate with existing contracts */ bytes32 private constant SPHEREX_ADMIN_STORAGE_SLOT = bytes32(uint256(keccak256("eip1967.spherex.spherex")) - 1); bytes32 private constant SPHEREX_PENDING_ADMIN_STORAGE_SLOT = bytes32(uint256(keccak256("eip1967.spherex.pending")) - 1); bytes32 private constant SPHEREX_OPERATOR_STORAGE_SLOT = bytes32(uint256(keccak256("eip1967.spherex.operator")) - 1); bytes32 private constant SPHEREX_ENGINE_STORAGE_SLOT = bytes32(uint256(keccak256("eip1967.spherex.spherex_engine")) - 1); event ChangedSpherexOperator(address oldSphereXAdmin, address newSphereXAdmin); event ChangedSpherexEngineAddress(address oldEngineAddress, address newEngineAddress); event SpherexAdminTransferStarted(address currentAdmin, address pendingAdmin); event SpherexAdminTransferCompleted(address oldAdmin, address newAdmin); event NewAllowedSenderOnchain(address sender); /** * @dev used when the client doesn't use a proxy */ constructor(address admin, address operator, address engine) { __SphereXProtectedBase_init(admin, operator, engine); } /** * @dev used when the client uses a proxy - should be called by the inhereter initialization */ function __SphereXProtectedBase_init(address admin, address operator, address engine) internal virtual { _setAddress(SPHEREX_ADMIN_STORAGE_SLOT, admin); emit SpherexAdminTransferCompleted(address(0), admin); _setAddress(SPHEREX_OPERATOR_STORAGE_SLOT, operator); emit ChangedSpherexOperator(address(0), operator); _checkSphereXEngine(engine); _setAddress(SPHEREX_ENGINE_STORAGE_SLOT, engine); emit ChangedSpherexEngineAddress(address(0), engine); } // ============ Helper functions ============ function _sphereXEngine() internal view returns (ISphereXEngine) { return ISphereXEngine(_getAddress(SPHEREX_ENGINE_STORAGE_SLOT)); } /** * Stores a new address in an arbitrary slot * @param slot where to store the address * @param newAddress address to store in given slot */ function _setAddress(bytes32 slot, address newAddress) internal { // solhint-disable-next-line no-inline-assembly // slither-disable-next-line assembly assembly { sstore(slot, newAddress) } } /** * Returns an address from an arbitrary slot. * @param slot to read an address from */ function _getAddress(bytes32 slot) internal view returns (address addr) { // solhint-disable-next-line no-inline-assembly // slither-disable-next-line assembly assembly { addr := sload(slot) } } // ============ Local modifiers ============ modifier onlySphereXAdmin() { require(msg.sender == _getAddress(SPHEREX_ADMIN_STORAGE_SLOT), "SphereX error: admin required"); _; } modifier onlySpherexOperator() { require(msg.sender == _getAddress(SPHEREX_OPERATOR_STORAGE_SLOT), "SphereX error: operator required"); _; } modifier returnsIfNotActivated() { if (address(_sphereXEngine()) == address(0)) { return; } _; } // ============ Management ============ /** * Returns the currently pending admin address, the one that can call acceptSphereXAdminRole to become the admin. * @dev Could not use OZ Ownable2Step because the client's contract might use it. */ function pendingSphereXAdmin() public view returns (address) { return _getAddress(SPHEREX_PENDING_ADMIN_STORAGE_SLOT); } /** * Returns the current admin address, the one that can call acceptSphereXAdminRole to become the admin. * @dev Could not use OZ Ownable2Step because the client's contract might use it. */ function sphereXAdmin() public view returns (address) { return _getAddress(SPHEREX_ADMIN_STORAGE_SLOT); } /** * Returns the current operator address. */ function sphereXOperator() public view returns (address) { return _getAddress(SPHEREX_OPERATOR_STORAGE_SLOT); } /** * Returns the current engine address. */ function sphereXEngine() public view returns (address) { return _getAddress(SPHEREX_ENGINE_STORAGE_SLOT); } /** * Setting the address of the next admin. this address will have to accept the role to become the new admin. * @dev Could not use OZ Ownable2Step because the client's contract might use it. */ function transferSphereXAdminRole(address newAdmin) public virtual onlySphereXAdmin { _setAddress(SPHEREX_PENDING_ADMIN_STORAGE_SLOT, newAdmin); emit SpherexAdminTransferStarted(sphereXAdmin(), newAdmin); } /** * Accepting the admin role and completing the transfer. * @dev Could not use OZ Ownable2Step because the client's contract might use it. */ function acceptSphereXAdminRole() public virtual { require(pendingSphereXAdmin() == msg.sender, "SphereX error: not the pending account"); address oldAdmin = sphereXAdmin(); _setAddress(SPHEREX_ADMIN_STORAGE_SLOT, msg.sender); _setAddress(SPHEREX_PENDING_ADMIN_STORAGE_SLOT, address(0)); emit SpherexAdminTransferCompleted(oldAdmin, msg.sender); } /** * * @param newSphereXOperator new address of the new operator account */ function changeSphereXOperator(address newSphereXOperator) external onlySphereXAdmin { address oldSphereXOperator = _getAddress(SPHEREX_OPERATOR_STORAGE_SLOT); _setAddress(SPHEREX_OPERATOR_STORAGE_SLOT, newSphereXOperator); emit ChangedSpherexOperator(oldSphereXOperator, newSphereXOperator); } /** * Checks the given address implements ISphereXEngine or is address(0) * @param newSphereXEngine new address of the spherex engine */ function _checkSphereXEngine(address newSphereXEngine) private view { require( newSphereXEngine == address(0) || ISphereXEngine(newSphereXEngine).supportsInterface(type(ISphereXEngine).interfaceId), "SphereX error: not a SphereXEngine" ); } /** * * @param newSphereXEngine new address of the spherex engine * @dev this is also used to actually enable the defense * (because as long is this address is 0, the protection is disabled). */ function changeSphereXEngine(address newSphereXEngine) external onlySpherexOperator { _checkSphereXEngine(newSphereXEngine); address oldEngine = _getAddress(SPHEREX_ENGINE_STORAGE_SLOT); _setAddress(SPHEREX_ENGINE_STORAGE_SLOT, newSphereXEngine); emit ChangedSpherexEngineAddress(oldEngine, newSphereXEngine); } // ============ Engine interaction ============ function _addAllowedSenderOnChain(address newSender) internal { ISphereXEngine engine = _sphereXEngine(); if (address(engine) != address(0)) { engine.addAllowedSenderOnChain(newSender); emit NewAllowedSenderOnchain(newSender); } } }
// SPDX-License-Identifier: UNLICENSED // (c) SphereX 2023 Terms&Conditions pragma solidity ^0.8.0; import {SphereXProtectedBase} from "./SphereXProtectedBase.sol"; /** * @title SphereX base Customer contract template * @dev notice this is an abstract */ abstract contract SphereXProtected is SphereXProtectedBase(msg.sender, address(0), address(0)) {}
// SPDX-License-Identifier: UNLICENSED // (c) SphereX 2023 Terms&Conditions pragma solidity ^0.8.0; import {ISphereXEngine, ModifierLocals} from "./ISphereXEngine.sol"; import {SphereXConfiguration} from "./SphereXConfiguration.sol"; /** * @title SphereX base Customer contract template */ /// @custom:oz-upgrades-unsafe-allow constructor abstract contract SphereXProtectedBase is SphereXConfiguration { constructor(address admin, address operator, address engine) SphereXConfiguration(admin, operator, engine) {} // ============ Hooks ============ /** * @dev internal function for engine communication. We use it to reduce contract size. * Should be called before the code of a function. * @param num function identifier * @param isExternalCall set to true if this was called externally * or a 'public' function from another address */ function _sphereXValidatePre(int256 num, bool isExternalCall) private returnsIfNotActivated returns (ModifierLocals memory locals) { ISphereXEngine engine = _sphereXEngine(); if (isExternalCall) { locals.storageSlots = engine.sphereXValidatePre(num, msg.sender, msg.data); } else { locals.storageSlots = engine.sphereXValidateInternalPre(num); } locals.valuesBefore = _readStorage(locals.storageSlots); locals.gas = gasleft(); locals.engine = address(engine); return locals; } /** * @dev internal function for engine communication. We use it to reduce contract size. * Should be called after the code of a function. * @param num function identifier * @param isExternalCall set to true if this was called externally * or a 'public' function from another address */ function _sphereXValidatePost(int256 num, bool isExternalCall, ModifierLocals memory locals) private { ISphereXEngine engine = ISphereXEngine(locals.engine); if (address(engine) == address(0)) { return; } uint256 gas = locals.gas - gasleft(); bytes32[] memory valuesAfter; valuesAfter = _readStorage(locals.storageSlots); if (isExternalCall) { engine.sphereXValidatePost(num, gas, locals.valuesBefore, valuesAfter); } else { engine.sphereXValidateInternalPost(num, gas, locals.valuesBefore, valuesAfter); } } // ============ Modifiers ============ /** * @dev Modifier to be incorporated in all internal protected non-view functions */ modifier sphereXGuardInternal(int256 num) { ModifierLocals memory locals = _sphereXValidatePre(num, false); _; _sphereXValidatePost(-num, false, locals); } /** * @dev Modifier to be incorporated in all external protected non-view functions */ modifier sphereXGuardExternal(int256 num) { ModifierLocals memory locals = _sphereXValidatePre(num, true); _; _sphereXValidatePost(-num, true, locals); } /** * @dev Modifier to be incorporated in all public protected non-view functions */ modifier sphereXGuardPublic(int256 num, bytes4 selector) { ModifierLocals memory locals = _sphereXValidatePre(num, msg.sig == selector); _; _sphereXValidatePost(-num, msg.sig == selector, locals); } // ============ Internal Storage logic ============ /** * Internal function that reads values from given storage slots and returns them * @param storageSlots list of storage slots to read * @return list of values read from the various storage slots */ function _readStorage(bytes32[] memory storageSlots) internal view returns (bytes32[] memory) { uint256 arrayLength = storageSlots.length; bytes32[] memory values = new bytes32[](arrayLength); // create the return array data for (uint256 i = 0; i < arrayLength; i++) { bytes32 slot = storageSlots[i]; bytes32 temp_value; // solhint-disable-next-line no-inline-assembly // slither-disable-next-line assembly assembly { temp_value := sload(slot) } values[i] = temp_value; } return values; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IAsset { // solhint-disable-previous-line no-empty-blocks } interface IBeraVault { struct SingleSwap { bytes32 poolId; SwapKind kind; IAsset assetIn; IAsset assetOut; uint256 amount; bytes userData; } struct BatchSwapStep { bytes32 poolId; uint256 assetInIndex; uint256 assetOutIndex; uint256 amount; bytes userData; } struct FundManagement { address sender; bool fromInternalBalance; address payable recipient; bool toInternalBalance; } struct JoinPoolRequest { IAsset[] assets; uint256[] maxAmountsIn; bytes userData; bool fromInternalBalance; } struct ExitPoolRequest { IAsset[] assets; uint256[] minAmountsOut; bytes userData; bool toInternalBalance; } enum PoolSpecialization { GENERAL, MINIMAL_SWAP_INFO, TWO_TOKEN } enum SwapKind { GIVEN_IN, GIVEN_OUT } function getPoolTokens( bytes32 poolId ) external view returns (IERC20[] memory tokens, uint256[] memory balances, uint256 lastChangeBlock); function getPool(bytes32 poolId) external view returns (address, PoolSpecialization); function swap( SingleSwap memory singleSwap, FundManagement memory funds, uint256 limit, uint256 deadline ) external returns (uint256 amountCalculated); function batchSwap( SwapKind kind, BatchSwapStep[] memory swaps, IAsset[] memory assets, FundManagement memory funds, int256[] memory limits, uint256 deadline ) external payable returns (int256[] memory); function joinPool(bytes32 poolId, address sender, address recipient, JoinPoolRequest memory request) external payable; function exitPool(bytes32 poolId, address sender, address payable recipient, ExitPoolRequest memory request) external; } interface IBeraPool { function getPoolId() external view returns (bytes32); function getVault() external view returns (address); function balanceOf(address account) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IWETH is IERC20 { function name() external view returns (string memory); function approve(address guy, uint256 wad) external returns (bool); function totalSupply() external view returns (uint256); function transferFrom(address src, address dst, uint256 wad) external returns (bool); function withdraw(uint256 wad) external; function withdrawTo(address account, uint256 amount) external; function decimals() external view returns (uint8); function balanceOf(address) external view returns (uint256); function symbol() external view returns (string memory); function transfer(address dst, uint256 wad) external returns (bool); function deposit() external payable; function allowance(address, address) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; interface IDexType { /// @notice Enum representing different DEX types enum DexType { UNISWAP_V2, // 0 UNISWAP_V3, // 1 SUSHISWAP_V2, // 2 SUSHISWAP_V3, // 3 CAMELOT_V3, // 4 BEX, // 5 KODIAK_V3, // 6 KODIAK_V2, // 7 STEER, // 8 GAMMA // 9 } /// @notice Emitted when the default DEX is set /// @param dex The DEX index event SetDefaultDex(uint8 dex); /// @notice Thrown when trying to use an unsupported DEX type error UnsupportedDexType(); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {IDexType} from "./IDexType.sol"; interface ILpRouter is IDexType { /// @notice Thrown when router arrays have mismatched lengths error InvalidRouterLength(); /// @notice Thrown when router address is zero error ZeroRouterAddress(); /// @notice Thrown when address is zero error ZeroAddress(); /// @notice Thrown when a function is called by an address that isn't governance error NotGovernance(); /// @notice Thrown when total ratio is zero error TotalRatioZero(); /// @notice Emitted when the governance is updated event GovernanceUpdated(address indexed oldGovernance, address indexed newGovernance); /// @notice Emitted when a router is set for a DEX /// @param dex The DEX index /// @param router The router address event SetRouter(uint8 dex, address indexed router); /// @notice Emitted when a swap router is set /// @param swapRouter The swap router address event SetSwapRouter(address indexed old, address indexed swapRouter); struct LiquidityAddInfo { address lp; address token0; address token1; uint256 amount0; uint256 amount1; } struct LiquidityRemoveInfo { address lp; uint256 lpAmount; address token0; address token1; address recipient; } function addLiquidity( address lp, address tokenIn, uint256 amountIn, address recipient, DexType dexType ) external returns (uint256 lpAmountOut); function removeLiquidity( address lp, uint256 lpAmount, address recipient, address tokenOut, DexType dexType ) external returns (uint256 tokenOutAmount); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {IDexType} from "./IDexType.sol"; import {IBeraPool} from "./exchange/Beraswap.sol"; /** * @title ISwapRouter * @notice Interface for the SwapRouter contract that handles token swaps across multiple DEXes */ interface ISwapRouter is IDexType { // Errors /// @notice Thrown when router arrays have mismatched lengths error InvalidRouterLength(); /// @notice Thrown when router/factory arrays have mismatched lengths error InvalidFactoryLength(); /// @notice Thrown when path length is less than 2 error InvalidPathLength(); /// @notice Thrown when address is zero error ZeroAddress(); /// @notice Thrown when router address is zero error ZeroRouterAddress(); /// @notice Thrown when trying to use an unsupported factory error FactoryNotSupported(); /// @notice Thrown when trying to use an unsupported router error RouterNotSupported(); /// @notice Thrown when no pool is found for a multihop swap error NoPoolFoundForMultihopSwap(); /// @notice Thrown when no pool is found for a multihop quote error NoPoolFoundForMultihopQuote(); /// @notice Thrown when output amount is less than minimum /// @param amountOut Actual output amount /// @param amountOutMinimum Minimum required output amount error InsufficientOutputAmount(uint256 amountOut, uint256 amountOutMinimum); /// @notice Thrown when amount is zero error ZeroAmount(); /// @notice Thrown when a function is called by an address that isn't governance error NotGovernance(); /// @notice Thrown when no swap route is found error NoSwapRouteFound(); /// @notice Thrown when path length exceeds the maximum error PathLengthExceeded(); /// @notice Thrown when no pool is found for a token pair error NoPoolFound(); // Events /// @notice Emitted when the governance is updated event GovernanceUpdated(address indexed oldGovernance, address indexed newGovernance); /// @notice Emitted when a router is set for a DEX /// @param dex The DEX index /// @param router The router address event SetRouter(uint8 dex, address indexed router); /// @notice Emitted when a factory is set for a DEX /// @param dex The DEX index /// @param factory The factory address event SetFactory(uint8 dex, address indexed factory); /// @notice Emitted when a pool is set /// @param tokenIn The input token address /// @param tokenOut The output token address /// @param pool The pool address event SetPool(address indexed tokenIn, address indexed tokenOut, address pool); /// @notice Emitted when a swap route is set /// @param tokenIn The input token address /// @param tokenOut The output token address /// @param path The swap route path /// @param reversePath Whether to set the inverse swap route event SetSwapRoute(address indexed tokenIn, address indexed tokenOut, SwapRoutePath[] path, bool reversePath); /// @notice Struct for a swap route path /// @param tokenIn The input token address /// @param tokenOut The output token address /// @param dex The DEX type /// @param isMultiPath Whether the path is a multi-path swap /// @param pool The pool address struct SwapRoutePath { address tokenIn; address tokenOut; DexType dex; bool isMultiPath; address pool; } // Functions /// @notice Returns the wrapped native token address (e.g. WETH) /// @return The address of the wrapped native token function wrappedNative() external view returns (address); /// @notice Returns the router address for a given DEX /// @param dex The DEX index /// @return The router address function routers(uint8 dex) external view returns (address); /// @notice Returns the factory address for a given DEX /// @param dex The DEX index /// @return The factory address function factories(uint8 dex) external view returns (address); /// @notice Returns the default DEX type used for swaps /// @return The default DexType enum value function defaultDex() external view returns (DexType); /// @notice Swaps tokens using the default DEX /// @param tokenIn The input token address /// @param tokenOut The output token address /// @param amountIn The amount of input tokens /// @param amountOutMinimum The minimum amount of output tokens required /// @param recipient The address that will receive the output tokens /// @return amountOut The amount of output tokens received function swapWithDefaultDex( address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOutMinimum, address recipient ) external returns (uint256 amountOut); /// @notice Swaps tokens using a specified DEX /// @param tokenIn The input token address /// @param tokenOut The output token address /// @param amountIn The amount of input tokens /// @param amountOutMinimum The minimum amount of output tokens required /// @param recipient The address that will receive the output tokens /// @param dex The DEX to use for the swap /// @return amountOut The amount of output tokens received function swap( address tokenIn, address tokenOut, uint256 amountIn, uint256 amountOutMinimum, address recipient, DexType dex ) external returns (uint256 amountOut); /// @notice Performs a multi-hop swap using the default DEX /// @param path Array of token addresses representing the swap path /// @param amountIn The amount of input tokens /// @param amountOutMinimum The minimum amount of output tokens required /// @param recipient The address that will receive the output tokens /// @return amountOut The amount of output tokens received function swapWithPathWithDefaultDex( address[] calldata path, uint256 amountIn, uint256 amountOutMinimum, address recipient ) external returns (uint256 amountOut); /// @notice Performs a multi-hop swap using a specified DEX /// @param path Array of token addresses representing the swap path /// @param amountIn The amount of input tokens /// @param amountOutMinimum The minimum amount of output tokens required /// @param recipient The address that will receive the output tokens /// @param dex The DEX to use for the swap /// @return amountOut The amount of output tokens received function swapWithPath( address[] calldata path, uint256 amountIn, uint256 amountOutMinimum, address recipient, DexType dex ) external returns (uint256 amountOut); /// @notice Gets a quote for a swap using the default DEX /// @param tokenIn The input token address /// @param tokenOut The output token address /// @param amountIn The amount of input tokens /// @return amountOut The expected amount of output tokens function getQuoteWithDefaultDex( address tokenIn, address tokenOut, uint256 amountIn ) external 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 timelock address is updated /// @param oldTimelock The old timelock address /// @param newTimelock The new timelock address event TimelockChanged(address indexed oldTimelock, address indexed newTimelock); /// @notice Emitted when the controller address is updated /// @param oldController The old controller address /// @param newController The new controller address event ControllerChanged(address indexed oldController, address indexed newController); /// @notice Emitted when the minimum ratio is updated /// @param oldMin The old minimum ratio /// @param newMin The new minimum ratio event MinChanged(uint256 oldMin, uint256 newMin); /// @notice Emitted when the deposit fee is updated /// @param oldFee The old deposit fee /// @param newFee The new deposit fee event DepositFeeChanged(uint16 oldFee, uint16 newFee); /// @notice Emitted when the withdraw fee is updated /// @param oldFee The old withdraw fee /// @param newFee The new withdraw fee event WithdrawFeeChanged(uint16 oldFee, uint16 newFee); // Functions /// @notice Sends available assets to controller to be invested in strategy function earn() external; /// @notice Calculates amount of assets available to be sent to strategy /// @return uint256 Amount of assets available function available() external view returns (uint256); /// @notice Deposits assets with minimum shares check /// @param assets Amount of assets to deposit /// @param receiver Address receiving the shares /// @param minShares Minimum shares that must be minted /// @return shares Amount of shares minted function deposit(uint256 assets, address receiver, uint256 minShares) external returns (uint256 shares); /// @notice Redeems shares with minimum assets check /// @param shares Amount of shares to redeem /// @param receiver Address receiving the assets /// @param owner Address that owns the shares /// @param minAssets Minimum assets that must be returned /// @return assets Amount of assets returned function redeem(uint256 shares, address receiver, address owner, uint256 minAssets) external returns (uint256 assets); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {IWETH} from "../interfaces/exchange/IWETH.sol"; import {ISwapRouter} from "../interfaces/ISwapRouter.sol"; import {IVault} from "../interfaces/IVault.sol"; /** * @title IZapper Interface * @notice Interface for contracts that enable deposits/withdrawals from vaults using any token * @dev Implements functionality for converting tokens and interacting with vaults */ interface IZapper { // Structs /** * @notice Struct to track leftover tokens returned to users * @param tokens Address of the token * @param amounts Amount of tokens returned */ struct ReturnedAsset { address tokens; uint256 amounts; } // Errors /// @notice Thrown when a non-governance address calls a governance-only function error NotGovernance(); /// @notice Thrown when a zero address is provided error ZeroAddress(); /// @notice Thrown when input amount is below minimum required error InsufficientInputAmount(address token, uint256 provided, uint256 minimum); /// @notice Thrown when token approval is missing error TokenNotApproved(); /// @notice Thrown when ETH transfer fails error ETHTransferFailed(); /// @notice Thrown when output amount is below minimum required error InsufficientOutputAmount(address token, uint256 received, uint256 minimum); /// @notice Thrown when fee percentage is too high error FeeTooHigh(uint16 fee, uint16 maxFee); /// @notice Thrown when total ratio is zero error TotalRatioZero(); // Events /// @notice Emitted when swap router address is updated /// @param newSwapRouter Address of the new swap router /// @param oldSwapRouter Address of the previous swap router event SwapRouterChanged(address indexed newSwapRouter, address indexed oldSwapRouter); /// @notice Emitted when stablecoin address is updated /// @param newStableCoin Address of the new stablecoin /// @param oldStableCoin Address of the previous stablecoin event StableCoinChanged(address indexed newStableCoin, address indexed oldStableCoin); /// @notice Emitted when governance address is updated /// @param newGovernance Address of the new governance /// @param oldGovernance Address of the previous governance event GovernanceChanged(address indexed newGovernance, address indexed oldGovernance); /// @notice Emitted when lp router address is updated /// @param newLpRouter Address of the new lp router /// @param oldLpRouter Address of the previous lp router event LpRouterChanged(address indexed newLpRouter, address indexed oldLpRouter); /// @notice Emitted when zapIn fee is updated /// @param oldFee Previous fee percentage in basis points /// @param newFee New fee percentage in basis points event ZapInFeeChanged(uint16 oldFee, uint16 newFee); /// @notice Emitted when zapOut fee is updated /// @param oldFee Previous fee percentage in basis points /// @param newFee New fee percentage in basis points event ZapOutFeeChanged(uint16 oldFee, uint16 newFee); /// @notice Emitted when fee recipient is updated /// @param oldRecipient Address of the previous fee recipient /// @param newRecipient Address of the new fee recipient event FeeRecipientChanged(address indexed oldRecipient, address indexed newRecipient); /// @notice Emitted when tokens are deposited into a vault /// @param user Address of the depositor /// @param vault Address of the target vault /// @param tokenIn Address of the input token /// @param tokenInAmount Amount of input tokens /// @param assetsIn Amount of assets deposited /// @param shares Amount of vault shares received /// @param fee Amount of fee paid /// @param returnedAssets Array of any remaining tokens returned to caller event ZapIn( address indexed user, address indexed vault, address tokenIn, uint256 tokenInAmount, uint256 assetsIn, uint256 shares, uint256 fee, ReturnedAsset[] returnedAssets ); /// @notice Emitted when tokens are withdrawn from a vault /// @param user Address of the withdrawer /// @param vault Address of the source vault /// @param tokenOut Address of the output token /// @param tokenOutAmount Amount of output tokens /// @param assetsOut Amount of assets withdrawn /// @param shares Amount of vault shares withdrawn /// @param fee Amount of fee paid /// @param returnedAssets Array of any remaining tokens returned to caller event ZapOut( address indexed user, address indexed vault, address tokenOut, uint256 tokenOutAmount, uint256 assetsOut, uint256 shares, uint256 fee, ReturnedAsset[] returnedAssets ); /** * @notice Converts input token balance of address(this) to vault's desired token * @param vault The vault to deposit into * @param tokenIn The input token to convert * @return assetsOut Amount of converted assets * @return returnedAssets Array of any remaining tokens returned to caller */ function swapToAssets( address vault, address tokenIn, uint256 tokenInAmount, address recipient ) external returns (uint256 assetsOut, ReturnedAsset[] memory returnedAssets); /** * @notice Converts vault's desired token balance to output token * @param vault The vault to withdraw from * @param tokenOut The output token to convert * @return tokenOutAmount Amount of converted tokens * @return returnedAssets Array of any remaining tokens returned to caller */ function swapFromAssets( address vault, address tokenOut, uint256 assetsInAmount, address recipient ) external returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets); /// @notice Deposits tokens into a vault after converting them if necessary /// @param vault Target vault /// @param tokenIn Input token address /// @param tokenInAmount Amount of input tokens /// @param minShares Minimum amount of vault shares to receive /// @return shares Number of vault shares received /// @return returnedAssets Array of any remaining tokens returned to caller function zapIn( IVault vault, address tokenIn, uint256 tokenInAmount, uint256 minShares ) external payable returns (uint256 shares, ReturnedAsset[] memory returnedAssets); /// @notice Withdraws from vault and converts to desired token /// @param vault Source vault /// @param withdrawAmount Amount of vault shares to withdraw /// @param tokenOut Desired output token /// @param minTokenOutAmount Minimum amount of desired tokens to receive /// @return tokenOutAmount Amount of output tokens received /// @return returnedAssets Array of any remaining tokens returned to caller function zapOut( IVault vault, uint256 withdrawAmount, address tokenOut, uint256 minTokenOutAmount ) external returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.20; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {IWETH} from "../interfaces/exchange/IWETH.sol"; import {ISwapRouter} from "../interfaces/ISwapRouter.sol"; import {ILpRouter} from "../interfaces/ILpRouter.sol"; import {IVault} from "../interfaces/IVault.sol"; import {IZapper} from "../interfaces/IZapper.sol"; import {SphereXProtected} from "@spherex-xyz/contracts/src/SphereXProtected.sol"; import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; /** * @title ZapperBase * @notice Base contract for implementing zapper functionality that allows users to deposit/withdraw * from vaults using any token through automated swaps * @dev This is an abstract contract that should be inherited by specific zapper implementations */ abstract contract ZapperBase is SphereXProtected, ReentrancyGuard, IZapper { using Address for address; using SafeERC20 for IERC20; using SafeERC20 for IVault; /// @notice Minimum token amount required for zap operations to prevent dust transactions uint16 public constant MINIMUM_AMOUNT = 1000; /// @notice Maximum fee that can be set (10% = 1000 basis points) uint16 public constant MAX_FEE = 1000; /// @notice Maximum fee that can be set in basis points (100% = 10000 basis points) uint16 public constant MAX_FEE_BPS = 10000; /// @notice The wrapped version of the native token (e.g., WBERA) IWETH public immutable wrappedNative; /// @notice The fee percentage for zapIn operations in basis points (1/10000) uint16 public zapInFee; /// @notice The fee percentage for zapOut operations in basis points (1/10000) uint16 public zapOutFee; /// @notice The stablecoin token contract used for price calculations and intermediate swaps IERC20 public stablecoin; /// @notice Address of the contract administrator with special privileges address public governance; /// @notice Router contract used for token swaps ISwapRouter public swapRouter; /// @notice Router contract used for add or remove Liquidity ILpRouter public lpRouter; /// @notice Address that receives the fees address public feeRecipient; /** * @notice Constructs the ZapperBase contract * @param devAddress Address of the contract administrator * @param wrappedNativeAddress Address of the wrapped native token (e.g. WBERA) * @param stablecoinAddress Address of the stablecoin token * @param swapRouterAddress Address of the swap router contract * @param lpRouterAddress Address of the lp router contract * @param feeRecipientAddress Address that receives the fees * @param initialZapInFee Initial zapIn fee percentage in basis points * @param initialZapOutFee Initial zapOut fee percentage in basis points */ constructor( address devAddress, address wrappedNativeAddress, address stablecoinAddress, address swapRouterAddress, address lpRouterAddress, address feeRecipientAddress, uint16 initialZapInFee, uint16 initialZapOutFee ) { if ( devAddress == address(0) || wrappedNativeAddress == address(0) || stablecoinAddress == address(0) || swapRouterAddress == address(0) || lpRouterAddress == address(0) || feeRecipientAddress == address(0) ) revert ZeroAddress(); governance = devAddress; wrappedNative = IWETH(wrappedNativeAddress); wrappedNative.deposit{value: 0}(); wrappedNative.withdraw(0); stablecoin = IERC20(stablecoinAddress); swapRouter = ISwapRouter(swapRouterAddress); lpRouter = ILpRouter(lpRouterAddress); if (initialZapInFee > MAX_FEE) revert FeeTooHigh(initialZapInFee, MAX_FEE); if (initialZapOutFee > MAX_FEE) revert FeeTooHigh(initialZapOutFee, MAX_FEE); feeRecipient = feeRecipientAddress; zapInFee = initialZapInFee; zapOutFee = initialZapOutFee; } /// @notice Restricts function access to only the governance address modifier onlyGovernance() { if (msg.sender != governance) revert NotGovernance(); _; } /** * @notice Updates the governance address, only callable by governance * @param governanceAddress New governance address */ function setGovernance(address governanceAddress) external onlyGovernance { _revertAddressZero(governanceAddress); governance = governanceAddress; emit GovernanceChanged(governanceAddress, governance); } /** * @notice Updates the swap router address, only callable by governance * @param routerAddress New swap router address */ function setSwapRouter(address routerAddress) external onlyGovernance sphereXGuardExternal(0xd473ef3c) { _revertAddressZero(routerAddress); address old = address(swapRouter); swapRouter = ISwapRouter(routerAddress); emit SwapRouterChanged(old, routerAddress); } /** * @notice Updates the lp router address, only callable by governance * @param routerAddress New lp router address */ function setLpRouter(address routerAddress) external onlyGovernance sphereXGuardExternal(0x26b2eef4) { _revertAddressZero(routerAddress); address old = address(lpRouter); lpRouter = ILpRouter(routerAddress); emit LpRouterChanged(old, routerAddress); } /** * @notice Updates the stablecoin address, only callable by governance * @param stablecoinAddress New stablecoin address */ function setStableCoin(address stablecoinAddress) external onlyGovernance sphereXGuardExternal(0x5b9fdae4) { _revertAddressZero(stablecoinAddress); stablecoin = IERC20(stablecoinAddress); emit StableCoinChanged(address(stablecoin), stablecoinAddress); } /** * @notice Updates the zapIn fee percentage, only callable by governance * @param newFee New fee percentage in basis points */ function setZapInFee(uint16 newFee) external onlyGovernance { if (newFee > MAX_FEE) revert FeeTooHigh(newFee, MAX_FEE); uint16 oldFee = zapInFee; zapInFee = newFee; emit ZapInFeeChanged(oldFee, newFee); } /** * @notice Updates the zapOut fee percentage, only callable by governance * @param newFee New fee percentage in basis points */ function setZapOutFee(uint16 newFee) external onlyGovernance { if (newFee > MAX_FEE) revert FeeTooHigh(newFee, MAX_FEE); uint16 oldFee = zapOutFee; zapOutFee = newFee; emit ZapOutFeeChanged(oldFee, newFee); } /** * @notice Updates the fee recipient address, only callable by governance * @param newRecipient New address to receive fees */ function setFeeRecipient(address newRecipient) external onlyGovernance { _revertAddressZero(newRecipient); address oldRecipient = feeRecipient; feeRecipient = newRecipient; emit FeeRecipientChanged(oldRecipient, newRecipient); } receive() external payable { assert(msg.sender == address(wrappedNative)); } /** Internal functions */ function _revertAddressZero(address addressToCheck) internal pure { if (addressToCheck == address(0)) revert ZeroAddress(); } /** * @notice Approves spending of a token if not already approved * @param tokenAddress Token to approve * @param spenderAddress Address to approve spending for */ function _approveTokenIfNeeded( address tokenAddress, address spenderAddress ) internal sphereXGuardInternal(0x367a5b5d) { if (IERC20(tokenAddress).allowance(address(this), spenderAddress) == 0) { IERC20(tokenAddress).approve(spenderAddress, type(uint256).max); } } function _safeTransferFromTokens( address token, uint256 amount ) internal sphereXGuardInternal(0x9ffc4661) returns (uint256) { if (IERC20(token).allowance(msg.sender, address(this)) < amount) revert TokenNotApproved(); uint256 balanceBefore = IERC20(token).balanceOf(address(this)); IERC20(token).safeTransferFrom(msg.sender, address(this), amount); uint256 balanceAfter = IERC20(token).balanceOf(address(this)); return balanceAfter - balanceBefore; } /** * @notice Divides an amount between two tokens based on their ratio * @dev Used to split a single token amount into two token amounts while maintaining their ratio * @param amount The total amount to divide * @param ratio0 The ratio for the first token * @param ratio1 The ratio for the second token * @return amount0 The amount allocated to the first token * @return amount1 The amount allocated to the second token */ function _divideAmountInRatio( uint256 amount, uint256 ratio0, uint256 ratio1 ) internal pure returns (uint256, uint256) { uint256 totalRatio = ratio0 + ratio1; if (totalRatio == 0) revert TotalRatioZero(); uint256 amount0 = (amount * ratio0) / totalRatio; uint256 amount1 = amount - amount0; return (amount0, amount1); } /** * @notice Returns any remaining tokens to the caller * @param tokens Array of token addresses to check and return * @return returnedAssets Array of ReturnedAsset structs containing token addresses and amounts returned */ function _returnAssets( address[] memory tokens ) internal sphereXGuardInternal(0x65afacc1) returns (ReturnedAsset[] memory returnedAssets) { uint256 balance; returnedAssets = new ReturnedAsset[](tokens.length); for (uint256 i = 0; i < tokens.length; i++) { if (tokens[i] == address(0)) continue; balance = IERC20(tokens[i]).balanceOf(address(this)); returnedAssets[i] = ReturnedAsset({tokens: tokens[i], amounts: balance}); if (balance > 0) { if (tokens[i] == address(wrappedNative)) { wrappedNative.withdraw(balance); (bool success, ) = msg.sender.call{value: balance}(new bytes(0)); if (!success) revert ETHTransferFailed(); } else { IERC20(tokens[i]).safeTransfer(msg.sender, balance); } } } } /** * @notice Returns any remaining tokens to the caller * @param token The token to return * @param recipient The address to return the token to * @return amount The amount of tokens returned */ function _returnAsset( address token, address recipient ) internal sphereXGuardInternal(0xf45372f8) returns (uint256 amount) { amount = IERC20(token).balanceOf(address(this)); _returnAssetWithAmount(token, recipient, amount); } /** * @notice Returns the amount of tokens to the caller, if the token is wrappedNative, it will be converted to native token * @param token The token to return * @param recipient The address to return the token to * @param amount The amount of tokens to return */ function _returnAssetWithAmount(address token, address recipient, uint256 amount) internal { if (amount > 0) { if (token == address(wrappedNative)) { wrappedNative.withdraw(amount); (bool success, ) = recipient.call{value: amount}(new bytes(0)); if (!success) revert ETHTransferFailed(); } else { IERC20(token).safeTransfer(recipient, amount); } } } /** * @notice Transfers the fee to the fee recipient * @param token The token to transfer * @param fee The fee percentage in basis points * @param amount The amount of tokens to transfer * @return amount The amount of tokens after the fee is transferred */ function _transferFee(address token, uint16 fee, uint256 amount) internal returns (uint256, uint256 feeAmount) { if (fee > 0) { feeAmount = (amount * fee) / MAX_FEE_BPS; _returnAssetWithAmount(token, feeRecipient, feeAmount); amount -= feeAmount; } return (amount, feeAmount); } /** * @notice Converts input token balance of address(this) to vault's desired token * @param asset The asset to convert * @param tokenIn The input token to convert * @return assetsOut Amount of converted assets * @return returnedAssets Array of any remaining tokens returned to caller */ function swapToAssets( address asset, address tokenIn, uint256 tokenInAmount, address recipient ) public virtual returns (uint256 assetsOut, ReturnedAsset[] memory returnedAssets); /** * @notice Converts vault's desired token balance to output token * @param asset The asset to convert * @param tokenOut The output token to convert * @return tokenOutAmount Amount of converted tokens * @return returnedAssets Array of any remaining tokens returned to caller */ function swapFromAssets( address asset, address tokenOut, uint256 assetsInAmount, address recipient ) public virtual returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets); /** * @notice Deposits tokens into a vault after converting them if necessary * @param vault Target vault * @param tokenIn Input token address * @param tokenInAmount Amount of input tokens * @param minShares Minimum amount of vault shares to receive * @return shares Number of vault shares received * @return returnedAssets Array of any remaining tokens returned to caller */ function zapIn( IVault vault, address tokenIn, uint256 tokenInAmount, uint256 minShares ) external payable virtual nonReentrant sphereXGuardExternal(0x621b094a) returns (uint256 shares, ReturnedAsset[] memory returnedAssets) { // if eth is the tokenIn, we need to convert it to the wrappedNative if (tokenIn == address(0)) { if (msg.value < MINIMUM_AMOUNT) revert InsufficientInputAmount(address(0), msg.value, MINIMUM_AMOUNT); wrappedNative.deposit{value: msg.value}(); tokenIn = address(wrappedNative); tokenInAmount = msg.value; } else { if (tokenInAmount < MINIMUM_AMOUNT) revert InsufficientInputAmount(tokenIn, tokenInAmount, MINIMUM_AMOUNT); tokenInAmount = _safeTransferFromTokens(tokenIn, tokenInAmount); } // transfer the fee uint256 feeAmount; (tokenInAmount, feeAmount) = _transferFee(tokenIn, zapInFee, tokenInAmount); // convert the input token to the vault's asset if needed uint256 assetsIn = tokenInAmount; if (vault.asset() != tokenIn) { (assetsIn, returnedAssets) = swapToAssets(vault.asset(), tokenIn, tokenInAmount, address(this)); } // approve the asset to the vault IERC20(vault.asset()).forceApprove(address(vault), assetsIn); // deposit the asset to the vault shares = vault.deposit(assetsIn, msg.sender, minShares); emit ZapIn(msg.sender, address(vault), tokenIn, tokenInAmount, assetsIn, shares, feeAmount, returnedAssets); } /** * @notice Withdraws from vault and converts to desired token * @param vault Source vault * @param sharesAmount Amount of vault shares to withdraw * @param tokenOut Desired output token * @param minTokenOutAmount Minimum amount of desired tokens to receive * @return tokenOutAmount Amount of output tokens received * @return returnedAssets Array of any remaining tokens returned to caller */ function zapOut( IVault vault, uint256 sharesAmount, address tokenOut, uint256 minTokenOutAmount ) external virtual nonReentrant sphereXGuardExternal(0xaf73b205) returns (uint256 tokenOutAmount, ReturnedAsset[] memory returnedAssets) { uint256 assetsOut = IVault(vault).redeem(sharesAmount, address(this), msg.sender); // if eth is the desiredToken, we need to convert it to the wrappedNative if (tokenOut == address(0)) { tokenOut = address(wrappedNative); } // convert the asset to the desired token if needed if (vault.asset() == tokenOut) { tokenOutAmount = assetsOut; } else { (tokenOutAmount, returnedAssets) = swapFromAssets(vault.asset(), tokenOut, assetsOut, address(this)); } // transfer the fee uint256 feeAmount; (tokenOutAmount, feeAmount) = _transferFee(tokenOut, zapOutFee, tokenOutAmount); // return the token _returnAsset(tokenOut, msg.sender); if (tokenOutAmount < minTokenOutAmount) revert InsufficientOutputAmount(tokenOut, tokenOutAmount, minTokenOutAmount); emit ZapOut( msg.sender, address(vault), tokenOut, tokenOutAmount, assetsOut, sharesAmount, feeAmount, returnedAssets ); } }
{ "optimizer": { "enabled": true, "runs": 100 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"devAddress","type":"address"},{"internalType":"address","name":"wrappedNative","type":"address"},{"internalType":"address","name":"stablecoin","type":"address"},{"internalType":"address","name":"swapRouter","type":"address"},{"internalType":"address","name":"lpRouter","type":"address"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"uint16","name":"zapInFee","type":"uint16"},{"internalType":"uint16","name":"zapOutFee","type":"uint16"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[{"internalType":"uint16","name":"fee","type":"uint16"},{"internalType":"uint16","name":"maxFee","type":"uint16"}],"name":"FeeTooHigh","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"provided","type":"uint256"},{"internalType":"uint256","name":"minimum","type":"uint256"}],"name":"InsufficientInputAmount","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"received","type":"uint256"},{"internalType":"uint256","name":"minimum","type":"uint256"}],"name":"InsufficientOutputAmount","type":"error"},{"inputs":[],"name":"NotGovernance","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"TokenNotApproved","type":"error"},{"inputs":[],"name":"TotalRatioZero","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldEngineAddress","type":"address"},{"indexed":false,"internalType":"address","name":"newEngineAddress","type":"address"}],"name":"ChangedSpherexEngineAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldSphereXAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newSphereXAdmin","type":"address"}],"name":"ChangedSpherexOperator","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"newRecipient","type":"address"}],"name":"FeeRecipientChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newGovernance","type":"address"},{"indexed":true,"internalType":"address","name":"oldGovernance","type":"address"}],"name":"GovernanceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newLpRouter","type":"address"},{"indexed":true,"internalType":"address","name":"oldLpRouter","type":"address"}],"name":"LpRouterChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"NewAllowedSenderOnchain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"SpherexAdminTransferCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"currentAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"pendingAdmin","type":"address"}],"name":"SpherexAdminTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newStableCoin","type":"address"},{"indexed":true,"internalType":"address","name":"oldStableCoin","type":"address"}],"name":"StableCoinChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newSwapRouter","type":"address"},{"indexed":true,"internalType":"address","name":"oldSwapRouter","type":"address"}],"name":"SwapRouterChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"address","name":"tokenIn","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenInAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetsIn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"components":[{"internalType":"address","name":"tokens","type":"address"},{"internalType":"uint256","name":"amounts","type":"uint256"}],"indexed":false,"internalType":"struct IZapper.ReturnedAsset[]","name":"returnedAssets","type":"tuple[]"}],"name":"ZapIn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"oldFee","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"newFee","type":"uint16"}],"name":"ZapInFeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"address","name":"tokenOut","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenOutAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetsOut","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"components":[{"internalType":"address","name":"tokens","type":"address"},{"internalType":"uint256","name":"amounts","type":"uint256"}],"indexed":false,"internalType":"struct IZapper.ReturnedAsset[]","name":"returnedAssets","type":"tuple[]"}],"name":"ZapOut","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"oldFee","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"newFee","type":"uint16"}],"name":"ZapOutFeeChanged","type":"event"},{"inputs":[],"name":"MAX_FEE","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_FEE_BPS","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_AMOUNT","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptSphereXAdminRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSphereXEngine","type":"address"}],"name":"changeSphereXEngine","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSphereXOperator","type":"address"}],"name":"changeSphereXOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpRouter","outputs":[{"internalType":"contract ILpRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingSphereXAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newRecipient","type":"address"}],"name":"setFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"governanceAddress","type":"address"}],"name":"setGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"routerAddress","type":"address"}],"name":"setLpRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"stablecoinAddress","type":"address"}],"name":"setStableCoin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"routerAddress","type":"address"}],"name":"setSwapRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newFee","type":"uint16"}],"name":"setZapInFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"newFee","type":"uint16"}],"name":"setZapOutFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sphereXAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sphereXEngine","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sphereXOperator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stablecoin","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"assetsInAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"swapFromAssets","outputs":[{"internalType":"uint256","name":"tokenOutAmount","type":"uint256"},{"components":[{"internalType":"address","name":"tokens","type":"address"},{"internalType":"uint256","name":"amounts","type":"uint256"}],"internalType":"struct IZapper.ReturnedAsset[]","name":"returnedAssets","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"contract ISwapRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"tokenInAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"swapToAssets","outputs":[{"internalType":"uint256","name":"tokenOutAmount","type":"uint256"},{"components":[{"internalType":"address","name":"tokens","type":"address"},{"internalType":"uint256","name":"amounts","type":"uint256"}],"internalType":"struct IZapper.ReturnedAsset[]","name":"returnedAssets","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"transferSphereXAdminRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrappedNative","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IVault","name":"vault","type":"address"},{"internalType":"address","name":"tokenIn","type":"address"},{"internalType":"uint256","name":"tokenInAmount","type":"uint256"},{"internalType":"uint256","name":"minShares","type":"uint256"}],"name":"zapIn","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"components":[{"internalType":"address","name":"tokens","type":"address"},{"internalType":"uint256","name":"amounts","type":"uint256"}],"internalType":"struct IZapper.ReturnedAsset[]","name":"returnedAssets","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"zapInFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IVault","name":"vault","type":"address"},{"internalType":"uint256","name":"sharesAmount","type":"uint256"},{"internalType":"address","name":"tokenOut","type":"address"},{"internalType":"uint256","name":"minTokenOutAmount","type":"uint256"}],"name":"zapOut","outputs":[{"internalType":"uint256","name":"tokenOutAmount","type":"uint256"},{"components":[{"internalType":"address","name":"tokens","type":"address"},{"internalType":"uint256","name":"amounts","type":"uint256"}],"internalType":"struct IZapper.ReturnedAsset[]","name":"returnedAssets","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"zapOutFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a06040523480156200001157600080fd5b506040516200331438038062003314833981016040819052620000349162000566565b87878787878787873360008082818062000050838280620002de565b50506001600055505050506001600160a01b03881615806200007957506001600160a01b038716155b806200008c57506001600160a01b038616155b806200009f57506001600160a01b038516155b80620000b257506001600160a01b038416155b80620000c557506001600160a01b038316155b15620000e45760405163d92e233d60e01b815260040160405180910390fd5b600280546001600160a01b0319166001600160a01b038a8116919091179091558716608081905260408051630d0e30db60e41b8152905163d0e30db0916000916004808301928492919082900301818388803b1580156200014457600080fd5b505af115801562000159573d6000803e3d6000fd5b5050608051604051632e1a7d4d60e01b8152600060048201526001600160a01b039091169350632e1a7d4d92506024019050600060405180830381600087803b158015620001a657600080fd5b505af1158015620001bb573d6000803e3d6000fd5b5050600180546001600160a01b03808b1664010000000002600160201b600160c01b031990921691909117909155600380548983166001600160a01b031991821617909155600480549289169290911691909117905550506103e861ffff831611156200024e57604051633c057d7b60e01b815261ffff831660048201526103e860248201526044015b60405180910390fd5b6103e861ffff821611156200028557604051633c057d7b60e01b815261ffff821660048201526103e8602482015260440162000245565b600580546001600160a01b039094166001600160a01b0319909416939093179092556001805461ffff938416620100000263ffffffff19909116939092169290921717905550620006619b505050505050505050505050565b620003146200030f60017fca334bf49ef20e9cbff039feda3bc1c2a853aff17b1b5187e4aa1380ec55829d6200060e565b849055565b60408051600081526001600160a01b03851660208201527f67ebaebcd2ca5a91a404e898110f221747e8d15567f2388a34794aab151cf3e6910160405180910390a16200038c6200038760017fadf90d75f0f2d657d5a22fa0f6e4dabb83c4598b77158eb4119cb38f1d8644636200060e565b839055565b60408051600081526001600160a01b03841660208201527f2ac55ae7ba47db34b5334622acafeb34a65daf143b47019273185d64c73a35a5910160405180910390a1620003d98162000456565b6200040f6200040a60017f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d66200060e565b829055565b60408051600081526001600160a01b03831660208201527ff33499cccaa0611882086224cc48cd82ef54b66a4d2edf4ed67108dd516896d5910160405180910390a1505050565b6001600160a01b0381161580620004da57506040516301ffc9a760e01b81526329f20dd560e11b60048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa158015620004b4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620004da919062000636565b620005335760405162461bcd60e51b815260206004820152602260248201527f53706865726558206572726f723a206e6f7420612053706865726558456e67696044820152616e6560f01b606482015260840162000245565b50565b80516001600160a01b03811681146200054e57600080fd5b919050565b805161ffff811681146200054e57600080fd5b600080600080600080600080610100898b0312156200058457600080fd5b6200058f8962000536565b97506200059f60208a0162000536565b9650620005af60408a0162000536565b9550620005bf60608a0162000536565b9450620005cf60808a0162000536565b9350620005df60a08a0162000536565b9250620005ef60c08a0162000553565b9150620005ff60e08a0162000553565b90509295985092959890939650565b818103818111156200063057634e487b7160e01b600052601160045260246000fd5b92915050565b6000602082840312156200064957600080fd5b815180151581146200065a57600080fd5b9392505050565b608051612c5f620006b5600039600081816101a10152818161052a015281816107e401528181610858015281816110230152818161208e015281816120f40152818161224901526122960152612c5f6000f3fe6080604052600436106101915760003560e01c806399e80f3b116100d7578063c31c9c0711610085578063c31c9c0714610465578063d55be8c614610485578063daba7ef71461049b578063e74b981b146104bb578063e7e5db4f146104db578063e9cbd822146104f0578063eb6d3a1114610518578063f99e63871461054c57600080fd5b806399e80f3b146103c05780639aa9019e146103d5578063a863ff2f146103ea578063a89635bc1461040a578063ab033ea914610425578063afb44e3714610445578063bc063e1a1461024b57600080fd5b8063412736571161013f57806341273657146102ca57806346904840146102ea5780634c6c848f1461030a5780634ee8f8581461032a5780635aa6e6751461034a5780638426b9681461036a5780638f0af4241461037f5780639739c03e1461039f57600080fd5b80630c8106dc146101d557806315a292031461020b57806323af4e171461022b578063257d9bb81461024b5780633218e83a146102745780633c231166146102a25780633c3b1ef6146102b757600080fd5b366101d057336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101ce576101ce6125cb565b005b600080fd5b3480156101e157600080fd5b506004546101f5906001600160a01b031681565b60405161020291906125e1565b60405180910390f35b34801561021757600080fd5b506101ce61022636600461260a565b61056c565b34801561023757600080fd5b506101ce61024636600461260a565b61061c565b34801561025757600080fd5b506102616103e881565b60405161ffff9091168152602001610202565b34801561028057600080fd5b5061029461028f366004612627565b6106cf565b6040516102029291906126c9565b3480156102ae57600080fd5b506101f5610758565b6102946102c53660046126ea565b61077f565b3480156102d657600080fd5b506101ce6102e536600461260a565b610b32565b3480156102f657600080fd5b506005546101f5906001600160a01b031681565b34801561031657600080fd5b506101ce61032536600461260a565b610bd5565b34801561033657600080fd5b506101ce61034536600461260a565b610cd8565b34801561035657600080fd5b506002546101f5906001600160a01b031681565b34801561037657600080fd5b506101ce610d91565b34801561038b57600080fd5b506101ce61039a366004612730565b610e8a565b3480156103ab57600080fd5b506001546102619062010000900461ffff1681565b3480156103cc57600080fd5b506101f5610f3a565b3480156103e157600080fd5b506101f5610f58565b3480156103f657600080fd5b50610294610405366004612754565b610f76565b34801561041657600080fd5b506001546102619061ffff1681565b34801561043157600080fd5b506101ce61044036600461260a565b6111ee565b34801561045157600080fd5b506101ce610460366004612730565b61126e565b34801561047157600080fd5b506003546101f5906001600160a01b031681565b34801561049157600080fd5b5061026161271081565b3480156104a757600080fd5b506101ce6104b636600461260a565b61132a565b3480156104c757600080fd5b506101ce6104d636600461260a565b6113cf565b3480156104e757600080fd5b506101f5611455565b3480156104fc57600080fd5b506001546101f59064010000000090046001600160a01b031681565b34801561052457600080fd5b506101f57f000000000000000000000000000000000000000000000000000000000000000081565b34801561055857600080fd5b50610294610567366004612627565b611473565b6002546001600160a01b0316331461059757604051632d5be4cb60e21b815260040160405180910390fd5b6326b2eef460006105a98260016114c7565b90506105b483611643565b600480546001600160a01b038581166001600160a01b0319831681179093556040519116919082907f82c52d8aa62200dfc997bdf1100b1c2ed614580941b2b8637d10b8ca0428eeec90600090a35061061761060f836127b2565b60018361166d565b505050565b6002546001600160a01b0316331461064757604051632d5be4cb60e21b815260040160405180910390fd5b635b9fdae460006106598260016114c7565b905061066483611643565b60018054640100000000600160c01b0319166401000000006001600160a01b03868116828102939093179384905560405192939190910416907f497b8419a37c8014b1a755ec707f25d11ae4bade591d379f9a4095f37edaf76e90600090a361061761060f836127b2565b600060606307c1e85d63190c741d60e11b836106f88382356001600160e01b03191684146114c7565b90506001600160a01b038616301461071757610714888861178f565b96505b61072389898989611958565b9450945061074c610733846127b2565b6000356001600160e01b0319908116908516148361166d565b50505094509492505050565b600061077a6107766001600080516020612c0a8339815191526127ce565b5490565b905090565b6000606061078b611a62565b63621b094a600061079d8260016114c7565b90506001600160a01b038716610881576103e83410156107e2576000346103e8604051630b722aef60e21b81526004016107d9939291906127e1565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561083d57600080fd5b505af1158015610851573d6000803e3d6000fd5b50505050507f000000000000000000000000000000000000000000000000000000000000000096503495506108b9565b6103e88610156108ac5786866103e8604051630b722aef60e21b81526004016107d9939291906127e1565b6108b6878761178f565b95505b6001546000906108cf90899061ffff1689611a8c565b80925081985050506000879050886001600160a01b03168a6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610924573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109489190612806565b6001600160a01b0316146109c8576109c38a6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610997573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109bb9190612806565b8a8a306106cf565b955090505b610a3f8a828c6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2f9190612806565b6001600160a01b03169190611ae7565b60405163bc157ac160e01b815260048101829052336024820152604481018890526001600160a01b038b169063bc157ac1906064016020604051808303816000875af1158015610a93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab79190612823565b9550896001600160a01b0316336001600160a01b03167f87640c2e40d67703e350e7d24d4e416e5c4f1e1550e1285b1bf667440d36bdcf8b8b858b888c604051610b069695949392919061283c565b60405180910390a35050610b1d8261060f906127b2565b5050610b296001600055565b94509492505050565b6002546001600160a01b03163314610b5d57604051632d5be4cb60e21b815260040160405180910390fd5b63d473ef3c6000610b6f8260016114c7565b9050610b7a83611643565b600380546001600160a01b038581166001600160a01b0319831681179093556040519116919082907f5c5b0bb5085481c320dc523e3b3f829eaa807936f615add0077fa213f345090e90600090a35061061761060f836127b2565b610bf16107766001600080516020612baa8339815191526127ce565b6001600160a01b0316336001600160a01b031614610c515760405162461bcd60e51b815260206004820181905260248201527f53706865726558206572726f723a206f70657261746f7220726571756972656460448201526064016107d9565b610c5a81611bb1565b6000610c786107766001600080516020612c0a8339815191526127ce565b9050610c9b610c966001600080516020612c0a8339815191526127ce565b839055565b7ff33499cccaa0611882086224cc48cd82ef54b66a4d2edf4ed67108dd516896d58183604051610ccc929190612881565b60405180910390a15050565b610cf46107766001600080516020612bea8339815191526127ce565b6001600160a01b0316336001600160a01b031614610d245760405162461bcd60e51b81526004016107d99061289b565b6000610d426107766001600080516020612baa8339815191526127ce565b9050610d60610c966001600080516020612baa8339815191526127ce565b7f2ac55ae7ba47db34b5334622acafeb34a65daf143b47019273185d64c73a35a58183604051610ccc929190612881565b33610d9a610f58565b6001600160a01b031614610dff5760405162461bcd60e51b815260206004820152602660248201527f53706865726558206572726f723a206e6f74207468652070656e64696e67206160448201526518d8dbdd5b9d60d21b60648201526084016107d9565b6000610e09610f3a565b9050610e2c610e276001600080516020612bea8339815191526127ce565b339055565b610e4e610e486001600080516020612bca8339815191526127ce565b60009055565b7f67ebaebcd2ca5a91a404e898110f221747e8d15567f2388a34794aab151cf3e68133604051610e7f929190612881565b60405180910390a150565b6002546001600160a01b03163314610eb557604051632d5be4cb60e21b815260040160405180910390fd5b6103e861ffff82161115610eea57604051633c057d7b60e01b815261ffff821660048201526103e860248201526044016107d9565b6001805461ffff83811661ffff1983168117909355604080519190921680825260208201939093527fcd5c26e400cb366bdac1d1cbdec4b428f15bc14a133ecbda85bc6f11f7acb9f19101610ccc565b600061077a6107766001600080516020612bea8339815191526127ce565b600061077a6107766001600080516020612bca8339815191526127ce565b60006060610f82611a62565b63af73b2056000610f948260016114c7565b604051635d043b2960e11b8152600481018990523060248201523360448201529091506000906001600160a01b038a169063ba087652906064016020604051808303816000875af1158015610fed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110119190612823565b90506001600160a01b038716611045577f000000000000000000000000000000000000000000000000000000000000000096505b866001600160a01b0316896001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561108d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b19190612806565b6001600160a01b0316036110c75780945061113a565b611134896001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611108573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112c9190612806565b888330611473565b90955093505b600061115788600160029054906101000a900461ffff1688611a8c565b90965090506111668833611c88565b50868610156111a157604051632752fb4960e11b81526001600160a01b038916600482015260248101879052604481018890526064016107d9565b896001600160a01b0316336001600160a01b03167f0bc6c5ccdba0b566b3adbb7c24c419a1b872218cd487d145a4e4eb70b2c8bfb38a89868e878c604051610b069695949392919061283c565b6002546001600160a01b0316331461121957604051632d5be4cb60e21b815260040160405180910390fd5b61122281611643565b600280546001600160a01b0319166001600160a01b03831690811790915560405181907f3aaaebeb4821d6a7e5c77ece53cff0afcc56c82add2c978dbbb7f73e84cbcfd290600090a350565b6002546001600160a01b0316331461129957604051632d5be4cb60e21b815260040160405180910390fd5b6103e861ffff821611156112ce57604051633c057d7b60e01b815261ffff821660048201526103e860248201526044016107d9565b6001805461ffff8381166201000081810263ffff00001985161790945560408051949093049091168084526020840191909152917febcac71ae552a15ae4d23c933603e1a71f47ff8371bdd98194f037156b73a7199101610ccc565b6113466107766001600080516020612bea8339815191526127ce565b6001600160a01b0316336001600160a01b0316146113765760405162461bcd60e51b81526004016107d99061289b565b6113976113926001600080516020612bca8339815191526127ce565b829055565b7f5778f1547abbbb86090a43c32aec38334b31df4beeb6f8f3fa063f593b53a5266113c0610f3a565b82604051610e7f929190612881565b6002546001600160a01b031633146113fa57604051632d5be4cb60e21b815260040160405180910390fd5b61140381611643565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f0bc21fe5c3ab742ff1d15b5c4477ffbacf1167e618228078fa625edebe7f331d90600090a35050565b600061077a6107766001600080516020612baa8339815191526127ce565b6000606063362279f763f99e638760e01b8361149c8382356001600160e01b03191684146114c7565b90506001600160a01b03861630146114bb576114b8898861178f565b96505b61072389898989611d19565b6114fb604051806080016040528060608152602001606081526020016000815260200160006001600160a01b031681525090565b6000611505610758565b6001600160a01b03161461163d57600061151d610758565b905082156115a657604051634492e52d60e11b81526001600160a01b03821690638925ca5a90611558908790339060009036906004016128d2565b6000604051808303816000875af1158015611577573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261159f919081019061292f565b8252611618565b604051633e88494360e01b8152600481018590526001600160a01b03821690633e884943906024016000604051808303816000875af11580156115ed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611615919081019061292f565b82525b815161162390611dda565b60208301525a60408301526001600160a01b031660608201525b92915050565b6001600160a01b03811661166a5760405163d92e233d60e01b815260040160405180910390fd5b50565b60608101516001600160a01b0381166116865750505050565b60005a836040015161169891906127ce565b905060606116a98460000151611dda565b9050841561171e576020840151604051631e17b28d60e31b81526001600160a01b0385169163f0bd9468916116e7918a918791908790600401612a11565b600060405180830381600087803b15801561170157600080fd5b505af1158015611715573d6000803e3d6000fd5b50505050611787565b602084015160405163027313cd60e11b81526001600160a01b038516916304e6279a91611754918a918791908790600401612a11565b600060405180830381600087803b15801561176e57600080fd5b505af1158015611782573d6000803e3d6000fd5b505050505b505050505050565b6000639ffc466160006117a38260006114c7565b905083856001600160a01b031663dd62ed3e33306040518363ffffffff1660e01b81526004016117d4929190612881565b602060405180830381865afa1580156117f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118159190612823565b1015611834576040516332da96a360e01b815260040160405180910390fd5b6040516370a0823160e01b81526000906001600160a01b038716906370a08231906118639030906004016125e1565b602060405180830381865afa158015611880573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118a49190612823565b90506118bb6001600160a01b038716333088611e91565b6040516370a0823160e01b81526000906001600160a01b038816906370a08231906118ea9030906004016125e1565b602060405180830381865afa158015611907573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192b9190612823565b905061193782826127ce565b945050505b611950611948836127b2565b60008361166d565b505092915050565b600454600090606090611978906001600160a01b03878116911686611eca565b6004805460405163190a4d4960e01b81526001600160a01b039091169163190a4d49916119b0918a918a918a918a9160059101612a6f565b6020604051808303816000875af11580156119cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f39190612823565b60408051600180825281830190925291935060009190602080830190803683370190505090508581600081518110611a2d57611a2d612aa3565b60200260200101906001600160a01b031690816001600160a01b031681525050611a5681611ef0565b91505094509492505050565b600260005403611a8557604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b60008061ffff841615611adc57612710611aaa61ffff861685612ab9565b611ab49190612ad0565b600554909150611acf9086906001600160a01b031683612241565b611ad981846127ce565b92505b829150935093915050565b6000836001600160a01b031663095ea7b38484604051602401611b0b929190612af2565b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050509050611b44848261239b565b611bab57611ba184856001600160a01b031663095ea7b3866000604051602401611b6f929190612af2565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050612443565b611bab8482612443565b50505050565b6001600160a01b0381161580611c3157506040516301ffc9a760e01b81526329f20dd560e11b60048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa158015611c0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c319190612b0b565b61166a5760405162461bcd60e51b815260206004820152602260248201527f53706865726558206572726f723a206e6f7420612053706865726558456e67696044820152616e6560f01b60648201526084016107d9565b600063f45372f86000611c9c8260006114c7565b6040516370a0823160e01b81529091506001600160a01b038616906370a0823190611ccb9030906004016125e1565b602060405180830381865afa158015611ce8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0c9190612823565b925061193c858585612241565b600454600090606090611d39906001600160a01b03888116911686611eca565b6004805460405163616a3dbd60e11b81526001600160a01b039091169163c2d47b7a91611d71918a91899189918c9160059101612b2d565b6020604051808303816000875af1158015611d90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db49190612823565b91506001600160a01b0383163014610b2957611dd08584611c88565b5094509492505050565b805160609060008167ffffffffffffffff811115611dfa57611dfa612919565b604051908082528060200260200182016040528015611e23578160200160208202803683370190505b50905060005b82811015611e89576000858281518110611e4557611e45612aa3565b6020026020010151905060008154905080848481518110611e6857611e68612aa3565b60200260200101818152505050508080611e8190612b61565b915050611e29565b509392505050565b6040516001600160a01b038481166024830152838116604483015260648201839052611bab9186918216906323b872dd90608401611b6f565b61061783846001600160a01b031663a9059cbb8585604051602401611b6f929190612af2565b60606365afacc16000611f048260006114c7565b90506000845167ffffffffffffffff811115611f2257611f22612919565b604051908082528060200260200182016040528015611f6757816020015b6040805180820190915260008082526020820152815260200190600190039081611f405790505b50935060005b855181101561222b5760006001600160a01b0316868281518110611f9357611f93612aa3565b60200260200101516001600160a01b0316031561221957858181518110611fbc57611fbc612aa3565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611fef91906125e1565b602060405180830381865afa15801561200c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120309190612823565b9150604051806040016040528087838151811061204f5761204f612aa3565b60200260200101516001600160a01b031681526020018381525085828151811061207b5761207b612aa3565b60209081029190910101528115612219577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168682815181106120c8576120c8612aa3565b60200260200101516001600160a01b0316036121e257604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561214057600080fd5b505af1158015612154573d6000803e3d6000fd5b50506040805160008082526020820192839052935033925085916121789190612b7a565b60006040518083038185875af1925050503d80600081146121b5576040519150601f19603f3d011682016040523d82523d6000602084013e6121ba565b606091505b50509050806121dc5760405163b12d13eb60e01b815260040160405180910390fd5b50612219565b61221933838884815181106121f9576121f9612aa3565b60200260200101516001600160a01b0316611eca9092919063ffffffff16565b8061222381612b61565b915050611f6d565b505061223a82611948906127b2565b5050919050565b8015610617577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03160361238757604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156122e257600080fd5b505af11580156122f6573d6000803e3d6000fd5b5050604080516000808252602082019283905293506001600160a01b038616925084916123239190612b7a565b60006040518083038185875af1925050503d8060008114612360576040519150601f19603f3d011682016040523d82523d6000602084013e612365565b606091505b5050905080611bab5760405163b12d13eb60e01b815260040160405180910390fd5b6106176001600160a01b0384168383611eca565b6000806000846001600160a01b0316846040516123b89190612b7a565b6000604051808303816000865af19150503d80600081146123f5576040519150601f19603f3d011682016040523d82523d6000602084013e6123fa565b606091505b50915091508180156124245750805115806124245750808060200190518101906124249190612b0b565b801561243a57506000856001600160a01b03163b115b95945050505050565b60006124586001600160a01b0384168361249d565b9050805160001415801561247d57508080602001905181019061247b9190612b0b565b155b156106175782604051635274afe760e01b81526004016107d991906125e1565b60606124ab838360006124b2565b9392505050565b6060814710156124d7573060405163cd78605960e01b81526004016107d991906125e1565b600080856001600160a01b031684866040516124f39190612b7a565b60006040518083038185875af1925050503d8060008114612530576040519150601f19603f3d011682016040523d82523d6000602084013e612535565b606091505b509150915061254586838361254f565b9695505050505050565b6060826125645761255f826125a2565b6124ab565b815115801561257b57506001600160a01b0384163b155b1561259b5783604051639996b31560e01b81526004016107d991906125e1565b50806124ab565b8051156125b25780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b600052600160045260246000fd5b6001600160a01b0391909116815260200190565b6001600160a01b038116811461166a57600080fd5b60006020828403121561261c57600080fd5b81356124ab816125f5565b6000806000806080858703121561263d57600080fd5b8435612648816125f5565b93506020850135612658816125f5565b925060408501359150606085013561266f816125f5565b939692955090935050565b600081518084526020808501945080840160005b838110156126be57815180516001600160a01b03168852830151838801526040909601959082019060010161268e565b509495945050505050565b8281526040602082015260006126e2604083018461267a565b949350505050565b6000806000806080858703121561270057600080fd5b843561270b816125f5565b9350602085013561271b816125f5565b93969395505050506040820135916060013590565b60006020828403121561274257600080fd5b813561ffff811681146124ab57600080fd5b6000806000806080858703121561276a57600080fd5b8435612775816125f5565b935060208501359250604085013561278c816125f5565b9396929550929360600135925050565b634e487b7160e01b600052601160045260246000fd5b6000600160ff1b82016127c7576127c761279c565b5060000390565b8181038181111561163d5761163d61279c565b6001600160a01b03939093168352602083019190915261ffff16604082015260600190565b60006020828403121561281857600080fd5b81516124ab816125f5565b60006020828403121561283557600080fd5b5051919050565b60018060a01b038716815285602082015284604082015283606082015282608082015260c060a0820152600061287560c083018461267a565b98975050505050505050565b6001600160a01b0392831681529116602082015260400190565b6020808252601d908201527f53706865726558206572726f723a2061646d696e207265717569726564000000604082015260600190565b8481526001600160a01b03841660208201526060604082018190528101829052818360808301376000818301608090810191909152601f909201601f191601019392505050565b634e487b7160e01b600052604160045260246000fd5b6000602080838503121561294257600080fd5b825167ffffffffffffffff8082111561295a57600080fd5b818501915085601f83011261296e57600080fd5b81518181111561298057612980612919565b8060051b604051601f19603f830116810181811085821117156129a5576129a5612919565b6040529182528482019250838101850191888311156129c357600080fd5b938501935b82851015612875578451845293850193928501926129c8565b600081518084526020808501945080840160005b838110156126be578151875295820195908201906001016129f5565b848152836020820152608060408201526000612a3060808301856129e1565b8281036060840152612a4281856129e1565b979650505050505050565b600a8110612a6b57634e487b7160e01b600052602160045260246000fd5b9052565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a081016125456080830184612a4d565b634e487b7160e01b600052603260045260246000fd5b808202811582820484141761163d5761163d61279c565b600082612aed57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b03929092168252602082015260400190565b600060208284031215612b1d57600080fd5b815180151581146124ab57600080fd5b6001600160a01b0386811682526020820186905284811660408301528316606082015260a081016125456080830184612a4d565b600060018201612b7357612b7361279c565b5060010190565b6000825160005b81811015612b9b5760208186018101518583015201612b81565b50600092019182525091905056feadf90d75f0f2d657d5a22fa0f6e4dabb83c4598b77158eb4119cb38f1d8644633a517dd736309b905c692160a21b5439bdc56db1dc77d6982b66d44814e3fa97ca334bf49ef20e9cbff039feda3bc1c2a853aff17b1b5187e4aa1380ec55829d1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d6a26469706673582212207786a77d42a4991978e5e850a99aaaeba4fe496064a57818f8d1ee06443e28ba64736f6c6343000814003300000000000000000000000062137cec7754aa3f530c98866a86dba36d2687170000000000000000000000006969696969696969696969696969696969696969000000000000000000000000fcbd14dc51f0a4d49d5e53c2e0950e0bc26d0dce000000000000000000000000ff3076c7dd12e427c8548ce9d0a7621a52115b950000000000000000000000005a9c666c7ea0f48e1dc972c0552941d7391fc2380000000000000000000000001cfe31bfa1ac9b28588c91bb4300a1ed032f069f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106101915760003560e01c806399e80f3b116100d7578063c31c9c0711610085578063c31c9c0714610465578063d55be8c614610485578063daba7ef71461049b578063e74b981b146104bb578063e7e5db4f146104db578063e9cbd822146104f0578063eb6d3a1114610518578063f99e63871461054c57600080fd5b806399e80f3b146103c05780639aa9019e146103d5578063a863ff2f146103ea578063a89635bc1461040a578063ab033ea914610425578063afb44e3714610445578063bc063e1a1461024b57600080fd5b8063412736571161013f57806341273657146102ca57806346904840146102ea5780634c6c848f1461030a5780634ee8f8581461032a5780635aa6e6751461034a5780638426b9681461036a5780638f0af4241461037f5780639739c03e1461039f57600080fd5b80630c8106dc146101d557806315a292031461020b57806323af4e171461022b578063257d9bb81461024b5780633218e83a146102745780633c231166146102a25780633c3b1ef6146102b757600080fd5b366101d057336001600160a01b037f000000000000000000000000696969696969696969696969696969696969696916146101ce576101ce6125cb565b005b600080fd5b3480156101e157600080fd5b506004546101f5906001600160a01b031681565b60405161020291906125e1565b60405180910390f35b34801561021757600080fd5b506101ce61022636600461260a565b61056c565b34801561023757600080fd5b506101ce61024636600461260a565b61061c565b34801561025757600080fd5b506102616103e881565b60405161ffff9091168152602001610202565b34801561028057600080fd5b5061029461028f366004612627565b6106cf565b6040516102029291906126c9565b3480156102ae57600080fd5b506101f5610758565b6102946102c53660046126ea565b61077f565b3480156102d657600080fd5b506101ce6102e536600461260a565b610b32565b3480156102f657600080fd5b506005546101f5906001600160a01b031681565b34801561031657600080fd5b506101ce61032536600461260a565b610bd5565b34801561033657600080fd5b506101ce61034536600461260a565b610cd8565b34801561035657600080fd5b506002546101f5906001600160a01b031681565b34801561037657600080fd5b506101ce610d91565b34801561038b57600080fd5b506101ce61039a366004612730565b610e8a565b3480156103ab57600080fd5b506001546102619062010000900461ffff1681565b3480156103cc57600080fd5b506101f5610f3a565b3480156103e157600080fd5b506101f5610f58565b3480156103f657600080fd5b50610294610405366004612754565b610f76565b34801561041657600080fd5b506001546102619061ffff1681565b34801561043157600080fd5b506101ce61044036600461260a565b6111ee565b34801561045157600080fd5b506101ce610460366004612730565b61126e565b34801561047157600080fd5b506003546101f5906001600160a01b031681565b34801561049157600080fd5b5061026161271081565b3480156104a757600080fd5b506101ce6104b636600461260a565b61132a565b3480156104c757600080fd5b506101ce6104d636600461260a565b6113cf565b3480156104e757600080fd5b506101f5611455565b3480156104fc57600080fd5b506001546101f59064010000000090046001600160a01b031681565b34801561052457600080fd5b506101f57f000000000000000000000000696969696969696969696969696969696969696981565b34801561055857600080fd5b50610294610567366004612627565b611473565b6002546001600160a01b0316331461059757604051632d5be4cb60e21b815260040160405180910390fd5b6326b2eef460006105a98260016114c7565b90506105b483611643565b600480546001600160a01b038581166001600160a01b0319831681179093556040519116919082907f82c52d8aa62200dfc997bdf1100b1c2ed614580941b2b8637d10b8ca0428eeec90600090a35061061761060f836127b2565b60018361166d565b505050565b6002546001600160a01b0316331461064757604051632d5be4cb60e21b815260040160405180910390fd5b635b9fdae460006106598260016114c7565b905061066483611643565b60018054640100000000600160c01b0319166401000000006001600160a01b03868116828102939093179384905560405192939190910416907f497b8419a37c8014b1a755ec707f25d11ae4bade591d379f9a4095f37edaf76e90600090a361061761060f836127b2565b600060606307c1e85d63190c741d60e11b836106f88382356001600160e01b03191684146114c7565b90506001600160a01b038616301461071757610714888861178f565b96505b61072389898989611958565b9450945061074c610733846127b2565b6000356001600160e01b0319908116908516148361166d565b50505094509492505050565b600061077a6107766001600080516020612c0a8339815191526127ce565b5490565b905090565b6000606061078b611a62565b63621b094a600061079d8260016114c7565b90506001600160a01b038716610881576103e83410156107e2576000346103e8604051630b722aef60e21b81526004016107d9939291906127e1565b60405180910390fd5b7f00000000000000000000000069696969696969696969696969696969696969696001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b15801561083d57600080fd5b505af1158015610851573d6000803e3d6000fd5b50505050507f000000000000000000000000696969696969696969696969696969696969696996503495506108b9565b6103e88610156108ac5786866103e8604051630b722aef60e21b81526004016107d9939291906127e1565b6108b6878761178f565b95505b6001546000906108cf90899061ffff1689611a8c565b80925081985050506000879050886001600160a01b03168a6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610924573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109489190612806565b6001600160a01b0316146109c8576109c38a6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610997573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109bb9190612806565b8a8a306106cf565b955090505b610a3f8a828c6001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a2f9190612806565b6001600160a01b03169190611ae7565b60405163bc157ac160e01b815260048101829052336024820152604481018890526001600160a01b038b169063bc157ac1906064016020604051808303816000875af1158015610a93573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab79190612823565b9550896001600160a01b0316336001600160a01b03167f87640c2e40d67703e350e7d24d4e416e5c4f1e1550e1285b1bf667440d36bdcf8b8b858b888c604051610b069695949392919061283c565b60405180910390a35050610b1d8261060f906127b2565b5050610b296001600055565b94509492505050565b6002546001600160a01b03163314610b5d57604051632d5be4cb60e21b815260040160405180910390fd5b63d473ef3c6000610b6f8260016114c7565b9050610b7a83611643565b600380546001600160a01b038581166001600160a01b0319831681179093556040519116919082907f5c5b0bb5085481c320dc523e3b3f829eaa807936f615add0077fa213f345090e90600090a35061061761060f836127b2565b610bf16107766001600080516020612baa8339815191526127ce565b6001600160a01b0316336001600160a01b031614610c515760405162461bcd60e51b815260206004820181905260248201527f53706865726558206572726f723a206f70657261746f7220726571756972656460448201526064016107d9565b610c5a81611bb1565b6000610c786107766001600080516020612c0a8339815191526127ce565b9050610c9b610c966001600080516020612c0a8339815191526127ce565b839055565b7ff33499cccaa0611882086224cc48cd82ef54b66a4d2edf4ed67108dd516896d58183604051610ccc929190612881565b60405180910390a15050565b610cf46107766001600080516020612bea8339815191526127ce565b6001600160a01b0316336001600160a01b031614610d245760405162461bcd60e51b81526004016107d99061289b565b6000610d426107766001600080516020612baa8339815191526127ce565b9050610d60610c966001600080516020612baa8339815191526127ce565b7f2ac55ae7ba47db34b5334622acafeb34a65daf143b47019273185d64c73a35a58183604051610ccc929190612881565b33610d9a610f58565b6001600160a01b031614610dff5760405162461bcd60e51b815260206004820152602660248201527f53706865726558206572726f723a206e6f74207468652070656e64696e67206160448201526518d8dbdd5b9d60d21b60648201526084016107d9565b6000610e09610f3a565b9050610e2c610e276001600080516020612bea8339815191526127ce565b339055565b610e4e610e486001600080516020612bca8339815191526127ce565b60009055565b7f67ebaebcd2ca5a91a404e898110f221747e8d15567f2388a34794aab151cf3e68133604051610e7f929190612881565b60405180910390a150565b6002546001600160a01b03163314610eb557604051632d5be4cb60e21b815260040160405180910390fd5b6103e861ffff82161115610eea57604051633c057d7b60e01b815261ffff821660048201526103e860248201526044016107d9565b6001805461ffff83811661ffff1983168117909355604080519190921680825260208201939093527fcd5c26e400cb366bdac1d1cbdec4b428f15bc14a133ecbda85bc6f11f7acb9f19101610ccc565b600061077a6107766001600080516020612bea8339815191526127ce565b600061077a6107766001600080516020612bca8339815191526127ce565b60006060610f82611a62565b63af73b2056000610f948260016114c7565b604051635d043b2960e11b8152600481018990523060248201523360448201529091506000906001600160a01b038a169063ba087652906064016020604051808303816000875af1158015610fed573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110119190612823565b90506001600160a01b038716611045577f000000000000000000000000696969696969696969696969696969696969696996505b866001600160a01b0316896001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561108d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110b19190612806565b6001600160a01b0316036110c75780945061113a565b611134896001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611108573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112c9190612806565b888330611473565b90955093505b600061115788600160029054906101000a900461ffff1688611a8c565b90965090506111668833611c88565b50868610156111a157604051632752fb4960e11b81526001600160a01b038916600482015260248101879052604481018890526064016107d9565b896001600160a01b0316336001600160a01b03167f0bc6c5ccdba0b566b3adbb7c24c419a1b872218cd487d145a4e4eb70b2c8bfb38a89868e878c604051610b069695949392919061283c565b6002546001600160a01b0316331461121957604051632d5be4cb60e21b815260040160405180910390fd5b61122281611643565b600280546001600160a01b0319166001600160a01b03831690811790915560405181907f3aaaebeb4821d6a7e5c77ece53cff0afcc56c82add2c978dbbb7f73e84cbcfd290600090a350565b6002546001600160a01b0316331461129957604051632d5be4cb60e21b815260040160405180910390fd5b6103e861ffff821611156112ce57604051633c057d7b60e01b815261ffff821660048201526103e860248201526044016107d9565b6001805461ffff8381166201000081810263ffff00001985161790945560408051949093049091168084526020840191909152917febcac71ae552a15ae4d23c933603e1a71f47ff8371bdd98194f037156b73a7199101610ccc565b6113466107766001600080516020612bea8339815191526127ce565b6001600160a01b0316336001600160a01b0316146113765760405162461bcd60e51b81526004016107d99061289b565b6113976113926001600080516020612bca8339815191526127ce565b829055565b7f5778f1547abbbb86090a43c32aec38334b31df4beeb6f8f3fa063f593b53a5266113c0610f3a565b82604051610e7f929190612881565b6002546001600160a01b031633146113fa57604051632d5be4cb60e21b815260040160405180910390fd5b61140381611643565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f0bc21fe5c3ab742ff1d15b5c4477ffbacf1167e618228078fa625edebe7f331d90600090a35050565b600061077a6107766001600080516020612baa8339815191526127ce565b6000606063362279f763f99e638760e01b8361149c8382356001600160e01b03191684146114c7565b90506001600160a01b03861630146114bb576114b8898861178f565b96505b61072389898989611d19565b6114fb604051806080016040528060608152602001606081526020016000815260200160006001600160a01b031681525090565b6000611505610758565b6001600160a01b03161461163d57600061151d610758565b905082156115a657604051634492e52d60e11b81526001600160a01b03821690638925ca5a90611558908790339060009036906004016128d2565b6000604051808303816000875af1158015611577573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261159f919081019061292f565b8252611618565b604051633e88494360e01b8152600481018590526001600160a01b03821690633e884943906024016000604051808303816000875af11580156115ed573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611615919081019061292f565b82525b815161162390611dda565b60208301525a60408301526001600160a01b031660608201525b92915050565b6001600160a01b03811661166a5760405163d92e233d60e01b815260040160405180910390fd5b50565b60608101516001600160a01b0381166116865750505050565b60005a836040015161169891906127ce565b905060606116a98460000151611dda565b9050841561171e576020840151604051631e17b28d60e31b81526001600160a01b0385169163f0bd9468916116e7918a918791908790600401612a11565b600060405180830381600087803b15801561170157600080fd5b505af1158015611715573d6000803e3d6000fd5b50505050611787565b602084015160405163027313cd60e11b81526001600160a01b038516916304e6279a91611754918a918791908790600401612a11565b600060405180830381600087803b15801561176e57600080fd5b505af1158015611782573d6000803e3d6000fd5b505050505b505050505050565b6000639ffc466160006117a38260006114c7565b905083856001600160a01b031663dd62ed3e33306040518363ffffffff1660e01b81526004016117d4929190612881565b602060405180830381865afa1580156117f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118159190612823565b1015611834576040516332da96a360e01b815260040160405180910390fd5b6040516370a0823160e01b81526000906001600160a01b038716906370a08231906118639030906004016125e1565b602060405180830381865afa158015611880573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118a49190612823565b90506118bb6001600160a01b038716333088611e91565b6040516370a0823160e01b81526000906001600160a01b038816906370a08231906118ea9030906004016125e1565b602060405180830381865afa158015611907573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061192b9190612823565b905061193782826127ce565b945050505b611950611948836127b2565b60008361166d565b505092915050565b600454600090606090611978906001600160a01b03878116911686611eca565b6004805460405163190a4d4960e01b81526001600160a01b039091169163190a4d49916119b0918a918a918a918a9160059101612a6f565b6020604051808303816000875af11580156119cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119f39190612823565b60408051600180825281830190925291935060009190602080830190803683370190505090508581600081518110611a2d57611a2d612aa3565b60200260200101906001600160a01b031690816001600160a01b031681525050611a5681611ef0565b91505094509492505050565b600260005403611a8557604051633ee5aeb560e01b815260040160405180910390fd5b6002600055565b60008061ffff841615611adc57612710611aaa61ffff861685612ab9565b611ab49190612ad0565b600554909150611acf9086906001600160a01b031683612241565b611ad981846127ce565b92505b829150935093915050565b6000836001600160a01b031663095ea7b38484604051602401611b0b929190612af2565b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050509050611b44848261239b565b611bab57611ba184856001600160a01b031663095ea7b3866000604051602401611b6f929190612af2565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050612443565b611bab8482612443565b50505050565b6001600160a01b0381161580611c3157506040516301ffc9a760e01b81526329f20dd560e11b60048201526001600160a01b038216906301ffc9a790602401602060405180830381865afa158015611c0d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c319190612b0b565b61166a5760405162461bcd60e51b815260206004820152602260248201527f53706865726558206572726f723a206e6f7420612053706865726558456e67696044820152616e6560f01b60648201526084016107d9565b600063f45372f86000611c9c8260006114c7565b6040516370a0823160e01b81529091506001600160a01b038616906370a0823190611ccb9030906004016125e1565b602060405180830381865afa158015611ce8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d0c9190612823565b925061193c858585612241565b600454600090606090611d39906001600160a01b03888116911686611eca565b6004805460405163616a3dbd60e11b81526001600160a01b039091169163c2d47b7a91611d71918a91899189918c9160059101612b2d565b6020604051808303816000875af1158015611d90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db49190612823565b91506001600160a01b0383163014610b2957611dd08584611c88565b5094509492505050565b805160609060008167ffffffffffffffff811115611dfa57611dfa612919565b604051908082528060200260200182016040528015611e23578160200160208202803683370190505b50905060005b82811015611e89576000858281518110611e4557611e45612aa3565b6020026020010151905060008154905080848481518110611e6857611e68612aa3565b60200260200101818152505050508080611e8190612b61565b915050611e29565b509392505050565b6040516001600160a01b038481166024830152838116604483015260648201839052611bab9186918216906323b872dd90608401611b6f565b61061783846001600160a01b031663a9059cbb8585604051602401611b6f929190612af2565b60606365afacc16000611f048260006114c7565b90506000845167ffffffffffffffff811115611f2257611f22612919565b604051908082528060200260200182016040528015611f6757816020015b6040805180820190915260008082526020820152815260200190600190039081611f405790505b50935060005b855181101561222b5760006001600160a01b0316868281518110611f9357611f93612aa3565b60200260200101516001600160a01b0316031561221957858181518110611fbc57611fbc612aa3565b60200260200101516001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401611fef91906125e1565b602060405180830381865afa15801561200c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120309190612823565b9150604051806040016040528087838151811061204f5761204f612aa3565b60200260200101516001600160a01b031681526020018381525085828151811061207b5761207b612aa3565b60209081029190910101528115612219577f00000000000000000000000069696969696969696969696969696969696969696001600160a01b03168682815181106120c8576120c8612aa3565b60200260200101516001600160a01b0316036121e257604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000069696969696969696969696969696969696969696001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561214057600080fd5b505af1158015612154573d6000803e3d6000fd5b50506040805160008082526020820192839052935033925085916121789190612b7a565b60006040518083038185875af1925050503d80600081146121b5576040519150601f19603f3d011682016040523d82523d6000602084013e6121ba565b606091505b50509050806121dc5760405163b12d13eb60e01b815260040160405180910390fd5b50612219565b61221933838884815181106121f9576121f9612aa3565b60200260200101516001600160a01b0316611eca9092919063ffffffff16565b8061222381612b61565b915050611f6d565b505061223a82611948906127b2565b5050919050565b8015610617577f00000000000000000000000069696969696969696969696969696969696969696001600160a01b0316836001600160a01b03160361238757604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000069696969696969696969696969696969696969696001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156122e257600080fd5b505af11580156122f6573d6000803e3d6000fd5b5050604080516000808252602082019283905293506001600160a01b038616925084916123239190612b7a565b60006040518083038185875af1925050503d8060008114612360576040519150601f19603f3d011682016040523d82523d6000602084013e612365565b606091505b5050905080611bab5760405163b12d13eb60e01b815260040160405180910390fd5b6106176001600160a01b0384168383611eca565b6000806000846001600160a01b0316846040516123b89190612b7a565b6000604051808303816000865af19150503d80600081146123f5576040519150601f19603f3d011682016040523d82523d6000602084013e6123fa565b606091505b50915091508180156124245750805115806124245750808060200190518101906124249190612b0b565b801561243a57506000856001600160a01b03163b115b95945050505050565b60006124586001600160a01b0384168361249d565b9050805160001415801561247d57508080602001905181019061247b9190612b0b565b155b156106175782604051635274afe760e01b81526004016107d991906125e1565b60606124ab838360006124b2565b9392505050565b6060814710156124d7573060405163cd78605960e01b81526004016107d991906125e1565b600080856001600160a01b031684866040516124f39190612b7a565b60006040518083038185875af1925050503d8060008114612530576040519150601f19603f3d011682016040523d82523d6000602084013e612535565b606091505b509150915061254586838361254f565b9695505050505050565b6060826125645761255f826125a2565b6124ab565b815115801561257b57506001600160a01b0384163b155b1561259b5783604051639996b31560e01b81526004016107d991906125e1565b50806124ab565b8051156125b25780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b600052600160045260246000fd5b6001600160a01b0391909116815260200190565b6001600160a01b038116811461166a57600080fd5b60006020828403121561261c57600080fd5b81356124ab816125f5565b6000806000806080858703121561263d57600080fd5b8435612648816125f5565b93506020850135612658816125f5565b925060408501359150606085013561266f816125f5565b939692955090935050565b600081518084526020808501945080840160005b838110156126be57815180516001600160a01b03168852830151838801526040909601959082019060010161268e565b509495945050505050565b8281526040602082015260006126e2604083018461267a565b949350505050565b6000806000806080858703121561270057600080fd5b843561270b816125f5565b9350602085013561271b816125f5565b93969395505050506040820135916060013590565b60006020828403121561274257600080fd5b813561ffff811681146124ab57600080fd5b6000806000806080858703121561276a57600080fd5b8435612775816125f5565b935060208501359250604085013561278c816125f5565b9396929550929360600135925050565b634e487b7160e01b600052601160045260246000fd5b6000600160ff1b82016127c7576127c761279c565b5060000390565b8181038181111561163d5761163d61279c565b6001600160a01b03939093168352602083019190915261ffff16604082015260600190565b60006020828403121561281857600080fd5b81516124ab816125f5565b60006020828403121561283557600080fd5b5051919050565b60018060a01b038716815285602082015284604082015283606082015282608082015260c060a0820152600061287560c083018461267a565b98975050505050505050565b6001600160a01b0392831681529116602082015260400190565b6020808252601d908201527f53706865726558206572726f723a2061646d696e207265717569726564000000604082015260600190565b8481526001600160a01b03841660208201526060604082018190528101829052818360808301376000818301608090810191909152601f909201601f191601019392505050565b634e487b7160e01b600052604160045260246000fd5b6000602080838503121561294257600080fd5b825167ffffffffffffffff8082111561295a57600080fd5b818501915085601f83011261296e57600080fd5b81518181111561298057612980612919565b8060051b604051601f19603f830116810181811085821117156129a5576129a5612919565b6040529182528482019250838101850191888311156129c357600080fd5b938501935b82851015612875578451845293850193928501926129c8565b600081518084526020808501945080840160005b838110156126be578151875295820195908201906001016129f5565b848152836020820152608060408201526000612a3060808301856129e1565b8281036060840152612a4281856129e1565b979650505050505050565b600a8110612a6b57634e487b7160e01b600052602160045260246000fd5b9052565b6001600160a01b0386811682528581166020830152604082018590528316606082015260a081016125456080830184612a4d565b634e487b7160e01b600052603260045260246000fd5b808202811582820484141761163d5761163d61279c565b600082612aed57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b03929092168252602082015260400190565b600060208284031215612b1d57600080fd5b815180151581146124ab57600080fd5b6001600160a01b0386811682526020820186905284811660408301528316606082015260a081016125456080830184612a4d565b600060018201612b7357612b7361279c565b5060010190565b6000825160005b81811015612b9b5760208186018101518583015201612b81565b50600092019182525091905056feadf90d75f0f2d657d5a22fa0f6e4dabb83c4598b77158eb4119cb38f1d8644633a517dd736309b905c692160a21b5439bdc56db1dc77d6982b66d44814e3fa97ca334bf49ef20e9cbff039feda3bc1c2a853aff17b1b5187e4aa1380ec55829d1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d6a26469706673582212207786a77d42a4991978e5e850a99aaaeba4fe496064a57818f8d1ee06443e28ba64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000062137cec7754aa3f530c98866a86dba36d2687170000000000000000000000006969696969696969696969696969696969696969000000000000000000000000fcbd14dc51f0a4d49d5e53c2e0950e0bc26d0dce000000000000000000000000ff3076c7dd12e427c8548ce9d0a7621a52115b950000000000000000000000005a9c666c7ea0f48e1dc972c0552941d7391fc2380000000000000000000000001cfe31bfa1ac9b28588c91bb4300a1ed032f069f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : devAddress (address): 0x62137cEc7754aA3f530c98866a86dba36d268717
Arg [1] : wrappedNative (address): 0x6969696969696969696969696969696969696969
Arg [2] : stablecoin (address): 0xFCBD14DC51f0A4d49d5E53C2E0950e0bC26d0Dce
Arg [3] : swapRouter (address): 0xff3076c7dD12e427C8548cE9d0a7621a52115b95
Arg [4] : lpRouter (address): 0x5A9c666c7eA0f48E1Dc972C0552941d7391fc238
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] : 000000000000000000000000ff3076c7dd12e427c8548ce9d0a7621a52115b95
Arg [4] : 0000000000000000000000005a9c666c7ea0f48e1dc972c0552941d7391fc238
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.