More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 5,715 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Zap Bridge | 18504747 | 383 days ago | IN | 0 ETH | 0.00528849 | ||||
Zap Bridge | 15559996 | 796 days ago | IN | 0.002 ETH | 0.00030691 | ||||
Zap Bridge | 15427807 | 817 days ago | IN | 0.00081382 ETH | 0.00005919 | ||||
Zap Bridge | 15202273 | 852 days ago | IN | 0.001 ETH | 0.00054994 | ||||
Zap Bridge | 14325534 | 993 days ago | IN | 0 ETH | 0.00341177 | ||||
Zap Bridge | 14138724 | 1022 days ago | IN | 0.00008 ETH | 0.01031453 | ||||
Zap Bridge | 14085625 | 1030 days ago | IN | 0.42 ETH | 0.02128188 | ||||
Zap Bridge | 14085149 | 1030 days ago | IN | 0.03658 ETH | 0.03266041 | ||||
Zap Bridge | 14084023 | 1031 days ago | IN | 0.11 ETH | 0.02629477 | ||||
Zap Bridge | 14081122 | 1031 days ago | IN | 1 ETH | 0.02619284 | ||||
Zap Bridge | 14079908 | 1031 days ago | IN | 0.18 ETH | 0.02450738 | ||||
Zap Bridge | 14079709 | 1031 days ago | IN | 0.05 ETH | 0.02189921 | ||||
Zap Bridge | 14077326 | 1032 days ago | IN | 0.55 ETH | 0.03602193 | ||||
Zap Bridge | 14077145 | 1032 days ago | IN | 0.5 ETH | 0.06198737 | ||||
Zap Bridge | 14076268 | 1032 days ago | IN | 0.008 ETH | 0.00346197 | ||||
Zap Bridge | 14076151 | 1032 days ago | IN | 0.3 ETH | 0.04913031 | ||||
Zap Bridge | 14076027 | 1032 days ago | IN | 0 ETH | 0.04702631 | ||||
Zap Bridge | 14075716 | 1032 days ago | IN | 0 ETH | 0.02471024 | ||||
Zap Bridge | 14074687 | 1032 days ago | IN | 0 ETH | 0.03343148 | ||||
Zap Bridge | 14074422 | 1032 days ago | IN | 0 ETH | 0.01464049 | ||||
Zap Bridge | 14073692 | 1032 days ago | IN | 0.152 ETH | 0.02222892 | ||||
Zap Bridge | 14073593 | 1032 days ago | IN | 0 ETH | 0.02499515 | ||||
Zap Bridge | 14073104 | 1032 days ago | IN | 0 ETH | 0.02383211 | ||||
Zap Bridge | 14072198 | 1032 days ago | IN | 0.07 ETH | 0.02570849 | ||||
Zap Bridge | 14070294 | 1033 days ago | IN | 0.169 ETH | 0.03133855 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
15559996 | 796 days ago | 0.002 ETH | ||||
15202273 | 852 days ago | 0.001 ETH | ||||
14325534 | 993 days ago | 0.03990609 ETH | ||||
14138724 | 1022 days ago | 0.00008 ETH | ||||
14085625 | 1030 days ago | 0.42 ETH | ||||
14085149 | 1030 days ago | 0.03658 ETH | ||||
14084023 | 1031 days ago | 0.11 ETH | ||||
14081122 | 1031 days ago | 1 ETH | ||||
14079908 | 1031 days ago | 0.18 ETH | ||||
14079709 | 1031 days ago | 0.05 ETH | ||||
14077326 | 1032 days ago | 0.55 ETH | ||||
14077145 | 1032 days ago | 0.5 ETH | ||||
14076151 | 1032 days ago | 0.3 ETH | ||||
14073692 | 1032 days ago | 0.152 ETH | ||||
14073104 | 1032 days ago | 0.27200388 ETH | ||||
14073104 | 1032 days ago | 0.27200388 ETH | ||||
14072198 | 1032 days ago | 0.07 ETH | ||||
14070294 | 1033 days ago | 0.169 ETH | ||||
14029456 | 1039 days ago | 0.035 ETH | ||||
14028786 | 1039 days ago | 0.08 ETH | ||||
14027361 | 1039 days ago | 0.04 ETH | ||||
14027247 | 1039 days ago | 1.66141 ETH | ||||
14026640 | 1039 days ago | 0.25 ETH | ||||
14026639 | 1039 days ago | 0.005 ETH | ||||
14026558 | 1039 days ago | 0.32 ETH |
Loading...
Loading
Contract Name:
Zapper_Matic_Bridge_V1_1
Compiler Version
v0.8.4+commit.c7e474f2
Contract Source Code (Solidity Standard Json-Input format)
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // Copyright (C) 2021 zapper // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // ///@author Zapper ///@notice This contract swaps and bridges ETH/Tokens to Matic/Polygon // SPDX-License-Identifier: GPLv2 pragma solidity ^0.8.0; import "../../_base/ZapBaseV2.sol"; // PoS Bridge interface IRootChainManager { function depositEtherFor(address user) external payable; function depositFor( address user, address rootToken, bytes calldata depositData ) external; function tokenToType(address) external returns (bytes32); function typeToPredicate(bytes32) external returns (address); } // Plasma Bridge interface IDepositManager { function depositERC20ForUser( address _token, address _user, uint256 _amount ) external; } interface IWETH { function deposit() external payable; } contract Zapper_Matic_Bridge_V1_1 is ZapBaseV2 { using SafeERC20 for IERC20; address private constant wethTokenAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; IRootChainManager public rootChainManager = IRootChainManager(0xA0c68C638235ee32657e8f720a23ceC1bFc77C77); IDepositManager public depositManager = IDepositManager(0x401F6c983eA34274ec46f84D70b31C151321188b); address private constant maticAddress = 0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0; constructor(uint256 _goodwill, uint256 _affiliateSplit) ZapBaseV2(_goodwill, _affiliateSplit) { _approveToken(maticAddress, address(depositManager)); approvedTargets[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] = true; } /** @notice Bridge from Ethereum to Matic @notice Use index 0 for primary swap and index 1 for matic swap @param fromToken Address of the token to swap from @param toToken Address of the token to bridge @param swapAmounts Quantites of fromToken to swap to toToken and matic @param minTokensRec Minimum acceptable quantity of swapped tokens and/or matic @param swapTargets Execution targets for swaps @param swapData DEX swap data @param affiliate Affiliate address */ function ZapBridge( address fromToken, address toToken, uint256[2] calldata swapAmounts, uint256[2] calldata minTokensRec, address[2] calldata swapTargets, bytes[2] calldata swapData, address affiliate ) external payable stopInEmergency { uint256[2] memory toInvest = _pullTokens(fromToken, swapAmounts, affiliate); if (swapAmounts[0] > 0) { // Token swap uint256 toTokenAmt = _fillQuote( fromToken, toInvest[0], toToken, swapTargets[0], swapData[0] ); require(toTokenAmt >= minTokensRec[0], "ERR: High Slippage 1"); _bridgeToken(toToken, toTokenAmt); } // Matic swap if (swapAmounts[1] > 0) { uint256 maticAmount = _fillQuote( fromToken, toInvest[1], maticAddress, swapTargets[1], swapData[1] ); require(maticAmount >= minTokensRec[1], "ERR: High Slippage 2"); _bridgeMatic(maticAmount); } } function _bridgeToken(address toToken, uint256 toTokenAmt) internal { if (toToken == address(0)) { rootChainManager.depositEtherFor{ value: toTokenAmt }(msg.sender); } else { bytes32 tokenType = rootChainManager.tokenToType(toToken); address predicate = rootChainManager.typeToPredicate(tokenType); _approveToken(toToken, predicate); rootChainManager.depositFor( msg.sender, toToken, abi.encode(toTokenAmt) ); } } function _bridgeMatic(uint256 maticAmount) internal { depositManager.depositERC20ForUser( maticAddress, msg.sender, maticAmount ); } // 0x Swap function _fillQuote( address fromToken, uint256 amount, address toToken, address swapTarget, bytes memory swapCallData ) internal returns (uint256 amtBought) { if (fromToken == wethTokenAddress && toToken == address(0)) { IWETH(wethTokenAddress).deposit{ value: amount }(); return amount; } uint256 valueToSend; if (fromToken == toToken) { return amount; } if (fromToken == address(0)) { valueToSend = amount; } else { _approveToken(fromToken, swapTarget); } uint256 iniBal = _getBalance(toToken); require(approvedTargets[swapTarget], "Target not Authorized"); (bool success, ) = swapTarget.call{ value: valueToSend }(swapCallData); require(success, "Error Swapping Tokens"); uint256 finalBal = _getBalance(toToken); amtBought = finalBal - iniBal; } function _pullTokens( address fromToken, uint256[2] memory swapAmounts, address affiliate ) internal returns (uint256[2] memory toInvest) { if (fromToken == address(0)) { require(msg.value > 0, "No eth sent"); require( swapAmounts[0] + (swapAmounts[1]) == msg.value, "msg.value != fromTokenAmounts" ); } else { require(msg.value == 0, "Eth sent with token"); // transfer token IERC20(fromToken).safeTransferFrom( msg.sender, address(this), swapAmounts[0] + (swapAmounts[1]) ); } if (swapAmounts[0] > 0) { toInvest[0] = swapAmounts[0] - (_subtractGoodwill(fromToken, swapAmounts[0], affiliate)); } if (swapAmounts[1] > 0) { toInvest[1] = swapAmounts[1] - (_subtractGoodwill(fromToken, swapAmounts[1], affiliate)); } } function _subtractGoodwill( address token, uint256 amount, address affiliate ) internal returns (uint256 totalGoodwillPortion) { bool whitelisted = feeWhitelist[msg.sender]; if (!whitelisted && goodwill > 0) { totalGoodwillPortion = (amount * goodwill) / 10000; if (affiliates[affiliate]) { if (token == address(0)) { token = ETHAddress; } uint256 affiliatePortion = (totalGoodwillPortion * affiliateSplit) / 100; affiliateBalance[affiliate][token] += affiliatePortion; totalAffiliateBalance[token] += affiliatePortion; } } } }
// SPDX-License-Identifier: GPL-2.0 pragma solidity ^0.8.0; import "../oz/0.8.0/access/Ownable.sol"; import "../oz/0.8.0/token/ERC20/utils/SafeERC20.sol"; abstract contract ZapBaseV2 is Ownable { using SafeERC20 for IERC20; bool public stopped = false; // if true, goodwill is not deducted mapping(address => bool) public feeWhitelist; uint256 public goodwill; // % share of goodwill (0-100 %) uint256 affiliateSplit; // restrict affiliates mapping(address => bool) public affiliates; // affiliate => token => amount mapping(address => mapping(address => uint256)) public affiliateBalance; // token => amount mapping(address => uint256) public totalAffiliateBalance; // swapTarget => approval status mapping(address => bool) public approvedTargets; address internal constant ETHAddress = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; constructor(uint256 _goodwill, uint256 _affiliateSplit) { goodwill = _goodwill; affiliateSplit = _affiliateSplit; } // circuit breaker modifiers modifier stopInEmergency { if (stopped) { revert("Temporarily Paused"); } else { _; } } function _getBalance(address token) internal view returns (uint256 balance) { if (token == address(0)) { balance = address(this).balance; } else { balance = IERC20(token).balanceOf(address(this)); } } function _approveToken(address token, address spender) internal { IERC20 _token = IERC20(token); if (_token.allowance(address(this), spender) > 0) return; else { _token.safeApprove(spender, type(uint256).max); } } function _approveToken( address token, address spender, uint256 amount ) internal { IERC20(token).safeApprove(spender, 0); IERC20(token).safeApprove(spender, amount); } // - to Pause the contract function toggleContractActive() public onlyOwner { stopped = !stopped; } function set_feeWhitelist(address zapAddress, bool status) external onlyOwner { feeWhitelist[zapAddress] = status; } function set_new_goodwill(uint256 _new_goodwill) public onlyOwner { require( _new_goodwill >= 0 && _new_goodwill <= 100, "GoodWill Value not allowed" ); goodwill = _new_goodwill; } function set_new_affiliateSplit(uint256 _new_affiliateSplit) external onlyOwner { require( _new_affiliateSplit <= 100, "Affiliate Split Value not allowed" ); affiliateSplit = _new_affiliateSplit; } function set_affiliate(address _affiliate, bool _status) external onlyOwner { affiliates[_affiliate] = _status; } ///@notice Withdraw goodwill share, retaining affilliate share function withdrawTokens(address[] calldata tokens) external onlyOwner { for (uint256 i = 0; i < tokens.length; i++) { uint256 qty; if (tokens[i] == ETHAddress) { qty = address(this).balance - totalAffiliateBalance[tokens[i]]; Address.sendValue(payable(owner()), qty); } else { qty = IERC20(tokens[i]).balanceOf(address(this)) - totalAffiliateBalance[tokens[i]]; IERC20(tokens[i]).safeTransfer(owner(), qty); } } } ///@notice Withdraw affilliate share, retaining goodwill share function affilliateWithdraw(address[] calldata tokens) external { uint256 tokenBal; for (uint256 i = 0; i < tokens.length; i++) { tokenBal = affiliateBalance[msg.sender][tokens[i]]; affiliateBalance[msg.sender][tokens[i]] = 0; totalAffiliateBalance[tokens[i]] = totalAffiliateBalance[tokens[i]] - tokenBal; if (tokens[i] == ETHAddress) { Address.sendValue(payable(msg.sender), tokenBal); } else { IERC20(tokens[i]).safeTransfer(msg.sender, tokenBal); } } } function setApprovedTargets( address[] calldata targets, bool[] calldata isApproved ) external onlyOwner { require(targets.length == isApproved.length, "Invalid Input length"); for (uint256 i = 0; i < targets.length; i++) { approvedTargets[targets[i]] = isApproved[i]; } } receive() external payable { require(msg.sender != tx.origin, "Do not send ETH directly"); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require( newOwner != address(0), "Ownable: new owner is the zero address" ); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../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; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn( token, abi.encodeWithSelector(token.transfer.selector, to, value) ); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn( token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value) ); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn( token, abi.encodeWithSelector(token.approve.selector, spender, value) ); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn( token, abi.encodeWithSelector( token.approve.selector, spender, newAllowance ) ); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require( oldAllowance >= value, "SafeERC20: decreased allowance below zero" ); uint256 newAllowance = oldAllowance - value; _callOptionalReturn( token, abi.encodeWithSelector( token.approve.selector, spender, newAllowance ) ); } } /** * @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, "SafeERC20: low-level call failed" ); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require( abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed" ); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) 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 `amount` 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 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @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 ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require( address(this).balance >= amount, "Address: insufficient balance" ); // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{ value: amount }(""); require( success, "Address: unable to send value, recipient may have reverted" ); } /** * @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, it is bubbled up by this * function (like regular Solidity function calls). * * 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. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @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`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue( target, data, value, "Address: low-level call with value failed" ); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require( address(this).balance >= value, "Address: insufficient balance for call" ); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall( target, data, "Address: low-level static call failed" ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall( target, data, "Address: low-level delegate call failed" ); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) private pure returns (bytes memory) { if (success) { return returndata; } else { // 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 // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: GPL-2.0 pragma solidity ^0.8.0; import "./ZapBaseV2.sol"; abstract contract ZapOutBaseV3 is ZapBaseV2 { using SafeERC20 for IERC20; /** @dev Transfer tokens from msg.sender to this contract @param token The ERC20 token to transfer to this contract @param shouldSellEntireBalance If True transfers entrire allowable amount from another contract @return Quantity of tokens transferred to this contract */ function _pullTokens( address token, uint256 amount, bool shouldSellEntireBalance ) internal returns (uint256) { if (shouldSellEntireBalance) { require( Address.isContract(msg.sender), "ERR: shouldSellEntireBalance is true for EOA" ); uint256 allowance = IERC20(token).allowance(msg.sender, address(this)); IERC20(token).safeTransferFrom( msg.sender, address(this), allowance ); return allowance; } else { IERC20(token).safeTransferFrom(msg.sender, address(this), amount); return amount; } } function _subtractGoodwill( address token, uint256 amount, address affiliate, bool enableGoodwill ) internal returns (uint256 totalGoodwillPortion) { bool whitelisted = feeWhitelist[msg.sender]; if (enableGoodwill && !whitelisted && goodwill > 0) { totalGoodwillPortion = (amount * goodwill) / 10000; if (affiliates[affiliate]) { if (token == address(0)) { token = ETHAddress; } uint256 affiliatePortion = (totalGoodwillPortion * affiliateSplit) / 100; affiliateBalance[affiliate][token] += affiliatePortion; totalAffiliateBalance[token] += affiliatePortion; } } } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // Copyright (C) 2021 zapper // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // Visit <https://www.gnu.org/licenses/>for a copy of the GNU Affero General Public License ///@author Zapper ///@notice this contract implements one click removal of liquidity from UniswapV2 pools, receiving ETH, ERC20 or both. // SPDX-License-Identifier: GPL-2.0 pragma solidity ^0.8.0; import "../_base/ZapOutBaseV3.sol"; interface IUniswapV2Factory { function getPair(address tokenA, address tokenB) external view returns (address pair); } interface IUniswapV2Router02 { function WETH() external pure returns (address); function removeLiquidity( address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns (uint256 amountA, uint256 amountB); function removeLiquidityETH( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external returns (uint256 amountToken, uint256 amountETH); } interface IUniswapV2Pair { function token0() external pure returns (address); function token1() external pure returns (address); function balanceOf(address user) external view returns (uint256); function totalSupply() external view returns (uint256); function getReserves() external view returns ( uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast ); function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; } interface IWETH { function withdraw(uint256 wad) external; } contract UniswapV2_ZapOut_General_V4_0_1 is ZapOutBaseV3 { using SafeERC20 for IERC20; uint256 private constant deadline = 0xf000000000000000000000000000000000000000000000000000000000000000; IUniswapV2Router02 private constant uniswapV2Router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); IUniswapV2Factory private constant uniswapFactory = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f); address private constant wethTokenAddress = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); constructor(uint256 _goodwill, uint256 _affiliateSplit) ZapBaseV2(_goodwill, _affiliateSplit) { // 0x exchange approvedTargets[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] = true; } event zapOut( address sender, address pool, address token, uint256 tokensRec ); /** @notice Zap out in both tokens @param fromPoolAddress Pool from which to remove liquidity @param incomingLP Quantity of LP to remove from pool @param affiliate Affiliate address @return amountA Quantity of tokenA received after zapout @return amountB Quantity of tokenB received after zapout */ function ZapOut2PairToken( address fromPoolAddress, uint256 incomingLP, address affiliate ) public stopInEmergency returns (uint256 amountA, uint256 amountB) { IUniswapV2Pair pair = IUniswapV2Pair(fromPoolAddress); require(address(pair) != address(0), "Pool Cannot be Zero Address"); // get reserves address token0 = pair.token0(); address token1 = pair.token1(); IERC20(fromPoolAddress).safeTransferFrom( msg.sender, address(this), incomingLP ); _approveToken(fromPoolAddress, address(uniswapV2Router), incomingLP); if (token0 == wethTokenAddress || token1 == wethTokenAddress) { address _token = token0 == wethTokenAddress ? token1 : token0; (amountA, amountB) = uniswapV2Router.removeLiquidityETH( _token, incomingLP, 1, 1, address(this), deadline ); // subtract goodwill uint256 tokenGoodwill = _subtractGoodwill(_token, amountA, affiliate, true); uint256 ethGoodwill = _subtractGoodwill(ETHAddress, amountB, affiliate, true); // send tokens IERC20(_token).safeTransfer(msg.sender, amountA - tokenGoodwill); Address.sendValue(payable(msg.sender), amountB - ethGoodwill); } else { (amountA, amountB) = uniswapV2Router.removeLiquidity( token0, token1, incomingLP, 1, 1, address(this), deadline ); // subtract goodwill uint256 tokenAGoodwill = _subtractGoodwill(token0, amountA, affiliate, true); uint256 tokenBGoodwill = _subtractGoodwill(token1, amountB, affiliate, true); // send tokens IERC20(token0).safeTransfer(msg.sender, amountA - tokenAGoodwill); IERC20(token1).safeTransfer(msg.sender, amountB - tokenBGoodwill); } emit zapOut(msg.sender, fromPoolAddress, token0, amountA); emit zapOut(msg.sender, fromPoolAddress, token1, amountB); } /** @notice Zap out in a single token @param toTokenAddress Address of desired token @param fromPoolAddress Pool from which to remove liquidity @param incomingLP Quantity of LP to remove from pool @param minTokensRec Minimum quantity of tokens to receive @param swapTargets Execution targets for swaps @param swapData DEX swap data @param affiliate Affiliate address @param shouldSellEntireBalance If True transfers entrire allowable amount from another contract */ function ZapOut( address toTokenAddress, address fromPoolAddress, uint256 incomingLP, uint256 minTokensRec, address[] memory swapTargets, bytes[] memory swapData, address affiliate, bool shouldSellEntireBalance ) public stopInEmergency returns (uint256 tokensRec) { (uint256 amount0, uint256 amount1) = _removeLiquidity( fromPoolAddress, incomingLP, shouldSellEntireBalance ); //swaps tokens to token tokensRec = _swapTokens( fromPoolAddress, amount0, amount1, toTokenAddress, swapTargets, swapData ); require(tokensRec >= minTokensRec, "High Slippage"); uint256 totalGoodwillPortion; // transfer toTokens to sender if (toTokenAddress == address(0)) { totalGoodwillPortion = _subtractGoodwill( ETHAddress, tokensRec, affiliate, true ); payable(msg.sender).transfer(tokensRec - totalGoodwillPortion); } else { totalGoodwillPortion = _subtractGoodwill( toTokenAddress, tokensRec, affiliate, true ); IERC20(toTokenAddress).safeTransfer( msg.sender, tokensRec - totalGoodwillPortion ); } tokensRec = tokensRec - totalGoodwillPortion; emit zapOut(msg.sender, fromPoolAddress, toTokenAddress, tokensRec); return tokensRec; } /** @notice Zap out in both tokens with permit @param fromPoolAddress Pool from which to remove liquidity @param incomingLP Quantity of LP to remove from pool @param affiliate Affiliate address to share fees @param permitData Encoded permit data, which contains owner, spender, value, deadline, r,s,v values @return amountA Quantity of tokenA received @return amountB Quantity of tokenB received */ function ZapOut2PairTokenWithPermit( address fromPoolAddress, uint256 incomingLP, address affiliate, bytes calldata permitData ) external stopInEmergency returns (uint256 amountA, uint256 amountB) { // permit _validatePool(fromPoolAddress); (bool success, ) = fromPoolAddress.call(permitData); require(success, "Could Not Permit"); (amountA, amountB) = ZapOut2PairToken( fromPoolAddress, incomingLP, affiliate ); } /** @notice Zap out in a single token with permit @param toTokenAddress Address of desired token @param fromPoolAddress Pool from which to remove liquidity @param incomingLP Quantity of LP to remove from pool @param minTokensRec Minimum quantity of tokens to receive @param swapTargets Execution targets for swaps @param swapData DEX swap data @param affiliate Affiliate address */ function ZapOutWithPermit( address toTokenAddress, address fromPoolAddress, uint256 incomingLP, uint256 minTokensRec, bytes memory permitData, address[] memory swapTargets, bytes[] memory swapData, address affiliate ) public stopInEmergency returns (uint256) { // permit _validatePool(fromPoolAddress); (bool success, ) = fromPoolAddress.call(permitData); require(success, "Could Not Permit"); return ( ZapOut( toTokenAddress, fromPoolAddress, incomingLP, minTokensRec, swapTargets, swapData, affiliate, false ) ); } function _validatePool(address poolAddress) internal view { IUniswapV2Pair pair = IUniswapV2Pair(poolAddress); address token0 = pair.token0(); address token1 = pair.token1(); address retrievedAddress = uniswapFactory.getPair(token0, token1); require(retrievedAddress == poolAddress, "Invalid Pool Address"); } function _removeLiquidity( address fromPoolAddress, uint256 incomingLP, bool shouldSellEntireBalance ) internal returns (uint256 amount0, uint256 amount1) { IUniswapV2Pair pair = IUniswapV2Pair(fromPoolAddress); require(address(pair) != address(0), "Pool Cannot be Zero Address"); address token0 = pair.token0(); address token1 = pair.token1(); _pullTokens(fromPoolAddress, incomingLP, shouldSellEntireBalance); _approveToken(fromPoolAddress, address(uniswapV2Router), incomingLP); (amount0, amount1) = uniswapV2Router.removeLiquidity( token0, token1, incomingLP, 1, 1, address(this), deadline ); require(amount0 > 0 && amount1 > 0, "Removed Insufficient Liquidity"); } function _swapTokens( address fromPoolAddress, uint256 amount0, uint256 amount1, address toToken, address[] memory swapTargets, bytes[] memory swapData ) internal returns (uint256 tokensBought) { address token0 = IUniswapV2Pair(fromPoolAddress).token0(); address token1 = IUniswapV2Pair(fromPoolAddress).token1(); //swap token0 to toToken if (token0 == toToken) { tokensBought = tokensBought + amount0; } else { //swap token using 0x swap tokensBought = tokensBought + _fillQuote( token0, toToken, amount0, swapTargets[0], swapData[0] ); } //swap token1 to toToken if (token1 == toToken) { tokensBought = tokensBought + amount1; } else { //swap token using 0x swap tokensBought = tokensBought + _fillQuote( token1, toToken, amount1, swapTargets[1], swapData[1] ); } } function _fillQuote( address fromTokenAddress, address toToken, uint256 amount, address swapTarget, bytes memory swapData ) internal returns (uint256) { if (fromTokenAddress == wethTokenAddress && toToken == address(0)) { IWETH(wethTokenAddress).withdraw(amount); return amount; } uint256 valueToSend; if (fromTokenAddress == address(0)) { valueToSend = amount; } else { _approveToken(fromTokenAddress, swapTarget, amount); } uint256 initialBalance = _getBalance(toToken); require(approvedTargets[swapTarget], "Target not Authorized"); (bool success, ) = swapTarget.call{ value: valueToSend }(swapData); require(success, "Error Swapping Tokens"); uint256 finalBalance = _getBalance(toToken) - initialBalance; require(finalBalance > 0, "Swapped to Invalid Intermediate"); return finalBalance; } /** @notice Utility function to determine quantity and addresses of tokens being removed @param fromPoolAddress Pool from which to remove liquidity @param liquidity Quantity of LP tokens to remove. @return amountA Quantity of tokenA removed @return amountB Quantity of tokenB removed @return token0 Address of the underlying token to be removed @return token1 Address of the underlying token to be removed */ function removeLiquidityReturn(address fromPoolAddress, uint256 liquidity) external view returns ( uint256 amountA, uint256 amountB, address token0, address token1 ) { IUniswapV2Pair pair = IUniswapV2Pair(fromPoolAddress); token0 = pair.token0(); token1 = pair.token1(); uint256 balance0 = IERC20(token0).balanceOf(fromPoolAddress); uint256 balance1 = IERC20(token1).balanceOf(fromPoolAddress); uint256 _totalSupply = pair.totalSupply(); amountA = (liquidity * balance0) / _totalSupply; amountB = (liquidity * balance1) / _totalSupply; } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // Copyright (C) 2021 zapper // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // Visit <https://www.gnu.org/licenses/>for a copy of the GNU Affero General Public License ///@author Zapper ///@notice this contract implements one click removal of liquidity from Sushiswap pools, receiving ETH, ERC20 or both. // SPDX-License-Identifier: GPL-2.0 pragma solidity ^0.8.0; import "../_base/ZapOutBaseV3.sol"; interface IUniswapV2Factory { function getPair(address tokenA, address tokenB) external view returns (address pair); } interface IUniswapV2Router02 { function WETH() external pure returns (address); function removeLiquidity( address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns (uint256 amountA, uint256 amountB); function removeLiquidityETH( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external returns (uint256 amountToken, uint256 amountETH); } interface IUniswapV2Pair { function token0() external pure returns (address); function token1() external pure returns (address); function balanceOf(address user) external view returns (uint256); function totalSupply() external view returns (uint256); function getReserves() external view returns ( uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast ); function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; } interface IWETH { function withdraw(uint256 wad) external; } contract Sushiswap_ZapOut_General_V3 is ZapOutBaseV3 { using SafeERC20 for IERC20; uint256 private constant deadline = 0xf000000000000000000000000000000000000000000000000000000000000000; IUniswapV2Router02 private constant sushiswapRouter = IUniswapV2Router02(0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F); IUniswapV2Factory private constant sushiswapFactory = IUniswapV2Factory(0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac); address private constant wethTokenAddress = address(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); constructor(uint256 _goodwill, uint256 _affiliateSplit) ZapBaseV2(_goodwill, _affiliateSplit) { // 0x exchange approvedTargets[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] = true; } event zapOut( address sender, address pool, address token, uint256 tokensRec ); /** @notice Zap out in both tokens @param fromPoolAddress Pool from which to remove liquidity @param incomingLP Quantity of LP to remove from pool @param affiliate Affiliate address @return amountA Quantity of tokenA received after zapout @return amountB Quantity of tokenB received after zapout */ function ZapOut2PairToken( address fromPoolAddress, uint256 incomingLP, address affiliate ) public stopInEmergency returns (uint256 amountA, uint256 amountB) { IUniswapV2Pair pair = IUniswapV2Pair(fromPoolAddress); require(address(pair) != address(0), "Pool Cannot be Zero Address"); // get reserves address token0 = pair.token0(); address token1 = pair.token1(); IERC20(fromPoolAddress).safeTransferFrom( msg.sender, address(this), incomingLP ); _approveToken(fromPoolAddress, address(sushiswapRouter), incomingLP); if (token0 == wethTokenAddress || token1 == wethTokenAddress) { address _token = token0 == wethTokenAddress ? token1 : token0; (amountA, amountB) = sushiswapRouter.removeLiquidityETH( _token, incomingLP, 1, 1, address(this), deadline ); // subtract goodwill uint256 tokenGoodwill = _subtractGoodwill(_token, amountA, affiliate, true); uint256 ethGoodwill = _subtractGoodwill(ETHAddress, amountB, affiliate, true); // send tokens IERC20(_token).safeTransfer(msg.sender, amountA - tokenGoodwill); Address.sendValue(payable(msg.sender), amountB - ethGoodwill); } else { (amountA, amountB) = sushiswapRouter.removeLiquidity( token0, token1, incomingLP, 1, 1, address(this), deadline ); // subtract goodwill uint256 tokenAGoodwill = _subtractGoodwill(token0, amountA, affiliate, true); uint256 tokenBGoodwill = _subtractGoodwill(token1, amountB, affiliate, true); // send tokens IERC20(token0).safeTransfer(msg.sender, amountA - tokenAGoodwill); IERC20(token1).safeTransfer(msg.sender, amountB - tokenBGoodwill); } emit zapOut(msg.sender, fromPoolAddress, token0, amountA); emit zapOut(msg.sender, fromPoolAddress, token1, amountB); } /** @notice Zap out in a single token @param toTokenAddress Address of desired token @param fromPoolAddress Pool from which to remove liquidity @param incomingLP Quantity of LP to remove from pool @param minTokensRec Minimum quantity of tokens to receive @param swapTargets Execution targets for swaps @param swapData DEX swap data @param affiliate Affiliate address @param shouldSellEntireBalance If True transfers entrire allowable amount from another contract */ function ZapOut( address toTokenAddress, address fromPoolAddress, uint256 incomingLP, uint256 minTokensRec, address[] memory swapTargets, bytes[] memory swapData, address affiliate, bool shouldSellEntireBalance ) public stopInEmergency returns (uint256 tokensRec) { (uint256 amount0, uint256 amount1) = _removeLiquidity( fromPoolAddress, incomingLP, shouldSellEntireBalance ); //swaps tokens to token tokensRec = _swapTokens( fromPoolAddress, amount0, amount1, toTokenAddress, swapTargets, swapData ); require(tokensRec >= minTokensRec, "High Slippage"); uint256 totalGoodwillPortion; // transfer toTokens to sender if (toTokenAddress == address(0)) { totalGoodwillPortion = _subtractGoodwill( ETHAddress, tokensRec, affiliate, true ); payable(msg.sender).transfer(tokensRec - totalGoodwillPortion); } else { totalGoodwillPortion = _subtractGoodwill( toTokenAddress, tokensRec, affiliate, true ); IERC20(toTokenAddress).safeTransfer( msg.sender, tokensRec - totalGoodwillPortion ); } tokensRec = tokensRec - totalGoodwillPortion; emit zapOut(msg.sender, fromPoolAddress, toTokenAddress, tokensRec); return tokensRec; } /** @notice Zap out in both tokens with permit @param fromPoolAddress Pool from which to remove liquidity @param incomingLP Quantity of LP to remove from pool @param affiliate Affiliate address to share fees @param permitData Encoded permit data, which contains owner, spender, value, deadline, r,s,v values @return amountA Quantity of tokenA received @return amountB Quantity of tokenB received */ function ZapOut2PairTokenWithPermit( address fromPoolAddress, uint256 incomingLP, address affiliate, bytes calldata permitData ) external stopInEmergency returns (uint256 amountA, uint256 amountB) { // permit _validatePool(fromPoolAddress); (bool success, ) = fromPoolAddress.call(permitData); require(success, "Could Not Permit"); (amountA, amountB) = ZapOut2PairToken( fromPoolAddress, incomingLP, affiliate ); } /** @notice Zap out in a single token with permit @param toTokenAddress Address of desired token @param fromPoolAddress Pool from which to remove liquidity @param incomingLP Quantity of LP to remove from pool @param minTokensRec Minimum quantity of tokens to receive @param swapTargets Execution targets for swaps @param swapData DEX swap data @param affiliate Affiliate address */ function ZapOutWithPermit( address toTokenAddress, address fromPoolAddress, uint256 incomingLP, uint256 minTokensRec, bytes memory permitData, address[] memory swapTargets, bytes[] memory swapData, address affiliate ) public stopInEmergency returns (uint256) { // permit _validatePool(fromPoolAddress); (bool success, ) = fromPoolAddress.call(permitData); require(success, "Could Not Permit"); return ( ZapOut( toTokenAddress, fromPoolAddress, incomingLP, minTokensRec, swapTargets, swapData, affiliate, false ) ); } function _validatePool(address poolAddress) internal view { IUniswapV2Pair pair = IUniswapV2Pair(poolAddress); address token0 = pair.token0(); address token1 = pair.token1(); address retrievedAddress = sushiswapFactory.getPair(token0, token1); require(retrievedAddress == poolAddress, "Invalid Pool Address"); } function _removeLiquidity( address fromPoolAddress, uint256 incomingLP, bool shouldSellEntireBalance ) internal returns (uint256 amount0, uint256 amount1) { IUniswapV2Pair pair = IUniswapV2Pair(fromPoolAddress); require(address(pair) != address(0), "Pool Cannot be Zero Address"); address token0 = pair.token0(); address token1 = pair.token1(); _pullTokens(fromPoolAddress, incomingLP, shouldSellEntireBalance); _approveToken(fromPoolAddress, address(sushiswapRouter), incomingLP); (amount0, amount1) = sushiswapRouter.removeLiquidity( token0, token1, incomingLP, 1, 1, address(this), deadline ); require(amount0 > 0 && amount1 > 0, "Removed Insufficient Liquidity"); } function _swapTokens( address fromPoolAddress, uint256 amount0, uint256 amount1, address toToken, address[] memory swapTargets, bytes[] memory swapData ) internal returns (uint256 tokensBought) { address token0 = IUniswapV2Pair(fromPoolAddress).token0(); address token1 = IUniswapV2Pair(fromPoolAddress).token1(); //swap token0 to toToken if (token0 == toToken) { tokensBought = tokensBought + amount0; } else { //swap token using 0x swap tokensBought = tokensBought + _fillQuote( token0, toToken, amount0, swapTargets[0], swapData[0] ); } //swap token1 to toToken if (token1 == toToken) { tokensBought = tokensBought + amount1; } else { //swap token using 0x swap tokensBought = tokensBought + _fillQuote( token1, toToken, amount1, swapTargets[1], swapData[1] ); } } function _fillQuote( address fromTokenAddress, address toToken, uint256 amount, address swapTarget, bytes memory swapData ) internal returns (uint256) { if (fromTokenAddress == wethTokenAddress && toToken == address(0)) { IWETH(wethTokenAddress).withdraw(amount); return amount; } uint256 valueToSend; if (fromTokenAddress == address(0)) { valueToSend = amount; } else { _approveToken(fromTokenAddress, swapTarget, amount); } uint256 initialBalance = _getBalance(toToken); require(approvedTargets[swapTarget], "Target not Authorized"); (bool success, ) = swapTarget.call{ value: valueToSend }(swapData); require(success, "Error Swapping Tokens"); uint256 finalBalance = _getBalance(toToken) - initialBalance; require(finalBalance > 0, "Swapped to Invalid Intermediate"); return finalBalance; } /** @notice Utility function to determine quantity and addresses of tokens being removed @param fromPoolAddress Pool from which to remove liquidity @param liquidity Quantity of LP tokens to remove. @return amountA Quantity of tokenA removed @return amountB Quantity of tokenB removed @return token0 Address of the underlying token to be removed @return token1 Address of the underlying token to be removed */ function removeLiquidityReturn(address fromPoolAddress, uint256 liquidity) external view returns ( uint256 amountA, uint256 amountB, address token0, address token1 ) { IUniswapV2Pair pair = IUniswapV2Pair(fromPoolAddress); token0 = pair.token0(); token1 = pair.token1(); uint256 balance0 = IERC20(token0).balanceOf(fromPoolAddress); uint256 balance1 = IERC20(token1).balanceOf(fromPoolAddress); uint256 _totalSupply = pair.totalSupply(); amountA = (liquidity * balance0) / _totalSupply; amountB = (liquidity * balance1) / _totalSupply; } }
// SPDX-License-Identifier: GPL-2.0 pragma solidity ^0.8.0; import "./ZapBaseV2.sol"; abstract contract ZapInBaseV3 is ZapBaseV2 { using SafeERC20 for IERC20; function _pullTokens( address token, uint256 amount, address affiliate, bool enableGoodwill, bool shouldSellEntireBalance ) internal returns (uint256 value) { uint256 totalGoodwillPortion; if (token == address(0)) { require(msg.value > 0, "No eth sent"); // subtract goodwill totalGoodwillPortion = _subtractGoodwill( ETHAddress, msg.value, affiliate, enableGoodwill ); return msg.value - totalGoodwillPortion; } require(amount > 0, "Invalid token amount"); require(msg.value == 0, "Eth sent with token"); //transfer token if (shouldSellEntireBalance) { require( Address.isContract(msg.sender), "ERR: shouldSellEntireBalance is true for EOA" ); amount = IERC20(token).allowance(msg.sender, address(this)); } IERC20(token).safeTransferFrom(msg.sender, address(this), amount); // subtract goodwill totalGoodwillPortion = _subtractGoodwill( token, amount, affiliate, enableGoodwill ); return amount - totalGoodwillPortion; } function _subtractGoodwill( address token, uint256 amount, address affiliate, bool enableGoodwill ) internal returns (uint256 totalGoodwillPortion) { bool whitelisted = feeWhitelist[msg.sender]; if (enableGoodwill && !whitelisted && goodwill > 0) { totalGoodwillPortion = (amount * goodwill) / 10000; if (affiliates[affiliate]) { if (token == address(0)) { token = ETHAddress; } uint256 affiliatePortion = (totalGoodwillPortion * affiliateSplit) / 100; affiliateBalance[affiliate][token] += affiliatePortion; totalAffiliateBalance[token] += affiliatePortion; } } } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // Copyright (C) 2021 zapper // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // ///@author Zapper ///@notice This contract adds liquidity to Uniswap V2 pools using ETH or any ERC20 Token. // SPDX-License-Identifier: GPL-2.0 pragma solidity ^0.8.0; import "../_base/ZapInBaseV3.sol"; // import "@uniswap/lib/contracts/libraries/Babylonian.sol"; library Babylonian { function sqrt(uint256 y) internal pure returns (uint256 z) { if (y > 3) { z = y; uint256 x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } // else z = 0 } } interface IWETH { function deposit() external payable; function transfer(address to, uint256 value) external returns (bool); function withdraw(uint256) external; } interface IUniswapV2Factory { function getPair(address tokenA, address tokenB) external view returns (address); } interface IUniswapV2Router02 { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidity( address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns ( uint256 amountA, uint256 amountB, uint256 liquidity ); function addLiquidityETH( address token, uint256 amountTokenDesired, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external payable returns ( uint256 amountToken, uint256 amountETH, uint256 liquidity ); function removeLiquidity( address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns (uint256 amountA, uint256 amountB); function removeLiquidityETH( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external returns (uint256 amountToken, uint256 amountETH); function removeLiquidityWithPermit( address tokenA, address tokenB, uint256 liquidity, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint256 amountA, uint256 amountB); function removeLiquidityETHWithPermit( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint256 amountToken, uint256 amountETH); function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapTokensForExactTokens( uint256 amountOut, uint256 amountInMax, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapExactETHForTokens( uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external payable returns (uint256[] memory amounts); function swapTokensForExactETH( uint256 amountOut, uint256 amountInMax, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapExactTokensForETH( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); function swapETHForExactTokens( uint256 amountOut, address[] calldata path, address to, uint256 deadline ) external payable returns (uint256[] memory amounts); function removeLiquidityETHSupportingFeeOnTransferTokens( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline ) external returns (uint256 amountETH); function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( address token, uint256 liquidity, uint256 amountTokenMin, uint256 amountETHMin, address to, uint256 deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint256 amountETH); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external; function swapExactETHForTokensSupportingFeeOnTransferTokens( uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external payable; function swapExactTokensForETHSupportingFeeOnTransferTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external; function quote( uint256 amountA, uint256 reserveA, uint256 reserveB ) external pure returns (uint256 amountB); function getAmountOut( uint256 amountIn, uint256 reserveIn, uint256 reserveOut ) external pure returns (uint256 amountOut); function getAmountIn( uint256 amountOut, uint256 reserveIn, uint256 reserveOut ) external pure returns (uint256 amountIn); function getAmountsOut(uint256 amountIn, address[] calldata path) external view returns (uint256[] memory amounts); function getAmountsIn(uint256 amountOut, address[] calldata path) external view returns (uint256[] memory amounts); } interface IUniswapV2Pair { function token0() external pure returns (address); function token1() external pure returns (address); function getReserves() external view returns ( uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast ); } contract UniswapV2_ZapIn_General_V5 is ZapInBaseV3 { using SafeERC20 for IERC20; IUniswapV2Factory private constant UniSwapV2FactoryAddress = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f); IUniswapV2Router02 private constant uniswapRouter = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); address private constant wethTokenAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; uint256 private constant deadline = 0xf000000000000000000000000000000000000000000000000000000000000000; constructor(uint256 _goodwill, uint256 _affiliateSplit) ZapBaseV2(_goodwill, _affiliateSplit) { // 0x exchange approvedTargets[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] = true; } event zapIn(address sender, address pool, uint256 tokensRec); /** @notice This function is used to invest in given Uniswap V2 pair through ETH/ERC20 Tokens @param _FromTokenContractAddress The ERC20 token used for investment (address(0x00) if ether) @param _pairAddress The Uniswap pair address @param _amount The amount of fromToken to invest @param _minPoolTokens Reverts if less tokens received than this @param _swapTarget Excecution target for the first swap @param swapData DEX quote data @param affiliate Affiliate address @param transferResidual Set false to save gas by donating the residual remaining after a Zap @param shouldSellEntireBalance If True transfers entrire allowable amount from another contract @return Amount of LP bought */ function ZapIn( address _FromTokenContractAddress, address _pairAddress, uint256 _amount, uint256 _minPoolTokens, address _swapTarget, bytes calldata swapData, address affiliate, bool transferResidual, bool shouldSellEntireBalance ) external payable stopInEmergency returns (uint256) { uint256 toInvest = _pullTokens( _FromTokenContractAddress, _amount, affiliate, true, shouldSellEntireBalance ); uint256 LPBought = _performZapIn( _FromTokenContractAddress, _pairAddress, toInvest, _swapTarget, swapData, transferResidual ); require(LPBought >= _minPoolTokens, "High Slippage"); emit zapIn(msg.sender, _pairAddress, LPBought); IERC20(_pairAddress).safeTransfer(msg.sender, LPBought); return LPBought; } function _getPairTokens(address _pairAddress) internal pure returns (address token0, address token1) { IUniswapV2Pair uniPair = IUniswapV2Pair(_pairAddress); token0 = uniPair.token0(); token1 = uniPair.token1(); } function _performZapIn( address _FromTokenContractAddress, address _pairAddress, uint256 _amount, address _swapTarget, bytes memory swapData, bool transferResidual ) internal returns (uint256) { uint256 intermediateAmt; address intermediateToken; (address _ToUniswapToken0, address _ToUniswapToken1) = _getPairTokens(_pairAddress); if ( _FromTokenContractAddress != _ToUniswapToken0 && _FromTokenContractAddress != _ToUniswapToken1 ) { // swap to intermediate (intermediateAmt, intermediateToken) = _fillQuote( _FromTokenContractAddress, _pairAddress, _amount, _swapTarget, swapData ); } else { intermediateToken = _FromTokenContractAddress; intermediateAmt = _amount; } // divide intermediate into appropriate amount to add liquidity (uint256 token0Bought, uint256 token1Bought) = _swapIntermediate( intermediateToken, _ToUniswapToken0, _ToUniswapToken1, intermediateAmt ); return _uniDeposit( _ToUniswapToken0, _ToUniswapToken1, token0Bought, token1Bought, transferResidual ); } function _uniDeposit( address _ToUnipoolToken0, address _ToUnipoolToken1, uint256 token0Bought, uint256 token1Bought, bool transferResidual ) internal returns (uint256) { _approveToken(_ToUnipoolToken0, address(uniswapRouter), token0Bought); _approveToken(_ToUnipoolToken1, address(uniswapRouter), token1Bought); (uint256 amountA, uint256 amountB, uint256 LP) = uniswapRouter.addLiquidity( _ToUnipoolToken0, _ToUnipoolToken1, token0Bought, token1Bought, 1, 1, address(this), deadline ); if (transferResidual) { //Returning Residue in token0, if any. if (token0Bought - amountA > 0) { IERC20(_ToUnipoolToken0).safeTransfer( msg.sender, token0Bought - amountA ); } //Returning Residue in token1, if any if (token1Bought - amountB > 0) { IERC20(_ToUnipoolToken1).safeTransfer( msg.sender, token1Bought - amountB ); } } return LP; } function _fillQuote( address _fromTokenAddress, address _pairAddress, uint256 _amount, address _swapTarget, bytes memory swapData ) internal returns (uint256 amountBought, address intermediateToken) { if (_swapTarget == wethTokenAddress) { IWETH(wethTokenAddress).deposit{ value: _amount }(); return (_amount, wethTokenAddress); } uint256 valueToSend; if (_fromTokenAddress == address(0)) { valueToSend = _amount; } else { _approveToken(_fromTokenAddress, _swapTarget, _amount); } (address _token0, address _token1) = _getPairTokens(_pairAddress); IERC20 token0 = IERC20(_token0); IERC20 token1 = IERC20(_token1); uint256 initialBalance0 = token0.balanceOf(address(this)); uint256 initialBalance1 = token1.balanceOf(address(this)); require(approvedTargets[_swapTarget], "Target not Authorized"); (bool success, ) = _swapTarget.call{ value: valueToSend }(swapData); require(success, "Error Swapping Tokens 1"); uint256 finalBalance0 = token0.balanceOf(address(this)) - initialBalance0; uint256 finalBalance1 = token1.balanceOf(address(this)) - initialBalance1; if (finalBalance0 > finalBalance1) { amountBought = finalBalance0; intermediateToken = _token0; } else { amountBought = finalBalance1; intermediateToken = _token1; } require(amountBought > 0, "Swapped to Invalid Intermediate"); } function _swapIntermediate( address _toContractAddress, address _ToUnipoolToken0, address _ToUnipoolToken1, uint256 _amount ) internal returns (uint256 token0Bought, uint256 token1Bought) { IUniswapV2Pair pair = IUniswapV2Pair( UniSwapV2FactoryAddress.getPair( _ToUnipoolToken0, _ToUnipoolToken1 ) ); (uint256 res0, uint256 res1, ) = pair.getReserves(); if (_toContractAddress == _ToUnipoolToken0) { uint256 amountToSwap = calculateSwapInAmount(res0, _amount); //if no reserve or a new pair is created if (amountToSwap <= 0) amountToSwap = _amount / 2; token1Bought = _token2Token( _toContractAddress, _ToUnipoolToken1, amountToSwap ); token0Bought = _amount - amountToSwap; } else { uint256 amountToSwap = calculateSwapInAmount(res1, _amount); //if no reserve or a new pair is created if (amountToSwap <= 0) amountToSwap = _amount / 2; token0Bought = _token2Token( _toContractAddress, _ToUnipoolToken0, amountToSwap ); token1Bought = _amount - amountToSwap; } } function calculateSwapInAmount(uint256 reserveIn, uint256 userIn) internal pure returns (uint256) { return (Babylonian.sqrt( reserveIn * ((userIn * 3988000) + (reserveIn * 3988009)) ) - (reserveIn * 1997)) / 1994; } /** @notice This function is used to swap ERC20 <> ERC20 @param _FromTokenContractAddress The token address to swap from. @param _ToTokenContractAddress The token address to swap to. @param tokens2Trade The amount of tokens to swap @return tokenBought The quantity of tokens bought */ function _token2Token( address _FromTokenContractAddress, address _ToTokenContractAddress, uint256 tokens2Trade ) internal returns (uint256 tokenBought) { if (_FromTokenContractAddress == _ToTokenContractAddress) { return tokens2Trade; } _approveToken( _FromTokenContractAddress, address(uniswapRouter), tokens2Trade ); address pair = UniSwapV2FactoryAddress.getPair( _FromTokenContractAddress, _ToTokenContractAddress ); require(pair != address(0), "No Swap Available"); address[] memory path = new address[](2); path[0] = _FromTokenContractAddress; path[1] = _ToTokenContractAddress; tokenBought = uniswapRouter.swapExactTokensForTokens( tokens2Trade, 1, path, address(this), deadline )[path.length - 1]; require(tokenBought > 0, "Error Swapping Tokens 2"); } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // Copyright (C) 2021 zapper // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // ///@author Zapper ///@notice This contract adds liquidity to Sushiswap pools using ETH or any ERC20 Token. // SPDX-License-Identifier: GPL-2.0 pragma solidity ^0.8.0; import "../_base/ZapInBaseV3.sol"; // import "@uniswap/lib/contracts/libraries/Babylonian.sol"; library Babylonian { function sqrt(uint256 y) internal pure returns (uint256 z) { if (y > 3) { z = y; uint256 x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } // else z = 0 } } interface IWETH { function deposit() external payable; } interface IUniswapV2Factory { function getPair(address tokenA, address tokenB) external view returns (address); } interface IUniswapV2Router02 { function addLiquidity( address tokenA, address tokenB, uint256 amountADesired, uint256 amountBDesired, uint256 amountAMin, uint256 amountBMin, address to, uint256 deadline ) external returns ( uint256 amountA, uint256 amountB, uint256 liquidity ); function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, address[] calldata path, address to, uint256 deadline ) external returns (uint256[] memory amounts); } interface IUniswapV2Pair { function token0() external pure returns (address); function token1() external pure returns (address); function getReserves() external view returns ( uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast ); } contract Sushiswap_ZapIn_V4 is ZapInBaseV3 { using SafeERC20 for IERC20; IUniswapV2Factory private constant sushiSwapFactoryAddress = IUniswapV2Factory(0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac); IUniswapV2Router02 private constant sushiSwapRouter = IUniswapV2Router02(0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F); address private constant wethTokenAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; uint256 private constant deadline = 0xf000000000000000000000000000000000000000000000000000000000000000; constructor(uint256 _goodwill, uint256 _affiliateSplit) ZapBaseV2(_goodwill, _affiliateSplit) { // 0x exchange approvedTargets[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] = true; } event zapIn(address sender, address pool, uint256 tokensRec); /** @notice Add liquidity to Sushiswap pools with ETH/ERC20 Tokens @param _FromTokenContractAddress The ERC20 token used (address(0x00) if ether) @param _pairAddress The Sushiswap pair address @param _amount The amount of fromToken to invest @param _minPoolTokens Minimum quantity of pool tokens to receive. Reverts otherwise @param _swapTarget Excecution target for the first swap @param swapData DEX quote data @param affiliate Affiliate address @param transferResidual Set false to save gas by donating the residual remaining after a Zap @param shouldSellEntireBalance If True transfers entrire allowable amount from another contract @return Amount of LP bought */ function ZapIn( address _FromTokenContractAddress, address _pairAddress, uint256 _amount, uint256 _minPoolTokens, address _swapTarget, bytes calldata swapData, address affiliate, bool transferResidual, bool shouldSellEntireBalance ) external payable stopInEmergency returns (uint256) { uint256 toInvest = _pullTokens( _FromTokenContractAddress, _amount, affiliate, true, shouldSellEntireBalance ); uint256 LPBought = _performZapIn( _FromTokenContractAddress, _pairAddress, toInvest, _swapTarget, swapData, transferResidual ); require(LPBought >= _minPoolTokens, "High Slippage"); emit zapIn(msg.sender, _pairAddress, LPBought); IERC20(_pairAddress).safeTransfer(msg.sender, LPBought); return LPBought; } function _getPairTokens(address _pairAddress) internal pure returns (address token0, address token1) { IUniswapV2Pair uniPair = IUniswapV2Pair(_pairAddress); token0 = uniPair.token0(); token1 = uniPair.token1(); } function _performZapIn( address _FromTokenContractAddress, address _pairAddress, uint256 _amount, address _swapTarget, bytes memory swapData, bool transferResidual ) internal returns (uint256) { uint256 intermediateAmt; address intermediateToken; (address _ToUniswapToken0, address _ToUniswapToken1) = _getPairTokens(_pairAddress); if ( _FromTokenContractAddress != _ToUniswapToken0 && _FromTokenContractAddress != _ToUniswapToken1 ) { // swap to intermediate (intermediateAmt, intermediateToken) = _fillQuote( _FromTokenContractAddress, _pairAddress, _amount, _swapTarget, swapData ); } else { intermediateToken = _FromTokenContractAddress; intermediateAmt = _amount; } // divide intermediate into appropriate amount to add liquidity (uint256 token0Bought, uint256 token1Bought) = _swapIntermediate( intermediateToken, _ToUniswapToken0, _ToUniswapToken1, intermediateAmt ); return _uniDeposit( _ToUniswapToken0, _ToUniswapToken1, token0Bought, token1Bought, transferResidual ); } function _uniDeposit( address _ToUnipoolToken0, address _ToUnipoolToken1, uint256 token0Bought, uint256 token1Bought, bool transferResidual ) internal returns (uint256) { _approveToken(_ToUnipoolToken0, address(sushiSwapRouter), token0Bought); _approveToken(_ToUnipoolToken1, address(sushiSwapRouter), token1Bought); (uint256 amountA, uint256 amountB, uint256 LP) = sushiSwapRouter.addLiquidity( _ToUnipoolToken0, _ToUnipoolToken1, token0Bought, token1Bought, 1, 1, address(this), deadline ); if (transferResidual) { //Returning Residue in token0, if any. if (token0Bought - amountA > 0) { IERC20(_ToUnipoolToken0).safeTransfer( msg.sender, token0Bought - amountA ); } //Returning Residue in token1, if any if (token1Bought - amountB > 0) { IERC20(_ToUnipoolToken1).safeTransfer( msg.sender, token1Bought - amountB ); } } return LP; } function _fillQuote( address _fromTokenAddress, address _pairAddress, uint256 _amount, address _swapTarget, bytes memory swapData ) internal returns (uint256 amountBought, address intermediateToken) { if (_swapTarget == wethTokenAddress) { IWETH(wethTokenAddress).deposit{ value: _amount }(); return (_amount, wethTokenAddress); } uint256 valueToSend; if (_fromTokenAddress == address(0)) { valueToSend = _amount; } else { _approveToken(_fromTokenAddress, _swapTarget, _amount); } (address _token0, address _token1) = _getPairTokens(_pairAddress); IERC20 token0 = IERC20(_token0); IERC20 token1 = IERC20(_token1); uint256 initialBalance0 = token0.balanceOf(address(this)); uint256 initialBalance1 = token1.balanceOf(address(this)); require(approvedTargets[_swapTarget], "Target not Authorized"); (bool success, ) = _swapTarget.call{ value: valueToSend }(swapData); require(success, "Error Swapping Tokens 1"); uint256 finalBalance0 = token0.balanceOf(address(this)) - initialBalance0; uint256 finalBalance1 = token1.balanceOf(address(this)) - initialBalance1; if (finalBalance0 > finalBalance1) { amountBought = finalBalance0; intermediateToken = _token0; } else { amountBought = finalBalance1; intermediateToken = _token1; } require(amountBought > 0, "Swapped to Invalid Intermediate"); } function _swapIntermediate( address _toContractAddress, address _ToUnipoolToken0, address _ToUnipoolToken1, uint256 _amount ) internal returns (uint256 token0Bought, uint256 token1Bought) { IUniswapV2Pair pair = IUniswapV2Pair( sushiSwapFactoryAddress.getPair( _ToUnipoolToken0, _ToUnipoolToken1 ) ); (uint256 res0, uint256 res1, ) = pair.getReserves(); if (_toContractAddress == _ToUnipoolToken0) { uint256 amountToSwap = calculateSwapInAmount(res0, _amount); //if no reserve or a new pair is created if (amountToSwap <= 0) amountToSwap = _amount / 2; token1Bought = _token2Token( _toContractAddress, _ToUnipoolToken1, amountToSwap ); token0Bought = _amount - amountToSwap; } else { uint256 amountToSwap = calculateSwapInAmount(res1, _amount); //if no reserve or a new pair is created if (amountToSwap <= 0) amountToSwap = _amount / 2; token0Bought = _token2Token( _toContractAddress, _ToUnipoolToken0, amountToSwap ); token1Bought = _amount - amountToSwap; } } function calculateSwapInAmount(uint256 reserveIn, uint256 userIn) internal pure returns (uint256) { return (Babylonian.sqrt( reserveIn * ((userIn * 3988000) + (reserveIn * 3988009)) ) - (reserveIn * 1997)) / 1994; } /** @notice This function is used to swap ERC20 <> ERC20 @param _FromTokenContractAddress The token address to swap from. @param _ToTokenContractAddress The token address to swap to. @param tokens2Trade The amount of tokens to swap @return tokenBought The quantity of tokens bought */ function _token2Token( address _FromTokenContractAddress, address _ToTokenContractAddress, uint256 tokens2Trade ) internal returns (uint256 tokenBought) { if (_FromTokenContractAddress == _ToTokenContractAddress) { return tokens2Trade; } _approveToken( _FromTokenContractAddress, address(sushiSwapRouter), tokens2Trade ); address pair = sushiSwapFactoryAddress.getPair( _FromTokenContractAddress, _ToTokenContractAddress ); require(pair != address(0), "No Swap Available"); address[] memory path = new address[](2); path[0] = _FromTokenContractAddress; path[1] = _ToTokenContractAddress; tokenBought = sushiSwapRouter.swapExactTokensForTokens( tokens2Trade, 1, path, address(this), deadline )[path.length - 1]; require(tokenBought > 0, "Error Swapping Tokens 2"); } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // Copyright (C) 2021 zapper // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // ///@author Zapper ///@notice This contract adds liquidity to Curve pools with ETH or ERC tokens. // SPDX-License-Identifier: GPL-2.0 pragma solidity ^0.8.0; import "../_base/ZapInBaseV3.sol"; interface IWETH { function deposit() external payable; } interface ICurveSwap { function coins(int128 arg0) external view returns (address); function underlying_coins(int128 arg0) external view returns (address); function add_liquidity(uint256[4] calldata amounts, uint256 min_mint_amount) external; function add_liquidity( uint256[4] calldata amounts, uint256 min_mint_amount, bool addUnderlying ) external; function add_liquidity(uint256[3] calldata amounts, uint256 min_mint_amount) external; function add_liquidity( uint256[3] calldata amounts, uint256 min_mint_amount, bool addUnderlying ) external; function add_liquidity(uint256[2] calldata amounts, uint256 min_mint_amount) external; function add_liquidity( uint256[2] calldata amounts, uint256 min_mint_amount, bool addUnderlying ) external; } interface ICurveEthSwap { function add_liquidity(uint256[2] calldata amounts, uint256 min_mint_amount) external payable returns (uint256); } interface ICurveRegistry { function getSwapAddress(address tokenAddress) external view returns (address swapAddress); function getTokenAddress(address swapAddress) external view returns (address tokenAddress); function getDepositAddress(address swapAddress) external view returns (address depositAddress); function getPoolTokens(address swapAddress) external view returns (address[4] memory poolTokens); function shouldAddUnderlying(address swapAddress) external view returns (bool); function getNumTokens(address swapAddress) external view returns (uint8 numTokens); function isBtcPool(address swapAddress) external view returns (bool); function isEthPool(address swapAddress) external view returns (bool); function isUnderlyingToken( address swapAddress, address tokenContractAddress ) external view returns (bool, uint8); } contract Curve_ZapIn_General_V4 is ZapInBaseV3 { using SafeERC20 for IERC20; ICurveRegistry public curveReg; address private constant wethTokenAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; constructor( ICurveRegistry _curveRegistry, uint256 _goodwill, uint256 _affiliateSplit ) ZapBaseV2(_goodwill, _affiliateSplit) { curveReg = _curveRegistry; // 0x exchange approvedTargets[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] = true; } event zapIn(address sender, address pool, uint256 tokensRec); /** @notice This function adds liquidity to a Curve pool with ETH or ERC20 tokens @param fromTokenAddress The token used for entry (address(0) if ether) @param toTokenAddress The intermediate ERC20 token to swap to @param swapAddress Curve swap address for the pool @param incomingTokenQty The amount of fromTokenAddress to invest @param minPoolTokens The minimum acceptable quantity of Curve LP to receive. Reverts otherwise @param swapTarget Excecution target for the first swap @param swapData DEX quote data @param affiliate Affiliate address @param shouldSellEntireBalance If True transfers entrire allowable amount from another contract @return crvTokensBought Quantity of Curve LP tokens received */ function ZapIn( address fromTokenAddress, address toTokenAddress, address swapAddress, uint256 incomingTokenQty, uint256 minPoolTokens, address swapTarget, bytes calldata swapData, address affiliate, bool shouldSellEntireBalance ) external payable stopInEmergency returns (uint256 crvTokensBought) { uint256 toInvest = _pullTokens( fromTokenAddress, incomingTokenQty, affiliate, true, shouldSellEntireBalance ); if (fromTokenAddress == address(0)) { fromTokenAddress = ETHAddress; } // perform zapIn crvTokensBought = _performZapIn( fromTokenAddress, toTokenAddress, swapAddress, toInvest, swapTarget, swapData ); require( crvTokensBought > minPoolTokens, "Received less than minPoolTokens" ); address poolTokenAddress = curveReg.getTokenAddress(swapAddress); emit zapIn(msg.sender, poolTokenAddress, crvTokensBought); IERC20(poolTokenAddress).transfer(msg.sender, crvTokensBought); } function _performZapIn( address fromTokenAddress, address toTokenAddress, address swapAddress, uint256 toInvest, address swapTarget, bytes memory swapData ) internal returns (uint256 crvTokensBought) { (bool isUnderlying, uint8 underlyingIndex) = curveReg.isUnderlyingToken(swapAddress, fromTokenAddress); if (isUnderlying) { crvTokensBought = _enterCurve( swapAddress, toInvest, underlyingIndex ); } else { //swap tokens using 0x swap uint256 tokensBought = _fillQuote( fromTokenAddress, toTokenAddress, toInvest, swapTarget, swapData ); if (toTokenAddress == address(0)) toTokenAddress = ETHAddress; //get underlying token index (isUnderlying, underlyingIndex) = curveReg.isUnderlyingToken( swapAddress, toTokenAddress ); if (isUnderlying) { crvTokensBought = _enterCurve( swapAddress, tokensBought, underlyingIndex ); } else { (uint256 tokens, uint8 metaIndex) = _enterMetaPool(swapAddress, toTokenAddress, tokensBought); crvTokensBought = _enterCurve(swapAddress, tokens, metaIndex); } } } /** @notice This function gets adds the liquidity for meta pools and returns the token index and swap tokens @param swapAddress Curve swap address for the pool @param toTokenAddress The ERC20 token to which from token to be convert @param swapTokens quantity of toToken to invest @return tokensBought quantity of curve LP acquired @return index index of LP token in swapAddress whose pool tokens were acquired */ function _enterMetaPool( address swapAddress, address toTokenAddress, uint256 swapTokens ) internal returns (uint256 tokensBought, uint8 index) { address[4] memory poolTokens = curveReg.getPoolTokens(swapAddress); for (uint8 i = 0; i < 4; i++) { address intermediateSwapAddress = curveReg.getSwapAddress(poolTokens[i]); if (intermediateSwapAddress != address(0)) { (, index) = curveReg.isUnderlyingToken( intermediateSwapAddress, toTokenAddress ); tokensBought = _enterCurve( intermediateSwapAddress, swapTokens, index ); return (tokensBought, i); } } } function _fillQuote( address fromTokenAddress, address toTokenAddress, uint256 amount, address swapTarget, bytes memory swapData ) internal returns (uint256 amountBought) { if (fromTokenAddress == toTokenAddress) { return amount; } if (swapTarget == wethTokenAddress) { IWETH(wethTokenAddress).deposit{ value: amount }(); return amount; } uint256 valueToSend; if (fromTokenAddress == ETHAddress) { valueToSend = amount; } else { _approveToken(fromTokenAddress, swapTarget, amount); } uint256 initialBalance = _getBalance(toTokenAddress); require(approvedTargets[swapTarget], "Target not Authorized"); (bool success, ) = swapTarget.call{ value: valueToSend }(swapData); require(success, "Error Swapping Tokens"); amountBought = _getBalance(toTokenAddress) - initialBalance; require(amountBought > 0, "Swapped To Invalid Intermediate"); } /** @notice This function adds liquidity to a curve pool @param swapAddress Curve swap address for the pool @param amount The quantity of tokens being added as liquidity @param index The token index for the add_liquidity call @return crvTokensBought the quantity of curve LP tokens received */ function _enterCurve( address swapAddress, uint256 amount, uint8 index ) internal returns (uint256 crvTokensBought) { address tokenAddress = curveReg.getTokenAddress(swapAddress); address depositAddress = curveReg.getDepositAddress(swapAddress); uint256 initialBalance = _getBalance(tokenAddress); address entryToken = curveReg.getPoolTokens(swapAddress)[index]; if (entryToken != ETHAddress) { IERC20(entryToken).safeIncreaseAllowance( address(depositAddress), amount ); } uint256 numTokens = curveReg.getNumTokens(swapAddress); bool addUnderlying = curveReg.shouldAddUnderlying(swapAddress); if (numTokens == 4) { uint256[4] memory amounts; amounts[index] = amount; if (addUnderlying) { ICurveSwap(depositAddress).add_liquidity(amounts, 0, true); } else { ICurveSwap(depositAddress).add_liquidity(amounts, 0); } } else if (numTokens == 3) { uint256[3] memory amounts; amounts[index] = amount; if (addUnderlying) { ICurveSwap(depositAddress).add_liquidity(amounts, 0, true); } else { ICurveSwap(depositAddress).add_liquidity(amounts, 0); } } else { uint256[2] memory amounts; amounts[index] = amount; if (curveReg.isEthPool(depositAddress)) { ICurveEthSwap(depositAddress).add_liquidity{ value: amount }( amounts, 0 ); } else if (addUnderlying) { ICurveSwap(depositAddress).add_liquidity(amounts, 0, true); } else { ICurveSwap(depositAddress).add_liquidity(amounts, 0); } } crvTokensBought = _getBalance(tokenAddress) - initialBalance; } function updateCurveRegistry(ICurveRegistry newCurveRegistry) external onlyOwner { require(newCurveRegistry != curveReg, "Already using this Registry"); curveReg = newCurveRegistry; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./SafeERC20.sol"; /** * @dev A token holder contract that will allow a beneficiary to extract the * tokens after a given release time. * * Useful for simple vesting schedules like "advisors get all of their tokens * after 1 year". */ contract TokenTimelock { using SafeERC20 for IERC20; // ERC20 basic token contract being held IERC20 private immutable _token; // beneficiary of tokens after they are released address private immutable _beneficiary; // timestamp when token release is enabled uint256 private immutable _releaseTime; constructor( IERC20 token_, address beneficiary_, uint256 releaseTime_ ) { // solhint-disable-next-line not-rely-on-time require( releaseTime_ > block.timestamp, "TokenTimelock: release time is before current time" ); _token = token_; _beneficiary = beneficiary_; _releaseTime = releaseTime_; } /** * @return the token being held. */ function token() public view virtual returns (IERC20) { return _token; } /** * @return the beneficiary of the tokens. */ function beneficiary() public view virtual returns (address) { return _beneficiary; } /** * @return the time when the tokens are released. */ function releaseTime() public view virtual returns (uint256) { return _releaseTime; } /** * @notice Transfers tokens held by timelock to beneficiary. */ function release() public virtual { // solhint-disable-next-line not-rely-on-time require( block.timestamp >= releaseTime(), "TokenTimelock: current time is before release time" ); uint256 amount = token().balanceOf(address(this)); require(amount > 0, "TokenTimelock: no tokens to release"); token().safeTransfer(beneficiary(), amount); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ 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 pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The defaut value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); uint256 currentAllowance = _allowances[sender][_msgSender()]; require( currentAllowance >= amount, "ERC20: transfer amount exceeds allowance" ); _approve(sender, _msgSender(), currentAllowance - amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve( _msgSender(), spender, _allowances[_msgSender()][spender] + addedValue ); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { uint256 currentAllowance = _allowances[_msgSender()][spender]; require( currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero" ); _approve(_msgSender(), spender, currentAllowance - subtractedValue); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); uint256 senderBalance = _balances[sender]; require( senderBalance >= amount, "ERC20: transfer amount exceeds balance" ); _balances[sender] = senderBalance - amount; _balances[recipient] += amount; emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); _balances[account] = accountBalance - amount; _totalSupply -= amount; emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/Context.sol"; import "../utils/Strings.sol"; import "../utils/introspection/ERC165.sol"; /** * @dev External interface of AccessControl declared to support ERC165 detection. */ interface IAccessControl { function hasRole(bytes32 role, address account) external view returns (bool); function getRoleAdmin(bytes32 role) external view returns (bytes32); function grantRole(bytes32 role, address account) external; function revokeRole(bytes32 role, address account) external; function renounceRole(bytes32 role, address account) external; } /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ``` * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ``` * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. */ abstract contract AccessControl is Context, IAccessControl, ERC165 { struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; /** * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` * * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite * {RoleAdminChanged} not being emitted signaling this. * * _Available since v3.1._ */ event RoleAdminChanged( bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole ); /** * @dev Emitted when `account` is granted `role`. * * `sender` is the account that originated the contract call, an admin role * bearer except when using {_setupRole}. */ event RoleGranted( bytes32 indexed role, address indexed account, address indexed sender ); /** * @dev Emitted when `account` is revoked `role`. * * `sender` is the account that originated the contract call: * - if using `revokeRole`, it is the admin role bearer * - if using `renounceRole`, it is the role bearer (i.e. `account`) */ event RoleRevoked( bytes32 indexed role, address indexed account, address indexed sender ); /** * @dev Modifier that checks that an account has a specific role. Reverts * with a standardized message including the required role. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/ * * _Available since v4.1._ */ modifier onlyRole(bytes32 role) { _checkRole(role, _msgSender()); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `account` is missing `role`. * * The format of the revert reason is given by the following regular expression: * * /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/ */ function _checkRole(bytes32 role, address account) internal view { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", Strings.toHexString(uint160(account), 20), " is missing role ", Strings.toHexString(uint256(role), 32) ) ) ); } } /** * @dev Returns the admin role that controls `role`. See {grantRole} and * {revokeRole}. * * To change a role's admin, use {_setRoleAdmin}. */ function getRoleAdmin(bytes32 role) public view override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _grantRole(role, account); } /** * @dev Revokes `role` from `account`. * * If `account` had been granted `role`, emits a {RoleRevoked} event. * * Requirements: * * - the caller must have ``role``'s admin role. */ function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { _revokeRole(role, account); } /** * @dev Revokes `role` from the calling account. * * Roles are often managed via {grantRole} and {revokeRole}: this function's * purpose is to provide a mechanism for accounts to lose their privileges * if they are compromised (such as when a trusted device is misplaced). * * If the calling account had been granted `role`, emits a {RoleRevoked} * event. * * Requirements: * * - the caller must be `account`. */ function renounceRole(bytes32 role, address account) public virtual override { require( account == _msgSender(), "AccessControl: can only renounce roles for self" ); _revokeRole(role, account); } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. Note that unlike {grantRole}, this function doesn't perform any * checks on the calling account. * * [WARNING] * ==== * This function should only be called from the constructor when setting * up the initial roles for the system. * * Using this function in any other way is effectively circumventing the admin * system imposed by {AccessControl}. * ==== */ function _setupRole(bytes32 role, address account) internal virtual { _grantRole(role, account); } /** * @dev Sets `adminRole` as ``role``'s admin role. * * Emits a {RoleAdminChanged} event. */ function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { emit RoleAdminChanged(role, getRoleAdmin(role), adminRole); _roles[role].adminRole = adminRole; } function _grantRole(bytes32 role, address account) private { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } function _revokeRole(bytes32 role, address account) private { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev String operations. */ library Strings { bytes16 private constant alphabet = "0123456789abcdef"; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { // Inspired by OraclizeAPI's implementation - MIT licence // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol if (value == 0) { return "0"; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return "0x00"; } uint256 temp = value; uint256 length = 0; while (temp != 0) { length++; temp >>= 8; } return toHexString(value, length); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = alphabet[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @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); }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "metadata": { "useLiteralContent": true } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"uint256","name":"_goodwill","type":"uint256"},{"internalType":"uint256","name":"_affiliateSplit","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"fromToken","type":"address"},{"internalType":"address","name":"toToken","type":"address"},{"internalType":"uint256[2]","name":"swapAmounts","type":"uint256[2]"},{"internalType":"uint256[2]","name":"minTokensRec","type":"uint256[2]"},{"internalType":"address[2]","name":"swapTargets","type":"address[2]"},{"internalType":"bytes[2]","name":"swapData","type":"bytes[2]"},{"internalType":"address","name":"affiliate","type":"address"}],"name":"ZapBridge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"affiliateBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"affiliates","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"affilliateWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approvedTargets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"depositManager","outputs":[{"internalType":"contract IDepositManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"feeWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"goodwill","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rootChainManager","outputs":[{"internalType":"contract IRootChainManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"targets","type":"address[]"},{"internalType":"bool[]","name":"isApproved","type":"bool[]"}],"name":"setApprovedTargets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_affiliate","type":"address"},{"internalType":"bool","name":"_status","type":"bool"}],"name":"set_affiliate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"zapAddress","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"set_feeWhitelist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_new_affiliateSplit","type":"uint256"}],"name":"set_new_affiliateSplit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_new_goodwill","type":"uint256"}],"name":"set_new_goodwill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopped","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"toggleContractActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalAffiliateBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"withdrawTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040526000805460ff60a01b19169055600880546001600160a01b031990811673a0c68c638235ee32657e8f720a23cec1bfc77c77179091556009805490911673401f6c983ea34274ec46f84d70b31c151321188b1790553480156200006657600080fd5b506040516200293f3803806200293f833981016040819052620000899162000618565b600080546001600160a01b03191633908117825560405184928492918291907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506002919091556003556009546200010490737d1afa7b718fb893db30a3abc0cfc608aacfebb0906001600160a01b031662000155565b505073def1c0ded9bec7f1a1670819833240f027b25eff60005260076020527ff6019cd1944dc466e824190b288e5a63528dd4c9a6d8cbd707956fd30d2f1e0d805460ff19166001179055620006c2565b604051636eb1769f60e11b81523060048201526001600160a01b038281166024830152839160009183169063dd62ed3e9060440160206040518083038186803b158015620001a257600080fd5b505afa158015620001b7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001dd9190620005ff565b1115620001e957505050565b6200021082600019836001600160a01b03166200021560201b62000fd4179092919060201c565b505050565b801580620002a35750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b1580156200026657600080fd5b505afa1580156200027b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002a19190620005ff565b155b6200031b5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527f20746f206e6f6e2d7a65726f20616c6c6f77616e63650000000000000000000060648201526084015b60405180910390fd5b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b17909152620002109185916200037316565b6000620003cf826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166200045160201b6200112b179092919060201c565b805190915015620002105780806020019051810190620003f09190620005dd565b620002105760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840162000312565b60606200046284846000856200046c565b90505b9392505050565b606082471015620004cf5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840162000312565b843b6200051f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640162000312565b600080866001600160a01b031685876040516200053d91906200063c565b60006040518083038185875af1925050503d80600081146200057c576040519150601f19603f3d011682016040523d82523d6000602084013e62000581565b606091505b509092509050620005948282866200059f565b979650505050505050565b60608315620005b057508162000465565b825115620005c15782518084602001fd5b8160405162461bcd60e51b81526004016200031291906200065a565b600060208284031215620005ef578081fd5b8151801515811462000465578182fd5b60006020828403121562000611578081fd5b5051919050565b600080604083850312156200062b578081fd5b505080516020909101519092909150565b60008251620006508184602087016200068f565b9190910192915050565b60208152600082518060208401526200067b8160408501602087016200068f565b601f01601f19169190910160400192915050565b60005b83811015620006ac57818101518382015260200162000692565b83811115620006bc576000848401525b50505050565b61226d80620006d26000396000f3fe60806040526004361061012e5760003560e01c80635ecb16cd116100ab5780639735a6341161006f5780639735a634146103b15780639779d1a6146103d1578063bd07018d14610401578063d408f65714610421578063f2fde38b14610451578063fbec27bf1461047157600080fd5b80635ecb16cd146103055780636c7ac9d814610325578063715018a61461035d57806375f12b21146103725780638da5cb5b1461039357600080fd5b80633ff428c7116100f25780633ff428c71461025c5780634f51e2941461027c578063510e92f3146102bc578063550bfa56146102cf5780635de0398e146102ef57600080fd5b806301e980d41461018f5780630dc9de85146101af5780631385d24c146101cf5780631781261f146101e457806318b135e31461022f57600080fd5b3661018a57333214156101885760405162461bcd60e51b815260206004820152601860248201527f446f206e6f742073656e6420455448206469726563746c79000000000000000060448201526064015b60405180910390fd5b005b600080fd5b34801561019b57600080fd5b506101886101aa36600461202d565b610491565b3480156101bb57600080fd5b506101886101ca366004611f34565b61051b565b3480156101db57600080fd5b50610188610776565b3480156101f057600080fd5b5061021c6101ff366004611e22565b600560209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b34801561023b57600080fd5b5061021c61024a366004611dea565b60066020526000908152604090205481565b34801561026857600080fd5b50610188610277366004611f07565b6107c1565b34801561028857600080fd5b506102ac610297366004611dea565b60046020526000908152604090205460ff1681565b6040519015158152602001610226565b6101886102ca366004611e5a565b610816565b3480156102db57600080fd5b506101886102ea36600461202d565b610a06565b3480156102fb57600080fd5b5061021c60025481565b34801561031157600080fd5b50610188610320366004611f34565b610a86565b34801561033157600080fd5b50600954610345906001600160a01b031681565b6040516001600160a01b039091168152602001610226565b34801561036957600080fd5b50610188610cf7565b34801561037e57600080fd5b506000546102ac90600160a01b900460ff1681565b34801561039f57600080fd5b506000546001600160a01b0316610345565b3480156103bd57600080fd5b506101886103cc366004611f74565b610d6b565b3480156103dd57600080fd5b506102ac6103ec366004611dea565b60076020526000908152604090205460ff1681565b34801561040d57600080fd5b50600854610345906001600160a01b031681565b34801561042d57600080fd5b506102ac61043c366004611dea565b60016020526000908152604090205460ff1681565b34801561045d57600080fd5b5061018861046c366004611dea565b610e95565b34801561047d57600080fd5b5061018861048c366004611f07565b610f7f565b6000546001600160a01b031633146104bb5760405162461bcd60e51b815260040161017f906120cc565b60648111156105165760405162461bcd60e51b815260206004820152602160248201527f416666696c696174652053706c69742056616c7565206e6f7420616c6c6f77656044820152601960fa1b606482015260840161017f565b600355565b6000805b82811015610770573360009081526005602052604081209085858481811061055757634e487b7160e01b600052603260045260246000fd5b905060200201602081019061056c9190611dea565b6001600160a01b031681526020808201929092526040908101600090812054338252600590935290812091935090818686858181106105bb57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906105d09190611dea565b6001600160a01b03166001600160a01b0316815260200190815260200160002081905550816006600086868581811061061957634e487b7160e01b600052603260045260246000fd5b905060200201602081019061062e9190611dea565b6001600160a01b03166001600160a01b0316815260200190815260200160002054610659919061219d565b6006600086868581811061067d57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906106929190611dea565b6001600160a01b0316815260208101919091526040016000205573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8484838181106106e157634e487b7160e01b600052603260045260246000fd5b90506020020160208101906106f69190611dea565b6001600160a01b031614156107145761070f3383611144565b61075e565b61075e338386868581811061073957634e487b7160e01b600052603260045260246000fd5b905060200201602081019061074e9190611dea565b6001600160a01b0316919061125d565b80610768816121e0565b91505061051f565b50505050565b6000546001600160a01b031633146107a05760405162461bcd60e51b815260040161017f906120cc565b6000805460ff60a01b198116600160a01b9182900460ff1615909102179055565b6000546001600160a01b031633146107eb5760405162461bcd60e51b815260040161017f906120cc565b6001600160a01b03919091166000908152600460205260409020805460ff1916911515919091179055565b600054600160a01b900460ff16156108655760405162461bcd60e51b815260206004820152601260248201527115195b5c1bdc985c9a5b1e4814185d5cd95960721b604482015260640161017f565b604080518082018252600091610897918a918990600290839083908082843760009201919091525086915061128d9050565b905085351561095d578051600090610907908a908a6108b960208a018a611dea565b8860005b6020028101906108cd9190612101565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061140d92505050565b905085358110156109515760405162461bcd60e51b81526020600482015260146024820152734552523a204869676820536c697070616765203160601b604482015260640161017f565b61095b8882611636565b505b6020860135156109fc576020808201516000916109a4918b91737d1afa7b718fb893db30a3abc0cfc608aacfebb09061099c9060408b01908b01611dea565b8860016108bd565b905060208601358110156109f15760405162461bcd60e51b815260206004820152601460248201527322a9291d102434b3b41029b634b83830b3b2901960611b604482015260640161017f565b6109fa81611832565b505b5050505050505050565b6000546001600160a01b03163314610a305760405162461bcd60e51b815260040161017f906120cc565b6064811115610a815760405162461bcd60e51b815260206004820152601a60248201527f476f6f6457696c6c2056616c7565206e6f7420616c6c6f776564000000000000604482015260640161017f565b600255565b6000546001600160a01b03163314610ab05760405162461bcd60e51b815260040161017f906120cc565b60005b81811015610cf257600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee848484818110610af257634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610b079190611dea565b6001600160a01b03161415610b955760066000858585818110610b3a57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610b4f9190611dea565b6001600160a01b03168152602081019190915260400160002054610b73904761219d565b9050610b90610b8a6000546001600160a01b031690565b82611144565b610cdf565b60066000858585818110610bb957634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610bce9190611dea565b6001600160a01b03166001600160a01b0316815260200190815260200160002054848484818110610c0f57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610c249190611dea565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a082319060240160206040518083038186803b158015610c6557600080fd5b505afa158015610c79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c9d9190612015565b610ca7919061219d565b9050610cdf610cbe6000546001600160a01b031690565b8286868681811061073957634e487b7160e01b600052603260045260246000fd5b5080610cea816121e0565b915050610ab3565b505050565b6000546001600160a01b03163314610d215760405162461bcd60e51b815260040161017f906120cc565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b03163314610d955760405162461bcd60e51b815260040161017f906120cc565b828114610ddb5760405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c84092dce0eae840d8cadccee8d60631b604482015260640161017f565b60005b83811015610e8e57828282818110610e0657634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610e1b9190611fdd565b60076000878785818110610e3f57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610e549190611dea565b6001600160a01b031681526020810191909152604001600020805460ff191691151591909117905580610e86816121e0565b915050610dde565b5050505050565b6000546001600160a01b03163314610ebf5760405162461bcd60e51b815260040161017f906120cc565b6001600160a01b038116610f245760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161017f565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610fa95760405162461bcd60e51b815260040161017f906120cc565b6001600160a01b03919091166000908152600160205260409020805460ff1916911515919091179055565b80158061105d5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b15801561102357600080fd5b505afa158015611037573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105b9190612015565b155b6110c85760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606482015260840161017f565b6040516001600160a01b038316602482015260448101829052610cf290849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526118ac565b606061113a848460008561197e565b90505b9392505050565b804710156111945760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015260640161017f565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146111e1576040519150601f19603f3d011682016040523d82523d6000602084013e6111e6565b606091505b5050905080610cf25760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d61792068617665207265766572746564000000000000606482015260840161017f565b6040516001600160a01b038316602482015260448101829052610cf290849063a9059cbb60e01b906064016110f4565b611295611d71565b6001600160a01b03841661134557600034116112e15760405162461bcd60e51b815260206004820152600b60248201526a139bc8195d1a081cd95b9d60aa1b604482015260640161017f565b6020830151835134916112f391612146565b146113405760405162461bcd60e51b815260206004820152601d60248201527f6d73672e76616c756520213d2066726f6d546f6b656e416d6f756e7473000000604482015260640161017f565b6113b3565b34156113895760405162461bcd60e51b815260206004820152601360248201527222ba341039b2b73a103bb4ba34103a37b5b2b760691b604482015260640161017f565b602083015183516113b391339130916113a191612146565b6001600160a01b038816929190611aa6565b8251156113dc576113cd848460005b602002015184611ade565b83516113d9919061219d565b81525b60208301511561113d576113f2848460016113c2565b6020840151611401919061219d565b60208201529392505050565b60006001600160a01b03861673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214801561144257506001600160a01b038416155b156114b75773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0866040518263ffffffff1660e01b81526004016000604051808303818588803b15801561149657600080fd5b505af11580156114aa573d6000803e3d6000fd5b505050505084905061162d565b6000846001600160a01b0316876001600160a01b031614156114dc578591505061162d565b6001600160a01b0387166114f15750846114fb565b6114fb8785611bff565b600061150686611ca4565b6001600160a01b03861660009081526007602052604090205490915060ff166115695760405162461bcd60e51b815260206004820152601560248201527415185c99d95d081b9bdd08105d5d1a1bdc9a5e9959605a1b604482015260640161017f565b6000856001600160a01b031683866040516115849190612071565b60006040518083038185875af1925050503d80600081146115c1576040519150601f19603f3d011682016040523d82523d6000602084013e6115c6565b606091505b505090508061160f5760405162461bcd60e51b81526020600482015260156024820152744572726f72205377617070696e6720546f6b656e7360581b604482015260640161017f565b600061161a88611ca4565b9050611626838261219d565b9450505050505b95945050505050565b6001600160a01b0382166116a7576008546040516327d5451360e11b81523360048201526001600160a01b0390911690634faa8a269083906024016000604051808303818588803b15801561168a57600080fd5b505af115801561169e573d6000803e3d6000fd5b50505050505050565b60085460405163721804d360e11b81526001600160a01b038481166004830152600092169063e43009a690602401602060405180830381600087803b1580156116ef57600080fd5b505af1158015611703573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117279190612015565b60085460405163e66f960360e01b8152600481018390529192506000916001600160a01b039091169063e66f960390602401602060405180830381600087803b15801561177357600080fd5b505af1158015611787573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ab9190611e06565b90506117b78482611bff565b600854604080516020808201879052825180830390910181528183019283905263e3dec8fb60e01b9092526001600160a01b039092169163e3dec8fb91611804913391899160440161208d565b600060405180830381600087803b15801561181e57600080fd5b505af11580156109fc573d6000803e3d6000fd5b600954604051638b9e4f9360e01b8152737d1afa7b718fb893db30a3abc0cfc608aacfebb06004820152336024820152604481018390526001600160a01b0390911690638b9e4f9390606401600060405180830381600087803b15801561189857600080fd5b505af1158015610e8e573d6000803e3d6000fd5b6000611901826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661112b9092919063ffffffff16565b805190915015610cf2578080602001905181019061191f9190611ff9565b610cf25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161017f565b6060824710156119df5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161017f565b843b611a2d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161017f565b600080866001600160a01b03168587604051611a499190612071565b60006040518083038185875af1925050503d8060008114611a86576040519150601f19603f3d011682016040523d82523d6000602084013e611a8b565b606091505b5091509150611a9b828286611d38565b979650505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526107709085906323b872dd60e01b906084016110f4565b3360009081526001602052604081205460ff1680158015611b0157506000600254115b15611bf75761271060025485611b17919061217e565b611b21919061215e565b6001600160a01b03841660009081526004602052604090205490925060ff1615611bf7576001600160a01b038516611b6b5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee94505b6000606460035484611b7d919061217e565b611b87919061215e565b6001600160a01b038086166000908152600560209081526040808320938b16835292905290812080549293508392909190611bc3908490612146565b90915550506001600160a01b03861660009081526006602052604081208054839290611bf0908490612146565b9091555050505b509392505050565b604051636eb1769f60e11b81523060048201526001600160a01b038281166024830152839160009183169063dd62ed3e9060440160206040518083038186803b158015611c4b57600080fd5b505afa158015611c5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c839190612015565b1115611c8e57505050565b610cf26001600160a01b03821683600019610fd4565b60006001600160a01b038216611cbb575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a082319060240160206040518083038186803b158015611cfa57600080fd5b505afa158015611d0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d329190612015565b92915050565b60608315611d4757508161113d565b825115611d575782518084602001fd5b8160405162461bcd60e51b815260040161017f91906120b9565b60405180604001604052806002906020820280368337509192915050565b8060408101831015611d3257600080fd5b60008083601f840112611db1578182fd5b50813567ffffffffffffffff811115611dc8578182fd5b6020830191508360208260051b8501011115611de357600080fd5b9250929050565b600060208284031215611dfb578081fd5b813561113d81612211565b600060208284031215611e17578081fd5b815161113d81612211565b60008060408385031215611e34578081fd5b8235611e3f81612211565b91506020830135611e4f81612211565b809150509250929050565b6000806000806000806000610140888a031215611e75578283fd5b8735611e8081612211565b96506020880135611e9081612211565b9550611e9f8960408a01611d8f565b9450611eae8960808a01611d8f565b9350611ebd8960c08a01611d8f565b925061010088013567ffffffffffffffff811115611ed9578283fd5b611ee58a828b01611d8f565b925050610120880135611ef781612211565b8091505092959891949750929550565b60008060408385031215611f19578182fd5b8235611f2481612211565b91506020830135611e4f81612229565b60008060208385031215611f46578182fd5b823567ffffffffffffffff811115611f5c578283fd5b611f6885828601611da0565b90969095509350505050565b60008060008060408587031215611f89578384fd5b843567ffffffffffffffff80821115611fa0578586fd5b611fac88838901611da0565b90965094506020870135915080821115611fc4578384fd5b50611fd187828801611da0565b95989497509550505050565b600060208284031215611fee578081fd5b813561113d81612229565b60006020828403121561200a578081fd5b815161113d81612229565b600060208284031215612026578081fd5b5051919050565b60006020828403121561203e578081fd5b5035919050565b6000815180845261205d8160208601602086016121b4565b601f01601f19169290920160200192915050565b600082516120838184602087016121b4565b9190910192915050565b6001600160a01b0384811682528316602082015260606040820181905260009061162d90830184612045565b60208152600061113d6020830184612045565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6000808335601e19843603018112612117578283fd5b83018035915067ffffffffffffffff821115612131578283fd5b602001915036819003821315611de357600080fd5b60008219821115612159576121596121fb565b500190565b60008261217957634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615612198576121986121fb565b500290565b6000828210156121af576121af6121fb565b500390565b60005b838110156121cf5781810151838201526020016121b7565b838111156107705750506000910152565b60006000198214156121f4576121f46121fb565b5060010190565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811461222657600080fd5b50565b801515811461222657600080fdfea2646970667358221220b15ed18efc59a00718b2feed77f21004a5f67ad01c3985e801c68a2840bbe07464736f6c6343000804003300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x60806040526004361061012e5760003560e01c80635ecb16cd116100ab5780639735a6341161006f5780639735a634146103b15780639779d1a6146103d1578063bd07018d14610401578063d408f65714610421578063f2fde38b14610451578063fbec27bf1461047157600080fd5b80635ecb16cd146103055780636c7ac9d814610325578063715018a61461035d57806375f12b21146103725780638da5cb5b1461039357600080fd5b80633ff428c7116100f25780633ff428c71461025c5780634f51e2941461027c578063510e92f3146102bc578063550bfa56146102cf5780635de0398e146102ef57600080fd5b806301e980d41461018f5780630dc9de85146101af5780631385d24c146101cf5780631781261f146101e457806318b135e31461022f57600080fd5b3661018a57333214156101885760405162461bcd60e51b815260206004820152601860248201527f446f206e6f742073656e6420455448206469726563746c79000000000000000060448201526064015b60405180910390fd5b005b600080fd5b34801561019b57600080fd5b506101886101aa36600461202d565b610491565b3480156101bb57600080fd5b506101886101ca366004611f34565b61051b565b3480156101db57600080fd5b50610188610776565b3480156101f057600080fd5b5061021c6101ff366004611e22565b600560209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b34801561023b57600080fd5b5061021c61024a366004611dea565b60066020526000908152604090205481565b34801561026857600080fd5b50610188610277366004611f07565b6107c1565b34801561028857600080fd5b506102ac610297366004611dea565b60046020526000908152604090205460ff1681565b6040519015158152602001610226565b6101886102ca366004611e5a565b610816565b3480156102db57600080fd5b506101886102ea36600461202d565b610a06565b3480156102fb57600080fd5b5061021c60025481565b34801561031157600080fd5b50610188610320366004611f34565b610a86565b34801561033157600080fd5b50600954610345906001600160a01b031681565b6040516001600160a01b039091168152602001610226565b34801561036957600080fd5b50610188610cf7565b34801561037e57600080fd5b506000546102ac90600160a01b900460ff1681565b34801561039f57600080fd5b506000546001600160a01b0316610345565b3480156103bd57600080fd5b506101886103cc366004611f74565b610d6b565b3480156103dd57600080fd5b506102ac6103ec366004611dea565b60076020526000908152604090205460ff1681565b34801561040d57600080fd5b50600854610345906001600160a01b031681565b34801561042d57600080fd5b506102ac61043c366004611dea565b60016020526000908152604090205460ff1681565b34801561045d57600080fd5b5061018861046c366004611dea565b610e95565b34801561047d57600080fd5b5061018861048c366004611f07565b610f7f565b6000546001600160a01b031633146104bb5760405162461bcd60e51b815260040161017f906120cc565b60648111156105165760405162461bcd60e51b815260206004820152602160248201527f416666696c696174652053706c69742056616c7565206e6f7420616c6c6f77656044820152601960fa1b606482015260840161017f565b600355565b6000805b82811015610770573360009081526005602052604081209085858481811061055757634e487b7160e01b600052603260045260246000fd5b905060200201602081019061056c9190611dea565b6001600160a01b031681526020808201929092526040908101600090812054338252600590935290812091935090818686858181106105bb57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906105d09190611dea565b6001600160a01b03166001600160a01b0316815260200190815260200160002081905550816006600086868581811061061957634e487b7160e01b600052603260045260246000fd5b905060200201602081019061062e9190611dea565b6001600160a01b03166001600160a01b0316815260200190815260200160002054610659919061219d565b6006600086868581811061067d57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906106929190611dea565b6001600160a01b0316815260208101919091526040016000205573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8484838181106106e157634e487b7160e01b600052603260045260246000fd5b90506020020160208101906106f69190611dea565b6001600160a01b031614156107145761070f3383611144565b61075e565b61075e338386868581811061073957634e487b7160e01b600052603260045260246000fd5b905060200201602081019061074e9190611dea565b6001600160a01b0316919061125d565b80610768816121e0565b91505061051f565b50505050565b6000546001600160a01b031633146107a05760405162461bcd60e51b815260040161017f906120cc565b6000805460ff60a01b198116600160a01b9182900460ff1615909102179055565b6000546001600160a01b031633146107eb5760405162461bcd60e51b815260040161017f906120cc565b6001600160a01b03919091166000908152600460205260409020805460ff1916911515919091179055565b600054600160a01b900460ff16156108655760405162461bcd60e51b815260206004820152601260248201527115195b5c1bdc985c9a5b1e4814185d5cd95960721b604482015260640161017f565b604080518082018252600091610897918a918990600290839083908082843760009201919091525086915061128d9050565b905085351561095d578051600090610907908a908a6108b960208a018a611dea565b8860005b6020028101906108cd9190612101565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061140d92505050565b905085358110156109515760405162461bcd60e51b81526020600482015260146024820152734552523a204869676820536c697070616765203160601b604482015260640161017f565b61095b8882611636565b505b6020860135156109fc576020808201516000916109a4918b91737d1afa7b718fb893db30a3abc0cfc608aacfebb09061099c9060408b01908b01611dea565b8860016108bd565b905060208601358110156109f15760405162461bcd60e51b815260206004820152601460248201527322a9291d102434b3b41029b634b83830b3b2901960611b604482015260640161017f565b6109fa81611832565b505b5050505050505050565b6000546001600160a01b03163314610a305760405162461bcd60e51b815260040161017f906120cc565b6064811115610a815760405162461bcd60e51b815260206004820152601a60248201527f476f6f6457696c6c2056616c7565206e6f7420616c6c6f776564000000000000604482015260640161017f565b600255565b6000546001600160a01b03163314610ab05760405162461bcd60e51b815260040161017f906120cc565b60005b81811015610cf257600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee848484818110610af257634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610b079190611dea565b6001600160a01b03161415610b955760066000858585818110610b3a57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610b4f9190611dea565b6001600160a01b03168152602081019190915260400160002054610b73904761219d565b9050610b90610b8a6000546001600160a01b031690565b82611144565b610cdf565b60066000858585818110610bb957634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610bce9190611dea565b6001600160a01b03166001600160a01b0316815260200190815260200160002054848484818110610c0f57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610c249190611dea565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a082319060240160206040518083038186803b158015610c6557600080fd5b505afa158015610c79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c9d9190612015565b610ca7919061219d565b9050610cdf610cbe6000546001600160a01b031690565b8286868681811061073957634e487b7160e01b600052603260045260246000fd5b5080610cea816121e0565b915050610ab3565b505050565b6000546001600160a01b03163314610d215760405162461bcd60e51b815260040161017f906120cc565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b03163314610d955760405162461bcd60e51b815260040161017f906120cc565b828114610ddb5760405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c84092dce0eae840d8cadccee8d60631b604482015260640161017f565b60005b83811015610e8e57828282818110610e0657634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610e1b9190611fdd565b60076000878785818110610e3f57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610e549190611dea565b6001600160a01b031681526020810191909152604001600020805460ff191691151591909117905580610e86816121e0565b915050610dde565b5050505050565b6000546001600160a01b03163314610ebf5760405162461bcd60e51b815260040161017f906120cc565b6001600160a01b038116610f245760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161017f565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b03163314610fa95760405162461bcd60e51b815260040161017f906120cc565b6001600160a01b03919091166000908152600160205260409020805460ff1916911515919091179055565b80158061105d5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b15801561102357600080fd5b505afa158015611037573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061105b9190612015565b155b6110c85760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b606482015260840161017f565b6040516001600160a01b038316602482015260448101829052610cf290849063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526118ac565b606061113a848460008561197e565b90505b9392505050565b804710156111945760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015260640161017f565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146111e1576040519150601f19603f3d011682016040523d82523d6000602084013e6111e6565b606091505b5050905080610cf25760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d61792068617665207265766572746564000000000000606482015260840161017f565b6040516001600160a01b038316602482015260448101829052610cf290849063a9059cbb60e01b906064016110f4565b611295611d71565b6001600160a01b03841661134557600034116112e15760405162461bcd60e51b815260206004820152600b60248201526a139bc8195d1a081cd95b9d60aa1b604482015260640161017f565b6020830151835134916112f391612146565b146113405760405162461bcd60e51b815260206004820152601d60248201527f6d73672e76616c756520213d2066726f6d546f6b656e416d6f756e7473000000604482015260640161017f565b6113b3565b34156113895760405162461bcd60e51b815260206004820152601360248201527222ba341039b2b73a103bb4ba34103a37b5b2b760691b604482015260640161017f565b602083015183516113b391339130916113a191612146565b6001600160a01b038816929190611aa6565b8251156113dc576113cd848460005b602002015184611ade565b83516113d9919061219d565b81525b60208301511561113d576113f2848460016113c2565b6020840151611401919061219d565b60208201529392505050565b60006001600160a01b03861673c02aaa39b223fe8d0a0e5c4f27ead9083c756cc214801561144257506001600160a01b038416155b156114b75773c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0866040518263ffffffff1660e01b81526004016000604051808303818588803b15801561149657600080fd5b505af11580156114aa573d6000803e3d6000fd5b505050505084905061162d565b6000846001600160a01b0316876001600160a01b031614156114dc578591505061162d565b6001600160a01b0387166114f15750846114fb565b6114fb8785611bff565b600061150686611ca4565b6001600160a01b03861660009081526007602052604090205490915060ff166115695760405162461bcd60e51b815260206004820152601560248201527415185c99d95d081b9bdd08105d5d1a1bdc9a5e9959605a1b604482015260640161017f565b6000856001600160a01b031683866040516115849190612071565b60006040518083038185875af1925050503d80600081146115c1576040519150601f19603f3d011682016040523d82523d6000602084013e6115c6565b606091505b505090508061160f5760405162461bcd60e51b81526020600482015260156024820152744572726f72205377617070696e6720546f6b656e7360581b604482015260640161017f565b600061161a88611ca4565b9050611626838261219d565b9450505050505b95945050505050565b6001600160a01b0382166116a7576008546040516327d5451360e11b81523360048201526001600160a01b0390911690634faa8a269083906024016000604051808303818588803b15801561168a57600080fd5b505af115801561169e573d6000803e3d6000fd5b50505050505050565b60085460405163721804d360e11b81526001600160a01b038481166004830152600092169063e43009a690602401602060405180830381600087803b1580156116ef57600080fd5b505af1158015611703573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117279190612015565b60085460405163e66f960360e01b8152600481018390529192506000916001600160a01b039091169063e66f960390602401602060405180830381600087803b15801561177357600080fd5b505af1158015611787573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117ab9190611e06565b90506117b78482611bff565b600854604080516020808201879052825180830390910181528183019283905263e3dec8fb60e01b9092526001600160a01b039092169163e3dec8fb91611804913391899160440161208d565b600060405180830381600087803b15801561181e57600080fd5b505af11580156109fc573d6000803e3d6000fd5b600954604051638b9e4f9360e01b8152737d1afa7b718fb893db30a3abc0cfc608aacfebb06004820152336024820152604481018390526001600160a01b0390911690638b9e4f9390606401600060405180830381600087803b15801561189857600080fd5b505af1158015610e8e573d6000803e3d6000fd5b6000611901826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661112b9092919063ffffffff16565b805190915015610cf2578080602001905181019061191f9190611ff9565b610cf25760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161017f565b6060824710156119df5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161017f565b843b611a2d5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161017f565b600080866001600160a01b03168587604051611a499190612071565b60006040518083038185875af1925050503d8060008114611a86576040519150601f19603f3d011682016040523d82523d6000602084013e611a8b565b606091505b5091509150611a9b828286611d38565b979650505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526107709085906323b872dd60e01b906084016110f4565b3360009081526001602052604081205460ff1680158015611b0157506000600254115b15611bf75761271060025485611b17919061217e565b611b21919061215e565b6001600160a01b03841660009081526004602052604090205490925060ff1615611bf7576001600160a01b038516611b6b5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee94505b6000606460035484611b7d919061217e565b611b87919061215e565b6001600160a01b038086166000908152600560209081526040808320938b16835292905290812080549293508392909190611bc3908490612146565b90915550506001600160a01b03861660009081526006602052604081208054839290611bf0908490612146565b9091555050505b509392505050565b604051636eb1769f60e11b81523060048201526001600160a01b038281166024830152839160009183169063dd62ed3e9060440160206040518083038186803b158015611c4b57600080fd5b505afa158015611c5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c839190612015565b1115611c8e57505050565b610cf26001600160a01b03821683600019610fd4565b60006001600160a01b038216611cbb575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a082319060240160206040518083038186803b158015611cfa57600080fd5b505afa158015611d0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d329190612015565b92915050565b60608315611d4757508161113d565b825115611d575782518084602001fd5b8160405162461bcd60e51b815260040161017f91906120b9565b60405180604001604052806002906020820280368337509192915050565b8060408101831015611d3257600080fd5b60008083601f840112611db1578182fd5b50813567ffffffffffffffff811115611dc8578182fd5b6020830191508360208260051b8501011115611de357600080fd5b9250929050565b600060208284031215611dfb578081fd5b813561113d81612211565b600060208284031215611e17578081fd5b815161113d81612211565b60008060408385031215611e34578081fd5b8235611e3f81612211565b91506020830135611e4f81612211565b809150509250929050565b6000806000806000806000610140888a031215611e75578283fd5b8735611e8081612211565b96506020880135611e9081612211565b9550611e9f8960408a01611d8f565b9450611eae8960808a01611d8f565b9350611ebd8960c08a01611d8f565b925061010088013567ffffffffffffffff811115611ed9578283fd5b611ee58a828b01611d8f565b925050610120880135611ef781612211565b8091505092959891949750929550565b60008060408385031215611f19578182fd5b8235611f2481612211565b91506020830135611e4f81612229565b60008060208385031215611f46578182fd5b823567ffffffffffffffff811115611f5c578283fd5b611f6885828601611da0565b90969095509350505050565b60008060008060408587031215611f89578384fd5b843567ffffffffffffffff80821115611fa0578586fd5b611fac88838901611da0565b90965094506020870135915080821115611fc4578384fd5b50611fd187828801611da0565b95989497509550505050565b600060208284031215611fee578081fd5b813561113d81612229565b60006020828403121561200a578081fd5b815161113d81612229565b600060208284031215612026578081fd5b5051919050565b60006020828403121561203e578081fd5b5035919050565b6000815180845261205d8160208601602086016121b4565b601f01601f19169290920160200192915050565b600082516120838184602087016121b4565b9190910192915050565b6001600160a01b0384811682528316602082015260606040820181905260009061162d90830184612045565b60208152600061113d6020830184612045565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b6000808335601e19843603018112612117578283fd5b83018035915067ffffffffffffffff821115612131578283fd5b602001915036819003821315611de357600080fd5b60008219821115612159576121596121fb565b500190565b60008261217957634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615612198576121986121fb565b500290565b6000828210156121af576121af6121fb565b500390565b60005b838110156121cf5781810151838201526020016121b7565b838111156107705750506000910152565b60006000198214156121f4576121f46121fb565b5060010190565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811461222657600080fd5b50565b801515811461222657600080fdfea2646970667358221220b15ed18efc59a00718b2feed77f21004a5f67ad01c3985e801c68a2840bbe07464736f6c63430008040033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _goodwill (uint256): 0
Arg [1] : _affiliateSplit (uint256): 0
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode Sourcemap
2470:6123:1:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4685:10:6;4699:9;4685:23;;4677:60;;;;-1:-1:-1;;;4677:60:6;;9423:2:21;4677:60:6;;;9405:21:21;9462:2;9442:18;;;9435:30;9501:26;9481:18;;;9474:54;9545:18;;4677:60:6;;;;;;;;;2470:6123:1;;;;;2521:269:6;;;;;;;;;;-1:-1:-1;2521:269:6;;;;;:::i;:::-;;:::i;3674:621::-;;;;;;;;;;-1:-1:-1;3674:621:6;;;;;:::i;:::-;;:::i;2039:84::-;;;;;;;;;;;;;:::i;565:71::-;;;;;;;;;;-1:-1:-1;565:71:6;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;8147:25:21;;;8135:2;8120:18;565:71:6;;;;;;;;665:56;;;;;;;;;;-1:-1:-1;665:56:6;;;;;:::i;:::-;;;;;;;;;;;;;;2796:145;;;;;;;;;;-1:-1:-1;2796:145:6;;;;;:::i;:::-;;:::i;481:42::-;;;;;;;;;;-1:-1:-1;481:42:6;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;7974:14:21;;7967:22;7949:41;;7937:2;7922:18;481:42:6;7904:92:21;3757:1268:1;;;;;;:::i;:::-;;:::i;2283:232:6:-;;;;;;;;;;-1:-1:-1;2283:232:6;;;;;:::i;:::-;;:::i;360:23::-;;;;;;;;;;;;;;;;3014:587;;;;;;;;;;-1:-1:-1;3014:587:6;;;;;:::i;:::-;;:::i;2776:107:1:-;;;;;;;;;;-1:-1:-1;2776:107:1;;;;-1:-1:-1;;;;;2776:107:1;;;;;;-1:-1:-1;;;;;6377:32:21;;;6359:51;;6347:2;6332:18;2776:107:1;6314:102:21;1722:145:10;;;;;;;;;;;;;:::i;234:27:6:-;;;;;;;;;;-1:-1:-1;234:27:6;;;;-1:-1:-1;;;234:27:6;;;;;;1090:85:10;;;;;;;;;;-1:-1:-1;1136:7:10;1162:6;-1:-1:-1;;;;;1162:6:10;1090:85;;4301:333:6;;;;;;;;;;-1:-1:-1;4301:333:6;;;;;:::i;:::-;;:::i;764:47::-;;;;;;;;;;-1:-1:-1;764:47:6;;;;;:::i;:::-;;;;;;;;;;;;;;;;2657:113:1;;;;;;;;;;-1:-1:-1;2657:113:1;;;;-1:-1:-1;;;;;2657:113:1;;;309:44:6;;;;;;;;;;-1:-1:-1;309:44:6;;;;;:::i;:::-;;;;;;;;;;;;;;;;2016:274:10;;;;;;;;;;-1:-1:-1;2016:274:10;;;;;:::i;:::-;;:::i;2129:148:6:-;;;;;;;;;;-1:-1:-1;2129:148:6;;;;;:::i;:::-;;:::i;2521:269::-;1136:7:10;1162:6;-1:-1:-1;;;;;1162:6:10;665:10:17;1302:23:10;1294:68;;;;-1:-1:-1;;;1294:68:10;;;;;;;:::i;:::-;2675:3:6::1;2652:19;:26;;2631:106;;;::::0;-1:-1:-1;;;2631:106:6;;14171:2:21;2631:106:6::1;::::0;::::1;14153:21:21::0;14210:2;14190:18;;;14183:30;14249:34;14229:18;;;14222:62;-1:-1:-1;;;14300:18:21;;;14293:31;14341:19;;2631:106:6::1;14143:223:21::0;2631:106:6::1;2747:14;:36:::0;2521:269::o;3674:621::-;3748:16;;3774:515;3794:17;;;3774:515;;;3860:10;3843:28;;;;:16;:28;;;;;;3872:6;;3879:1;3872:9;;;;;-1:-1:-1;;;3872:9:6;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;3843:39:6;;;;;;;;;;;;;;;-1:-1:-1;3843:39:6;;;;3913:10;3896:28;;:16;:28;;;;;;3843:39;;-1:-1:-1;;;3925:6:6;;3932:1;3925:9;;;;;-1:-1:-1;;;3925:9:6;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;3896:39:6;-1:-1:-1;;;;;3896:39:6;;;;;;;;;;;;:43;;;;4055:8;4004:21;:32;4026:6;;4033:1;4026:9;;;;;-1:-1:-1;;;4026:9:6;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;4004:32:6;-1:-1:-1;;;;;4004:32:6;;;;;;;;;;;;;:59;;;;:::i;:::-;3953:21;:32;3975:6;;3982:1;3975:9;;;;;-1:-1:-1;;;3975:9:6;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;3953:32:6;;;;;;;;;;;;-1:-1:-1;3953:32:6;:110;865:42;4082:6;;4089:1;4082:9;;;;;-1:-1:-1;;;4082:9:6;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;4082:23:6;;4078:201;;;4125:48;4151:10;4164:8;4125:17;:48::i;:::-;4078:201;;;4212:52;4243:10;4255:8;4219:6;;4226:1;4219:9;;;;;-1:-1:-1;;;4219:9:6;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;4212:30:6;;:52;:30;:52::i;:::-;3813:3;;;;:::i;:::-;;;;3774:515;;;;3674:621;;;:::o;2039:84::-;1136:7:10;1162:6;-1:-1:-1;;;;;1162:6:10;665:10:17;1302:23:10;1294:68;;;;-1:-1:-1;;;1294:68:10;;;;;;;:::i;:::-;2109:7:6::1;::::0;;-1:-1:-1;;;;2098:18:6;::::1;-1:-1:-1::0;;;2109:7:6;;;::::1;;;2108:8;2098:18:::0;;::::1;;::::0;;2039:84::o;2796:145::-;1136:7:10;1162:6;-1:-1:-1;;;;;1162:6:10;665:10:17;1302:23:10;1294:68;;;;-1:-1:-1;;;1294:68:10;;;;;;;:::i;:::-;-1:-1:-1;;;;;2902:22:6;;;::::1;;::::0;;;:10:::1;:22;::::0;;;;:32;;-1:-1:-1;;2902:32:6::1;::::0;::::1;;::::0;;;::::1;::::0;;2796:145::o;3757:1268:1:-;1127:7:6;;-1:-1:-1;;;1127:7:6;;;;1123:98;;;1150:28;;-1:-1:-1;;;1150:28:6;;12015:2:21;1150:28:6;;;11997:21:21;12054:2;12034:18;;;12027:30;-1:-1:-1;;;12073:18:21;;;12066:48;12131:18;;1150:28:6;11987:168:21;1123:98:6;4105:46:1;;;;;::::1;::::0;;4064:26:::1;::::0;4105:46:::1;::::0;4117:9;;4128:11;;4105:46:::1;::::0;;;4128:11;;4105:46;4128:11;4105:46;::::1;;::::0;::::1;::::0;;;;-1:-1:-1;4141:9:1;;-1:-1:-1;4105:11:1::1;::::0;-1:-1:-1;4105:46:1:i:1;:::-;4064:87:::0;-1:-1:-1;4166:14:1;::::1;:18:::0;4162:426:::1;;4326:11:::0;;4226:18:::1;::::0;4263:190:::1;::::0;4295:9;;4359:7;4388:14:::1;4326:11;4388:14:::0;::::1;:11:::0;:14:::1;:::i;:::-;4424:8:::0;4433:1:::1;4424:11;;;;;;;;;;:::i;:::-;4263:190;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;4263:10:1::1;::::0;-1:-1:-1;;;4263:190:1:i:1;:::-;4226:227:::0;-1:-1:-1;4489:15:1;::::1;4475:29:::0;::::1;;4467:62;;;::::0;-1:-1:-1;;;4467:62:1;;10183:2:21;4467:62:1::1;::::0;::::1;10165:21:21::0;10222:2;10202:18;;;10195:30;-1:-1:-1;;;10241:18:21;;;10234:50;10301:18;;4467:62:1::1;10155:170:21::0;4467:62:1::1;4544:33;4557:7;4566:10;4544:12;:33::i;:::-;4162:426;;4624:14;::::0;::::1;;:18:::0;4620:399:::1;;4759:11;::::0;;::::1;::::0;4658:19:::1;::::0;4696:195:::1;::::0;4728:9;;2938:42:::1;::::0;4826:14:::1;::::0;;;;;;::::1;;:::i;:::-;4862:8:::0;4871:1:::1;4862:11;::::0;4696:195:::1;4658:233:::0;-1:-1:-1;4928:15:1::1;::::0;::::1;;4913:30:::0;::::1;;4905:63;;;::::0;-1:-1:-1;;;4905:63:1;;15703:2:21;4905:63:1::1;::::0;::::1;15685:21:21::0;15742:2;15722:18;;;15715:30;-1:-1:-1;;;15761:18:21;;;15754:50;15821:18;;4905:63:1::1;15675:170:21::0;4905:63:1::1;4983:25;4996:11;4983:12;:25::i;:::-;4620:399;;1209:1:6;3757:1268:1::0;;;;;;;:::o;2283:232:6:-;1136:7:10;1162:6;-1:-1:-1;;;;;1162:6:10;665:10:17;1302:23:10;1294:68;;;;-1:-1:-1;;;1294:68:10;;;;;;;:::i;:::-;2419:3:6::1;2402:13;:20;;2359:115;;;::::0;-1:-1:-1;;;2359:115:6;;13127:2:21;2359:115:6::1;::::0;::::1;13109:21:21::0;13166:2;13146:18;;;13139:30;13205:28;13185:18;;;13178:56;13251:18;;2359:115:6::1;13099:176:21::0;2359:115:6::1;2484:8;:24:::0;2283:232::o;3014:587::-;1136:7:10;1162:6;-1:-1:-1;;;;;1162:6:10;665:10:17;1302:23:10;1294:68;;;;-1:-1:-1;;;1294:68:10;;;;;;;:::i;:::-;3099:9:6::1;3094:501;3114:17:::0;;::::1;3094:501;;;3152:11;865:42;3182:6:::0;;3189:1;3182:9;;::::1;;;-1:-1:-1::0;;;3182:9:6::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;3182:23:6::1;;3178:407;;;3255:21;:32;3277:6;;3284:1;3277:9;;;;;-1:-1:-1::0;;;3277:9:6::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;3255:32:6::1;::::0;;::::1;::::0;::::1;::::0;;;;;;-1:-1:-1;3255:32:6;;3231:56:::1;::::0;:21:::1;:56;:::i;:::-;3225:62;;3306:40;3332:7;1136::10::0;1162:6;-1:-1:-1;;;;;1162:6:10;;1090:85;3332:7:6::1;3342:3;3306:17;:40::i;:::-;3178:407;;;3476:21;:32;3498:6;;3505:1;3498:9;;;;;-1:-1:-1::0;;;3498:9:6::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;3476:32:6::1;-1:-1:-1::0;;;;;3476:32:6::1;;;;;;;;;;;;;3418:6;;3425:1;3418:9;;;;;-1:-1:-1::0;;;3418:9:6::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3411:42;::::0;-1:-1:-1;;;3411:42:6;;3447:4:::1;3411:42;::::0;::::1;6359:51:21::0;-1:-1:-1;;;;;3411:27:6;;;::::1;::::0;::::1;::::0;6332:18:21;;3411:42:6::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:97;;;;:::i;:::-;3385:123;;3526:44;3557:7;1136::10::0;1162:6;-1:-1:-1;;;;;1162:6:10;;1090:85;3557:7:6::1;3566:3;3533:6;;3540:1;3533:9;;;;;-1:-1:-1::0;;;3533:9:6::1;;;;;;;;3526:44;-1:-1:-1::0;3133:3:6;::::1;::::0;::::1;:::i;:::-;;;;3094:501;;;;3014:587:::0;;:::o;1722:145:10:-;1136:7;1162:6;-1:-1:-1;;;;;1162:6:10;665:10:17;1302:23:10;1294:68;;;;-1:-1:-1;;;1294:68:10;;;;;;;:::i;:::-;1828:1:::1;1812:6:::0;;1791:40:::1;::::0;-1:-1:-1;;;;;1812:6:10;;::::1;::::0;1791:40:::1;::::0;1828:1;;1791:40:::1;1858:1;1841:19:::0;;-1:-1:-1;;;;;;1841:19:10::1;::::0;;1722:145::o;4301:333:6:-;1136:7:10;1162:6;-1:-1:-1;;;;;1162:6:10;665:10:17;1302:23:10;1294:68;;;;-1:-1:-1;;;1294:68:10;;;;;;;:::i;:::-;4444:35:6;;::::1;4436:68;;;::::0;-1:-1:-1;;;4436:68:6;;13822:2:21;4436:68:6::1;::::0;::::1;13804:21:21::0;13861:2;13841:18;;;13834:30;-1:-1:-1;;;13880:18:21;;;13873:50;13940:18;;4436:68:6::1;13794:170:21::0;4436:68:6::1;4520:9;4515:113;4535:18:::0;;::::1;4515:113;;;4604:10;;4615:1;4604:13;;;;;-1:-1:-1::0;;;4604:13:6::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4574:15;:27;4590:7;;4598:1;4590:10;;;;;-1:-1:-1::0;;;4590:10:6::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;4574:27:6::1;::::0;;::::1;::::0;::::1;::::0;;;;;;-1:-1:-1;4574:27:6;:43;;-1:-1:-1;;4574:43:6::1;::::0;::::1;;::::0;;;::::1;::::0;;4555:3;::::1;::::0;::::1;:::i;:::-;;;;4515:113;;;;4301:333:::0;;;;:::o;2016:274:10:-;1136:7;1162:6;-1:-1:-1;;;;;1162:6:10;665:10:17;1302:23:10;1294:68;;;;-1:-1:-1;;;1294:68:10;;;;;;;:::i;:::-;-1:-1:-1;;;;;2117:22:10;::::1;2096:107;;;::::0;-1:-1:-1;;;2096:107:10;;9776:2:21;2096:107:10::1;::::0;::::1;9758:21:21::0;9815:2;9795:18;;;9788:30;9854:34;9834:18;;;9827:62;-1:-1:-1;;;9905:18:21;;;9898:36;9951:19;;2096:107:10::1;9748:228:21::0;2096:107:10::1;2239:6;::::0;;2218:38:::1;::::0;-1:-1:-1;;;;;2218:38:10;;::::1;::::0;2239:6;::::1;::::0;2218:38:::1;::::0;::::1;2266:6;:17:::0;;-1:-1:-1;;;;;;2266:17:10::1;-1:-1:-1::0;;;;;2266:17:10;;;::::1;::::0;;;::::1;::::0;;2016:274::o;2129:148:6:-;1136:7:10;1162:6;-1:-1:-1;;;;;1162:6:10;665:10:17;1302:23:10;1294:68;;;;-1:-1:-1;;;1294:68:10;;;;;;;:::i;:::-;-1:-1:-1;;;;;2237:24:6;;;::::1;;::::0;;;:12:::1;:24;::::0;;;;:33;;-1:-1:-1;;2237:33:6::1;::::0;::::1;;::::0;;;::::1;::::0;;2129:148::o;1414:690:14:-;1822:10;;;1821:62;;-1:-1:-1;1838:39:14;;-1:-1:-1;;;1838:39:14;;1862:4;1838:39;;;6633:34:21;-1:-1:-1;;;;;6703:15:21;;;6683:18;;;6676:43;1838:15:14;;;;;6568:18:21;;1838:39:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;1821:62;1800:163;;;;-1:-1:-1;;;1800:163:14;;16052:2:21;1800:163:14;;;16034:21:21;16091:2;16071:18;;;16064:30;16130:34;16110:18;;;16103:62;-1:-1:-1;;;16181:18:21;;;16174:52;16243:19;;1800:163:14;16024:244:21;1800:163:14;2025:62;;-1:-1:-1;;;;;7722:32:21;;2025:62:14;;;7704:51:21;7771:18;;;7764:34;;;1973:124:14;;2006:5;;-1:-1:-1;;;2048:22:14;7677:18:21;;2025:62:14;;;;-1:-1:-1;;2025:62:14;;;;;;;;;;;;;;-1:-1:-1;;;;;2025:62:14;-1:-1:-1;;;;;;2025:62:14;;;;;;;;;;1973:19;:124::i;3683:223:16:-;3816:12;3847:52;3869:6;3877:4;3883:1;3886:12;3847:21;:52::i;:::-;3840:59;;3683:223;;;;;;:::o;2068:459::-;2195:6;2170:21;:31;;2149:107;;;;-1:-1:-1;;;2149:107:16;;12362:2:21;2149:107:16;;;12344:21:21;12401:2;12381:18;;;12374:30;12440:31;12420:18;;;12413:59;12489:18;;2149:107:16;12334:179:21;2149:107:16;2345:12;2363:9;-1:-1:-1;;;;;2363:14:16;2386:6;2363:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2344:54;;;2429:7;2408:112;;;;-1:-1:-1;;;2408:112:16;;11240:2:21;2408:112:16;;;11222:21:21;11279:2;11259:18;;;11252:30;11318:34;11298:18;;;11291:62;11389:28;11369:18;;;11362:56;11435:19;;2408:112:16;11212:248:21;634:239:14;798:58;;-1:-1:-1;;;;;7722:32:21;;798:58:14;;;7704:51:21;7771:18;;;7764:34;;;746:120:14;;779:5;;-1:-1:-1;;;821:23:14;7677:18:21;;798:58:14;7659:145:21;6787:1059:1;6925:26;;:::i;:::-;-1:-1:-1;;;;;6967:23:1;;6963:519;;7026:1;7014:9;:13;7006:37;;;;-1:-1:-1;;;7006:37:1;;13482:2:21;7006:37:1;;;13464:21:21;13521:2;13501:18;;;13494:30;-1:-1:-1;;;13540:18:21;;;13533:41;13591:18;;7006:37:1;13454:161:21;7006:37:1;7100:14;;;;7082;;7119:9;;7082:33;;;:::i;:::-;:46;7057:134;;;;-1:-1:-1;;;7057:134:1;;10882:2:21;7057:134:1;;;10864:21:21;10921:2;10901:18;;;10894:30;10960:31;10940:18;;;10933:59;11009:18;;7057:134:1;10854:179:21;7057:134:1;6963:519;;;7230:9;:14;7222:46;;;;-1:-1:-1;;;7222:46:1;;11667:2:21;7222:46:1;;;11649:21:21;11706:2;11686:18;;;11679:30;-1:-1:-1;;;11725:18:21;;;11718:49;11784:18;;7222:46:1;11639:169:21;7222:46:1;7442:14;;;;7424;;7313:158;;7365:10;;7401:4;;7424:33;;;:::i;:::-;-1:-1:-1;;;;;7313:34:1;;;:158;;:34;:158::i;:::-;7496:14;;:18;7492:169;;7594:55;7612:9;7623:11;7635:1;7623:14;;;;;7639:9;7594:17;:55::i;:::-;7560:14;;:90;;;;:::i;:::-;7530:120;;7492:169;7675:14;;;;:18;7671:169;;7773:55;7791:9;7802:11;7814:1;7802:14;;7773:55;7739:14;;;;:90;;;;:::i;:::-;7709:11;;;:120;:8;6787:1059;-1:-1:-1;;;6787:1059:1:o;5807:974::-;5990:17;-1:-1:-1;;;;;6023:29:1;;2608:42;6023:29;:54;;;;-1:-1:-1;;;;;;6056:21:1;;;6023:54;6019:162;;;2608:42;-1:-1:-1;;;;;6093:31:1;;6133:6;6093:50;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6164:6;6157:13;;;;6019:162;6191:19;6238:7;-1:-1:-1;;;;;6225:20:1;:9;-1:-1:-1;;;;;6225:20:1;;6221:64;;;6268:6;6261:13;;;;;6221:64;-1:-1:-1;;;;;6299:23:1;;6295:141;;-1:-1:-1;6352:6:1;6295:141;;;6389:36;6403:9;6414:10;6389:13;:36::i;:::-;6446:14;6463:20;6475:7;6463:11;:20::i;:::-;-1:-1:-1;;;;;6501:27:1;;;;;;:15;:27;;;;;;6446:37;;-1:-1:-1;6501:27:1;;6493:61;;;;-1:-1:-1;;;6493:61:1;;9073:2:21;6493:61:1;;;9055:21:21;9112:2;9092:18;;;9085:30;-1:-1:-1;;;9131:18:21;;;9124:51;9192:18;;6493:61:1;9045:171:21;6493:61:1;6565:12;6583:10;-1:-1:-1;;;;;6583:15:1;6607:11;6621:12;6583:51;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6564:70;;;6652:7;6644:41;;;;-1:-1:-1;;;6644:41:1;;10532:2:21;6644:41:1;;;10514:21:21;10571:2;10551:18;;;10544:30;-1:-1:-1;;;10590:18:21;;;10583:51;10651:18;;6644:41:1;10504:171:21;6644:41:1;6695:16;6714:20;6726:7;6714:11;:20::i;:::-;6695:39;-1:-1:-1;6757:17:1;6768:6;6695:39;6757:17;:::i;:::-;6745:29;;5807:974;;;;;;;;;;;;:::o;5031:561::-;-1:-1:-1;;;;;5113:21:1;;5109:477;;5150:16;;:65;;-1:-1:-1;;;5150:65:1;;5204:10;5150:65;;;6359:51:21;-1:-1:-1;;;;;5150:16:1;;;;:32;;5191:10;;6332:18:21;;5150:65:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5031:561;;:::o;5109:477::-;5266:16;;:37;;-1:-1:-1;;;5266:37:1;;-1:-1:-1;;;;;6377:32:21;;;5266:37:1;;;6359:51:21;5246:17:1;;5266:16;;:28;;6332:18:21;;5266:37:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5337:16;;:43;;-1:-1:-1;;;5337:43:1;;;;;8147:25:21;;;5246:57:1;;-1:-1:-1;5317:17:1;;-1:-1:-1;;;;;5337:16:1;;;;:32;;8120:18:21;;5337:43:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5317:63;;5394:33;5408:7;5417:9;5394:13;:33::i;:::-;5441:16;;5539:22;;;;;;;8147:25:21;;;5539:22:1;;;;;;;;;;8120:18:21;;;5539:22:1;;;;-1:-1:-1;;;5441:134:1;;;-1:-1:-1;;;;;5441:16:1;;;;:27;;:134;;5486:10;;5514:7;;5441:134;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5598:188;5660:14;;:119;;-1:-1:-1;;;5660:119:1;;2938:42;5660:119;;;7390:34:21;5734:10:1;7440:18:21;;;7433:43;7492:18;;;7485:34;;;-1:-1:-1;;;;;5660:14:1;;;;:34;;7325:18:21;;5660:119:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3561:867:14;3980:23;4018:115;4063:4;4018:115;;;;;;;;;;;;;;;;;4026:5;-1:-1:-1;;;;;4018:27:14;;;:115;;;;;:::i;:::-;4147:17;;3980:153;;-1:-1:-1;4147:21:14;4143:279;;4316:10;4305:30;;;;;;;;;;;;:::i;:::-;4280:131;;;;-1:-1:-1;;;4280:131:14;;15292:2:21;4280:131:14;;;15274:21:21;15331:2;15311:18;;;15304:30;15370:34;15350:18;;;15343:62;-1:-1:-1;;;15421:18:21;;;15414:40;15471:19;;4280:131:14;15264:232:21;4860:607:16;5025:12;5095:5;5070:21;:30;;5049:115;;;;-1:-1:-1;;;5049:115:16;;12720:2:21;5049:115:16;;;12702:21:21;12759:2;12739:18;;;12732:30;12798:34;12778:18;;;12771:62;-1:-1:-1;;;12849:18:21;;;12842:36;12895:19;;5049:115:16;12692:228:21;5049:115:16;1090:20;;5174:60;;;;-1:-1:-1;;;5174:60:16;;14934:2:21;5174:60:16;;;14916:21:21;14973:2;14953:18;;;14946:30;15012:31;14992:18;;;14985:59;15061:18;;5174:60:16;14906:179:21;5174:60:16;5305:12;5319:23;5358:6;-1:-1:-1;;;;;5358:11:16;5378:5;5386:4;5358:33;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5304:87;;;;5408:52;5426:7;5435:10;5447:12;5408:17;:52::i;:::-;5401:59;4860:607;-1:-1:-1;;;;;;;4860:607:16:o;879:275:14:-;1069:68;;-1:-1:-1;;;;;7408:15:21;;;1069:68:14;;;7390:34:21;7460:15;;7440:18;;;7433:43;7492:18;;;7485:34;;;1017:130:14;;1050:5;;-1:-1:-1;;;1092:27:14;7325:18:21;;1069:68:14;7307:218:21;7852:739:1;8049:10;7977:28;8036:24;;;:12;:24;;;;;;;;8074:12;;:28;;;;;8101:1;8090:8;;:12;8074:28;8070:515;;;8163:5;8151:8;;8142:6;:17;;;;:::i;:::-;8141:27;;;;:::i;:::-;-1:-1:-1;;;;;8187:21:1;;;;;;:10;:21;;;;;;8118:50;;-1:-1:-1;8187:21:1;;8183:392;;;-1:-1:-1;;;;;8232:19:1;;8228:84;;865:42:6;8275:18:1;;8228:84;8330:24;8419:3;8401:14;;8378:20;:37;;;;:::i;:::-;8377:45;;;;:::i;:::-;-1:-1:-1;;;;;8440:27:1;;;;;;;:16;:27;;;;;;;;:34;;;;;;;;;;;:54;;8330:92;;-1:-1:-1;8330:92:1;;8440:34;;:27;:54;;8330:92;;8440:54;:::i;:::-;;;;-1:-1:-1;;;;;;;8512:28:1;;;;;;:21;:28;;;;;:48;;8544:16;;8512:28;:48;;8544:16;;8512:48;:::i;:::-;;;;-1:-1:-1;;;8183:392:1;7852:739;;;;;;:::o;1519:261:6:-;1636:40;;-1:-1:-1;;;1636:40:6;;1661:4;1636:40;;;6633:34:21;-1:-1:-1;;;;;6703:15:21;;;6683:18;;;6676:43;1616:5:6;;1593:13;;1636:16;;;;;6568:18:21;;1636:40:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;1632:142;;;1682:7;1519:261;;:::o;1632:142::-;1717:46;-1:-1:-1;;;;;1717:18:6;;1736:7;-1:-1:-1;;1717:18:6;:46::i;1233:280::-;1316:15;-1:-1:-1;;;;;1351:19:6;;1347:160;;-1:-1:-1;1396:21:6;1233:280;;;:::o;1347:160::-;1458:38;;-1:-1:-1;;;1458:38:6;;1490:4;1458:38;;;6359:51:21;-1:-1:-1;;;;;1458:23:6;;;;;6332:18:21;;1458:38:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1448:48;1233:280;-1:-1:-1;;1233:280:6:o;7683:756:16:-;7829:12;7857:7;7853:580;;;-1:-1:-1;7887:10:16;7880:17;;7853:580;7998:17;;:21;7994:429;;8256:10;8250:17;8316:15;8303:10;8299:2;8295:19;8288:44;8205:145;8395:12;8388:20;;-1:-1:-1;;;8388:20:16;;;;;;;;:::i;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;:::o;14:159:21:-;108:6;141:2;129:15;;126:24;-1:-1:-1;123:2:21;;;163:1;160;153:12;178:395;241:8;251:6;305:3;298:4;290:6;286:17;282:27;272:2;;330:8;320;313:26;272:2;-1:-1:-1;360:20:21;;403:18;392:30;;389:2;;;442:8;432;425:26;389:2;486:4;478:6;474:17;462:29;;546:3;539:4;529:6;526:1;522:14;514:6;510:27;506:38;503:47;500:2;;;563:1;560;553:12;500:2;262:311;;;;;:::o;578:257::-;637:6;690:2;678:9;669:7;665:23;661:32;658:2;;;711:6;703;696:22;658:2;755:9;742:23;774:31;799:5;774:31;:::i;840:261::-;910:6;963:2;951:9;942:7;938:23;934:32;931:2;;;984:6;976;969:22;931:2;1021:9;1015:16;1040:31;1065:5;1040:31;:::i;1106:398::-;1174:6;1182;1235:2;1223:9;1214:7;1210:23;1206:32;1203:2;;;1256:6;1248;1241:22;1203:2;1300:9;1287:23;1319:31;1344:5;1319:31;:::i;:::-;1369:5;-1:-1:-1;1426:2:21;1411:18;;1398:32;1439:33;1398:32;1439:33;:::i;:::-;1491:7;1481:17;;;1193:311;;;;;:::o;1509:1175::-;1733:6;1741;1749;1757;1765;1773;1781;1834:3;1822:9;1813:7;1809:23;1805:33;1802:2;;;1856:6;1848;1841:22;1802:2;1900:9;1887:23;1919:31;1944:5;1919:31;:::i;:::-;1969:5;-1:-1:-1;2026:2:21;2011:18;;1998:32;2039:33;1998:32;2039:33;:::i;:::-;2091:7;-1:-1:-1;2117:62:21;2171:7;2166:2;2151:18;;2117:62;:::i;:::-;2107:72;;2198:63;2253:7;2247:3;2236:9;2232:19;2198:63;:::i;:::-;2188:73;;2280:63;2335:7;2329:3;2318:9;2314:19;2280:63;:::i;:::-;2270:73;;2394:3;2383:9;2379:19;2366:33;2422:18;2414:6;2411:30;2408:2;;;2459:6;2451;2444:22;2408:2;2487:66;2545:7;2536:6;2525:9;2521:22;2487:66;:::i;:::-;2477:76;;;2605:3;2594:9;2590:19;2577:33;2619;2644:7;2619:33;:::i;:::-;2671:7;2661:17;;;1792:892;;;;;;;;;;:::o;2689:392::-;2754:6;2762;2815:2;2803:9;2794:7;2790:23;2786:32;2783:2;;;2836:6;2828;2821:22;2783:2;2880:9;2867:23;2899:31;2924:5;2899:31;:::i;:::-;2949:5;-1:-1:-1;3006:2:21;2991:18;;2978:32;3019:30;2978:32;3019:30;:::i;3086:457::-;3172:6;3180;3233:2;3221:9;3212:7;3208:23;3204:32;3201:2;;;3254:6;3246;3239:22;3201:2;3299:9;3286:23;3332:18;3324:6;3321:30;3318:2;;;3369:6;3361;3354:22;3318:2;3413:70;3475:7;3466:6;3455:9;3451:22;3413:70;:::i;:::-;3502:8;;3387:96;;-1:-1:-1;3191:352:21;-1:-1:-1;;;;3191:352:21:o;3548:800::-;3667:6;3675;3683;3691;3744:2;3732:9;3723:7;3719:23;3715:32;3712:2;;;3765:6;3757;3750:22;3712:2;3810:9;3797:23;3839:18;3880:2;3872:6;3869:14;3866:2;;;3901:6;3893;3886:22;3866:2;3945:70;4007:7;3998:6;3987:9;3983:22;3945:70;:::i;:::-;4034:8;;-1:-1:-1;3919:96:21;-1:-1:-1;4122:2:21;4107:18;;4094:32;;-1:-1:-1;4138:16:21;;;4135:2;;;4172:6;4164;4157:22;4135:2;;4216:72;4280:7;4269:8;4258:9;4254:24;4216:72;:::i;:::-;3702:646;;;;-1:-1:-1;4307:8:21;-1:-1:-1;;;;3702:646:21:o;4353:251::-;4409:6;4462:2;4450:9;4441:7;4437:23;4433:32;4430:2;;;4483:6;4475;4468:22;4430:2;4527:9;4514:23;4546:28;4568:5;4546:28;:::i;4609:255::-;4676:6;4729:2;4717:9;4708:7;4704:23;4700:32;4697:2;;;4750:6;4742;4735:22;4697:2;4787:9;4781:16;4806:28;4828:5;4806:28;:::i;4869:194::-;4939:6;4992:2;4980:9;4971:7;4967:23;4963:32;4960:2;;;5013:6;5005;4998:22;4960:2;-1:-1:-1;5041:16:21;;4950:113;-1:-1:-1;4950:113:21:o;5068:190::-;5127:6;5180:2;5168:9;5159:7;5155:23;5151:32;5148:2;;;5201:6;5193;5186:22;5148:2;-1:-1:-1;5229:23:21;;5138:120;-1:-1:-1;5138:120:21:o;5462:257::-;5503:3;5541:5;5535:12;5568:6;5563:3;5556:19;5584:63;5640:6;5633:4;5628:3;5624:14;5617:4;5610:5;5606:16;5584:63;:::i;:::-;5701:2;5680:15;-1:-1:-1;;5676:29:21;5667:39;;;;5708:4;5663:50;;5511:208;-1:-1:-1;;5511:208:21:o;5724:274::-;5853:3;5891:6;5885:13;5907:53;5953:6;5948:3;5941:4;5933:6;5929:17;5907:53;:::i;:::-;5976:16;;;;;5861:137;-1:-1:-1;;5861:137:21:o;6730:415::-;-1:-1:-1;;;;;6971:15:21;;;6953:34;;7023:15;;7018:2;7003:18;;6996:43;7075:2;7070;7055:18;;7048:30;;;6896:4;;7095:44;;7120:18;;7112:6;7095:44;:::i;8647:219::-;8796:2;8785:9;8778:21;8759:4;8816:44;8856:2;8845:9;8841:18;8833:6;8816:44;:::i;14371:356::-;14573:2;14555:21;;;14592:18;;;14585:30;14651:34;14646:2;14631:18;;14624:62;14718:2;14703:18;;14545:182::o;16455:533::-;16532:4;16538:6;16598:11;16585:25;16692:2;16688:7;16677:8;16661:14;16657:29;16653:43;16633:18;16629:68;16619:2;;16714:4;16708;16701:18;16619:2;16744:33;;16796:20;;;-1:-1:-1;16839:18:21;16828:30;;16825:2;;;16874:4;16868;16861:18;16825:2;16910:4;16898:17;;-1:-1:-1;16941:14:21;16937:27;;;16927:38;;16924:2;;;16978:1;16975;16968:12;16993:128;17033:3;17064:1;17060:6;17057:1;17054:13;17051:2;;;17070:18;;:::i;:::-;-1:-1:-1;17106:9:21;;17041:80::o;17126:217::-;17166:1;17192;17182:2;;-1:-1:-1;;;17217:31:21;;17271:4;17268:1;17261:15;17299:4;17224:1;17289:15;17182:2;-1:-1:-1;17328:9:21;;17172:171::o;17348:168::-;17388:7;17454:1;17450;17446:6;17442:14;17439:1;17436:21;17431:1;17424:9;17417:17;17413:45;17410:2;;;17461:18;;:::i;:::-;-1:-1:-1;17501:9:21;;17400:116::o;17521:125::-;17561:4;17589:1;17586;17583:8;17580:2;;;17594:18;;:::i;:::-;-1:-1:-1;17631:9:21;;17570:76::o;17651:258::-;17723:1;17733:113;17747:6;17744:1;17741:13;17733:113;;;17823:11;;;17817:18;17804:11;;;17797:39;17769:2;17762:10;17733:113;;;17864:6;17861:1;17858:13;17855:2;;;-1:-1:-1;;17899:1:21;17881:16;;17874:27;17704:205::o;17914:135::-;17953:3;-1:-1:-1;;17974:17:21;;17971:2;;;17994:18;;:::i;:::-;-1:-1:-1;18041:1:21;18030:13;;17961:88::o;18054:127::-;18115:10;18110:3;18106:20;18103:1;18096:31;18146:4;18143:1;18136:15;18170:4;18167:1;18160:15;18186:131;-1:-1:-1;;;;;18261:31:21;;18251:42;;18241:2;;18307:1;18304;18297:12;18241:2;18231:86;:::o;18322:118::-;18408:5;18401:13;18394:21;18387:5;18384:32;18374:2;;18430:1;18427;18420:12
Swarm Source
ipfs://b15ed18efc59a00718b2feed77f21004a5f67ad01c3985e801c68a2840bbe074
Loading...
Loading
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.