Polygon Sponsored slots available. Book your slot here!
Contract Overview
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
Contract Name:
Sushiswap_ZapOut_Polygon_V2
Compiler Version
v0.8.4+commit.c7e474f2
Contract Source Code (Solidity Standard Json-Input format)
// 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); } } } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // 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 "./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; } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // 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 removes liquidity from Sushiswap pools on Polygon (Matic), 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_Polygon_V2 is ZapOutBaseV3 { using SafeERC20 for IERC20; uint256 private constant deadline = 0xf000000000000000000000000000000000000000000000000000000000000000; IUniswapV2Router02 private constant sushiswapRouter = IUniswapV2Router02(0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506); IUniswapV2Factory private constant sushiswapFactory = IUniswapV2Factory(0xc35DADB65012eC5796536bD9864eD8773aBc74C4); address private constant wmaticTokenAddress = address(0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270); 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 == wmaticTokenAddress || token1 == wmaticTokenAddress) { address _token = token0 == wmaticTokenAddress ? 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 == wmaticTokenAddress && toToken == address(0)) { IWETH(wmaticTokenAddress).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 Sushiswap pools on Polygon (Matic) 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_Polygon_V3 is ZapInBaseV3 { using SafeERC20 for IERC20; IUniswapV2Factory private constant sushiSwapFactoryAddress = IUniswapV2Factory(0xc35DADB65012eC5796536bD9864eD8773aBc74C4); IUniswapV2Router02 private constant sushiSwapRouter = IUniswapV2Router02(0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506); address private constant wmaticTokenAddress = address(0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270); 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 == wmaticTokenAddress) { IWETH(wmaticTokenAddress).deposit{ value: _amount }(); return (_amount, wmaticTokenAddress); } 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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokensRec","type":"uint256"}],"name":"zapOut","type":"event"},{"inputs":[{"internalType":"address","name":"toTokenAddress","type":"address"},{"internalType":"address","name":"fromPoolAddress","type":"address"},{"internalType":"uint256","name":"incomingLP","type":"uint256"},{"internalType":"uint256","name":"minTokensRec","type":"uint256"},{"internalType":"address[]","name":"swapTargets","type":"address[]"},{"internalType":"bytes[]","name":"swapData","type":"bytes[]"},{"internalType":"address","name":"affiliate","type":"address"},{"internalType":"bool","name":"shouldSellEntireBalance","type":"bool"}],"name":"ZapOut","outputs":[{"internalType":"uint256","name":"tokensRec","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"fromPoolAddress","type":"address"},{"internalType":"uint256","name":"incomingLP","type":"uint256"},{"internalType":"address","name":"affiliate","type":"address"}],"name":"ZapOut2PairToken","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"fromPoolAddress","type":"address"},{"internalType":"uint256","name":"incomingLP","type":"uint256"},{"internalType":"address","name":"affiliate","type":"address"},{"internalType":"bytes","name":"permitData","type":"bytes"}],"name":"ZapOut2PairTokenWithPermit","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"toTokenAddress","type":"address"},{"internalType":"address","name":"fromPoolAddress","type":"address"},{"internalType":"uint256","name":"incomingLP","type":"uint256"},{"internalType":"uint256","name":"minTokensRec","type":"uint256"},{"internalType":"bytes","name":"permitData","type":"bytes"},{"internalType":"address[]","name":"swapTargets","type":"address[]"},{"internalType":"bytes[]","name":"swapData","type":"bytes[]"},{"internalType":"address","name":"affiliate","type":"address"}],"name":"ZapOutWithPermit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","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":[{"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":[{"internalType":"address","name":"fromPoolAddress","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"name":"removeLiquidityReturn","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","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
60806040526000805460ff60a01b191690553480156200001e57600080fd5b5060405162003415380380620034158339810160408190526200004191620000e0565b600080546001600160a01b03191633908117825560405184928492918291907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350600291909155600355505073def1c0ded9bec7f1a1670819833240f027b25eff60005260076020527ff6019cd1944dc466e824190b288e5a63528dd4c9a6d8cbd707956fd30d2f1e0d805460ff1916600117905562000104565b60008060408385031215620000f3578182fd5b505080516020909101519092909150565b61330180620001146000396000f3fe6080604052600436106101445760003560e01c8063715018a6116100b65780639779d1a61161006f5780639779d1a614610435578063cfd7789c14610465578063d408f6571461049a578063f21d3ab5146104ca578063f2fde38b146104ea578063fbec27bf1461050a57600080fd5b8063715018a61461034857806375f12b211461035d5780637ee992831461037e5780638da5cb5b146103cd57806391027c5b146103f55780639735a6341461041557600080fd5b8063247482ba11610108578063247482ba146102725780633ff428c7146102925780634f51e294146102b2578063550bfa56146102f25780635de0398e146103125780635ecb16cd1461032857600080fd5b806301e980d4146101a55780630dc9de85146101c55780631385d24c146101e55780631781261f146101fa57806318b135e31461024557600080fd5b366101a0573332141561019e5760405162461bcd60e51b815260206004820152601860248201527f446f206e6f742073656e6420455448206469726563746c79000000000000000060448201526064015b60405180910390fd5b005b600080fd5b3480156101b157600080fd5b5061019e6101c0366004612ff2565b61052a565b3480156101d157600080fd5b5061019e6101e0366004612f11565b6105b4565b3480156101f157600080fd5b5061019e61080f565b34801561020657600080fd5b50610232610215366004612c1b565b600560209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b34801561025157600080fd5b50610232610260366004612be3565b60066020526000908152604090205481565b34801561027e57600080fd5b5061023261028d366004612c53565b61085a565b34801561029e57600080fd5b5061019e6102ad366004612dde565b6109dc565b3480156102be57600080fd5b506102e26102cd366004612be3565b60046020526000908152604090205460ff1681565b604051901515815260200161023c565b3480156102fe57600080fd5b5061019e61030d366004612ff2565b610a31565b34801561031e57600080fd5b5061023260025481565b34801561033457600080fd5b5061019e610343366004612f11565b610ab1565b34801561035457600080fd5b5061019e610d22565b34801561036957600080fd5b506000546102e290600160a01b900460ff1681565b34801561038a57600080fd5b5061039e610399366004612e0b565b610d96565b6040805194855260208501939093526001600160a01b039182169284019290925216606082015260800161023c565b3480156103d957600080fd5b506000546040516001600160a01b03909116815260200161023c565b34801561040157600080fd5b50610232610410366004612d14565b611035565b34801561042157600080fd5b5061019e610430366004612f51565b611128565b34801561044157600080fd5b506102e2610450366004612be3565b60076020526000908152604090205460ff1681565b34801561047157600080fd5b50610485610480366004612e77565b611252565b6040805192835260208301919091520161023c565b3480156104a657600080fd5b506102e26104b5366004612be3565b60016020526000908152604090205460ff1681565b3480156104d657600080fd5b506104856104e5366004612e36565b611344565b3480156104f657600080fd5b5061019e610505366004612be3565b6117fd565b34801561051657600080fd5b5061019e610525366004612dde565b6118e7565b6000546001600160a01b031633146105545760405162461bcd60e51b81526004016101959061313a565b60648111156105af5760405162461bcd60e51b815260206004820152602160248201527f416666696c696174652053706c69742056616c7565206e6f7420616c6c6f77656044820152601960fa1b6064820152608401610195565b600355565b6000805b8281101561080957336000908152600560205260408120908585848181106105f057634e487b7160e01b600052603260045260246000fd5b90506020020160208101906106059190612be3565b6001600160a01b0316815260208082019290925260409081016000908120543382526005909352908120919350908186868581811061065457634e487b7160e01b600052603260045260246000fd5b90506020020160208101906106699190612be3565b6001600160a01b03166001600160a01b031681526020019081526020016000208190555081600660008686858181106106b257634e487b7160e01b600052603260045260246000fd5b90506020020160208101906106c79190612be3565b6001600160a01b03166001600160a01b03168152602001908152602001600020546106f2919061321b565b6006600086868581811061071657634e487b7160e01b600052603260045260246000fd5b905060200201602081019061072b9190612be3565b6001600160a01b0316815260208101919091526040016000205573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee84848381811061077a57634e487b7160e01b600052603260045260246000fd5b905060200201602081019061078f9190612be3565b6001600160a01b031614156107ad576107a8338361193c565b6107f7565b6107f733838686858181106107d257634e487b7160e01b600052603260045260246000fd5b90506020020160208101906107e79190612be3565b6001600160a01b03169190611a55565b806108018161325e565b9150506105b8565b50505050565b6000546001600160a01b031633146108395760405162461bcd60e51b81526004016101959061313a565b6000805460ff60a01b198116600160a01b9182900460ff1615909102179055565b60008054600160a01b900460ff16156108855760405162461bcd60e51b81526004016101959061310e565b6000806108938a8a86611ab8565b915091506108a58a83838e8b8b611d2b565b9250878310156108e75760405162461bcd60e51b815260206004820152600d60248201526c4869676820536c69707061676560981b6044820152606401610195565b60006001600160a01b038c166109565761091873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85886001611f3f565b9050336108fc610928838761321b565b6040518115909202916000818181858888f19350505050158015610950573d6000803e3d6000fd5b50610984565b6109638c85886001611f3f565b905061098433610973838761321b565b6001600160a01b038f169190611a55565b61098e818561321b565b93507ff2d3e32195f8631c70e1d996c9bd5d4a3369d0580786dcd662bf13139310355d338c8e876040516109c59493929190613071565b60405180910390a150505098975050505050505050565b6000546001600160a01b03163314610a065760405162461bcd60e51b81526004016101959061313a565b6001600160a01b03919091166000908152600460205260409020805460ff1916911515919091179055565b6000546001600160a01b03163314610a5b5760405162461bcd60e51b81526004016101959061313a565b6064811115610aac5760405162461bcd60e51b815260206004820152601a60248201527f476f6f6457696c6c2056616c7565206e6f7420616c6c6f7765640000000000006044820152606401610195565b600255565b6000546001600160a01b03163314610adb5760405162461bcd60e51b81526004016101959061313a565b60005b81811015610d1d57600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee848484818110610b1d57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610b329190612be3565b6001600160a01b03161415610bc05760066000858585818110610b6557634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610b7a9190612be3565b6001600160a01b03168152602081019190915260400160002054610b9e904761321b565b9050610bbb610bb56000546001600160a01b031690565b8261193c565b610d0a565b60066000858585818110610be457634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610bf99190612be3565b6001600160a01b03166001600160a01b0316815260200190815260200160002054848484818110610c3a57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610c4f9190612be3565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a082319060240160206040518083038186803b158015610c9057600080fd5b505afa158015610ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc8919061300a565b610cd2919061321b565b9050610d0a610ce96000546001600160a01b031690565b828686868181106107d257634e487b7160e01b600052603260045260246000fd5b5080610d158161325e565b915050610ade565b505050565b6000546001600160a01b03163314610d4c5760405162461bcd60e51b81526004016101959061313a565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000806000806000869050806001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b158015610dda57600080fd5b505afa158015610dee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e129190612bff565b9250806001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b158015610e4d57600080fd5b505afa158015610e61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e859190612bff565b6040516370a0823160e01b81526001600160a01b0389811660048301529193506000918516906370a082319060240160206040518083038186803b158015610ecc57600080fd5b505afa158015610ee0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f04919061300a565b6040516370a0823160e01b81526001600160a01b038a811660048301529192506000918516906370a082319060240160206040518083038186803b158015610f4b57600080fd5b505afa158015610f5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f83919061300a565b90506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc057600080fd5b505afa158015610fd4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff8919061300a565b905080611005848b6131fc565b61100f91906131dc565b97508061101c838b6131fc565b61102691906131dc565b96505050505092959194509250565b60008054600160a01b900460ff16156110605760405162461bcd60e51b81526004016101959061310e565b6110698861206a565b6000886001600160a01b0316866040516110839190613055565b6000604051808303816000865af19150503d80600081146110c0576040519150601f19603f3d011682016040523d82523d6000602084013e6110c5565b606091505b50509050806111095760405162461bcd60e51b815260206004820152601060248201526f10dbdd5b1908139bdd0814195c9b5a5d60821b6044820152606401610195565b61111a8a8a8a8a898989600061085a565b9a9950505050505050505050565b6000546001600160a01b031633146111525760405162461bcd60e51b81526004016101959061313a565b8281146111985760405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c84092dce0eae840d8cadccee8d60631b6044820152606401610195565b60005b8381101561124b578282828181106111c357634e487b7160e01b600052603260045260246000fd5b90506020020160208101906111d89190612fba565b600760008787858181106111fc57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906112119190612be3565b6001600160a01b031681526020810191909152604001600020805460ff1916911515919091179055806112438161325e565b91505061119b565b5050505050565b600080548190600160a01b900460ff161561127f5760405162461bcd60e51b81526004016101959061310e565b6112888761206a565b6000876001600160a01b031685856040516112a4929190613045565b6000604051808303816000865af19150503d80600081146112e1576040519150601f19603f3d011682016040523d82523d6000602084013e6112e6565b606091505b505090508061132a5760405162461bcd60e51b815260206004820152601060248201526f10dbdd5b1908139bdd0814195c9b5a5d60821b6044820152606401610195565b611335888888611344565b90999098509650505050505050565b600080548190600160a01b900460ff16156113715760405162461bcd60e51b81526004016101959061310e565b846001600160a01b0381166113c85760405162461bcd60e51b815260206004820152601b60248201527f506f6f6c2043616e6e6f74206265205a65726f204164647265737300000000006044820152606401610195565b6000816001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b15801561140357600080fd5b505afa158015611417573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061143b9190612bff565b90506000826001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b15801561147857600080fd5b505afa15801561148c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b09190612bff565b90506114c76001600160a01b03891633308a61224a565b6114e688731b02da8cb0d097eb8d57a175b88c7d8b4799750689612282565b6001600160a01b038216730d500b1d8e8ef31e21c99d1db9a6444d3adf1270148061152d57506001600160a01b038116730d500b1d8e8ef31e21c99d1db9a6444d3adf1270145b156116885760006001600160a01b038316730d500b1d8e8ef31e21c99d1db9a6444d3adf12701461155e5782611560565b815b604051629d473b60e21b81526001600160a01b0382166004820152602481018a90526001604482018190526064820152306084820152600f60fc1b60a4820152909150731b02da8cb0d097eb8d57a175b88c7d8b47997506906302751cec9060c4016040805180830381600087803b1580156115db57600080fd5b505af11580156115ef573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116139190613022565b9096509450600061162782888a6001611f3f565b9050600061164c73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee888b6001611f3f565b905061166d3361165c848b61321b565b6001600160a01b0386169190611a55565b6116803361167b838a61321b565b61193c565b505050611778565b604051635d5155ef60e11b8152731b02da8cb0d097eb8d57a175b88c7d8b479975069063baa2abde906116d090859085908c9060019081903090600f60fc1b9060040161309b565b6040805180830381600087803b1580156116e957600080fd5b505af11580156116fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117219190613022565b909550935060006117358387896001611f3f565b9050600061174683878a6001611f3f565b905061176733611756848a61321b565b6001600160a01b0387169190611a55565b6117753361165c838961321b565b50505b7ff2d3e32195f8631c70e1d996c9bd5d4a3369d0580786dcd662bf13139310355d338984886040516117ad9493929190613071565b60405180910390a17ff2d3e32195f8631c70e1d996c9bd5d4a3369d0580786dcd662bf13139310355d338983876040516117ea9493929190613071565b60405180910390a1505050935093915050565b6000546001600160a01b031633146118275760405162461bcd60e51b81526004016101959061313a565b6001600160a01b03811661188c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610195565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146119115760405162461bcd60e51b81526004016101959061313a565b6001600160a01b03919091166000908152600160205260409020805460ff1916911515919091179055565b8047101561198c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610195565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146119d9576040519150601f19603f3d011682016040523d82523d6000602084013e6119de565b606091505b5050905080610d1d5760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610195565b6040516001600160a01b038316602482015260448101829052610d1d90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526122ab565b600080846001600160a01b038116611b125760405162461bcd60e51b815260206004820152601b60248201527f506f6f6c2043616e6e6f74206265205a65726f204164647265737300000000006044820152606401610195565b6000816001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b158015611b4d57600080fd5b505afa158015611b61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b859190612bff565b90506000826001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b158015611bc257600080fd5b505afa158015611bd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bfa9190612bff565b9050611c0788888861237d565b50611c2788731b02da8cb0d097eb8d57a175b88c7d8b4799750689612282565b604051635d5155ef60e11b8152731b02da8cb0d097eb8d57a175b88c7d8b479975069063baa2abde90611c6f90859085908c9060019081903090600f60fc1b9060040161309b565b6040805180830381600087803b158015611c8857600080fd5b505af1158015611c9c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cc09190613022565b90955093508415801590611cd45750600084115b611d205760405162461bcd60e51b815260206004820152601e60248201527f52656d6f76656420496e73756666696369656e74204c697175696469747900006044820152606401610195565b505050935093915050565b600080876001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b158015611d6757600080fd5b505afa158015611d7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9f9190612bff565b90506000886001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b158015611ddc57600080fd5b505afa158015611df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e149190612bff565b9050856001600160a01b0316826001600160a01b03161415611e4157611e3a88846131c4565b9250611eab565b611e9e82878a88600081518110611e6857634e487b7160e01b600052603260045260246000fd5b602002602001015188600081518110611e9157634e487b7160e01b600052603260045260246000fd5b60200260200101516124a5565b611ea890846131c4565b92505b856001600160a01b0316816001600160a01b03161415611ed657611ecf87846131c4565b9250611f33565b611f2681878988600181518110611efd57634e487b7160e01b600052603260045260246000fd5b602002602001015188600181518110611e9157634e487b7160e01b600052603260045260246000fd5b611f3090846131c4565b92505b50509695505050505050565b3360009081526001602052604081205460ff16828015611f5d575080155b8015611f6b57506000600254115b156120615761271060025486611f8191906131fc565b611f8b91906131dc565b6001600160a01b03851660009081526004602052604090205490925060ff1615612061576001600160a01b038616611fd55773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee95505b6000606460035484611fe791906131fc565b611ff191906131dc565b6001600160a01b038087166000908152600560209081526040808320938c1683529290529081208054929350839290919061202d9084906131c4565b90915550506001600160a01b0387166000908152600660205260408120805483929061205a9084906131c4565b9091555050505b50949350505050565b60008190506000816001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b1580156120aa57600080fd5b505afa1580156120be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120e29190612bff565b90506000826001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b15801561211f57600080fd5b505afa158015612133573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121579190612bff565b60405163e6a4390560e01b81526001600160a01b0380851660048301528216602482015290915060009073c35dadb65012ec5796536bd9864ed8773abc74c49063e6a439059060440160206040518083038186803b1580156121b857600080fd5b505afa1580156121cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121f09190612bff565b9050846001600160a01b0316816001600160a01b03161461124b5760405162461bcd60e51b8152602060048201526014602482015273496e76616c696420506f6f6c204164647265737360601b6044820152606401610195565b6040516001600160a01b03808516602483015283166044820152606481018290526108099085906323b872dd60e01b90608401611a81565b6122976001600160a01b0384168360006126f9565b610d1d6001600160a01b03841683836126f9565b6000612300826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661281d9092919063ffffffff16565b805190915015610d1d578080602001905181019061231e9190612fd6565b610d1d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610195565b6000811561248657333b6123e85760405162461bcd60e51b815260206004820152602c60248201527f4552523a2073686f756c6453656c6c456e7469726542616c616e63652069732060448201526b7472756520666f7220454f4160a01b6064820152608401610195565b604051636eb1769f60e11b81523360048201523060248201526000906001600160a01b0386169063dd62ed3e9060440160206040518083038186803b15801561243057600080fd5b505afa158015612444573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612468919061300a565b905061247f6001600160a01b03861633308461224a565b905061249e565b61249b6001600160a01b03851633308661224a565b50815b9392505050565b60006001600160a01b038616730d500b1d8e8ef31e21c99d1db9a6444d3adf12701480156124da57506001600160a01b038516155b1561254c57604051632e1a7d4d60e01b815260048101859052730d500b1d8e8ef31e21c99d1db9a6444d3adf127090632e1a7d4d90602401600060405180830381600087803b15801561252c57600080fd5b505af1158015612540573d6000803e3d6000fd5b505050508390506126f0565b60006001600160a01b03871661256357508361256e565b61256e878587612282565b600061257987612834565b6001600160a01b03861660009081526007602052604090205490915060ff166125dc5760405162461bcd60e51b815260206004820152601560248201527415185c99d95d081b9bdd08105d5d1a1bdc9a5e9959605a1b6044820152606401610195565b6000856001600160a01b031683866040516125f79190613055565b60006040518083038185875af1925050503d8060008114612634576040519150601f19603f3d011682016040523d82523d6000602084013e612639565b606091505b50509050806126825760405162461bcd60e51b81526020600482015260156024820152744572726f72205377617070696e6720546f6b656e7360581b6044820152606401610195565b60008261268e8a612834565b612698919061321b565b9050600081116126ea5760405162461bcd60e51b815260206004820152601f60248201527f5377617070656420746f20496e76616c696420496e7465726d656469617465006044820152606401610195565b93505050505b95945050505050565b8015806127825750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b15801561274857600080fd5b505afa15801561275c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612780919061300a565b155b6127ed5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610195565b6040516001600160a01b038316602482015260448101829052610d1d90849063095ea7b360e01b90606401611a81565b606061282c84846000856128ca565b949350505050565b60006001600160a01b03821661284b575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a082319060240160206040518083038186803b15801561288a57600080fd5b505afa15801561289e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c2919061300a565b90505b919050565b60608247101561292b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610195565b843b6129795760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610195565b600080866001600160a01b031685876040516129959190613055565b60006040518083038185875af1925050503d80600081146129d2576040519150601f19603f3d011682016040523d82523d6000602084013e6129d7565b606091505b50915091506129e78282866129f2565b979650505050505050565b60608315612a0157508161249e565b825115612a115782518084602001fd5b8160405162461bcd60e51b815260040161019591906130db565b80356128c5816132a5565b60008083601f840112612a47578182fd5b50813567ffffffffffffffff811115612a5e578182fd5b6020830191508360208260051b8501011115612a7957600080fd5b9250929050565b600082601f830112612a90578081fd5b81356020612aa5612aa0836131a0565b61316f565b80838252828201915082860187848660051b8901011115612ac4578586fd5b855b85811015612aeb578135612ad9816132a5565b84529284019290840190600101612ac6565b5090979650505050505050565b600082601f830112612b08578081fd5b81356020612b18612aa0836131a0565b80838252828201915082860187848660051b8901011115612b37578586fd5b855b85811015612aeb57813567ffffffffffffffff811115612b57578788fd5b612b658a87838c0101612b78565b8552509284019290840190600101612b39565b600082601f830112612b88578081fd5b813567ffffffffffffffff811115612ba257612ba261328f565b612bb5601f8201601f191660200161316f565b818152846020838601011115612bc9578283fd5b816020850160208301379081016020019190915292915050565b600060208284031215612bf4578081fd5b813561249e816132a5565b600060208284031215612c10578081fd5b815161249e816132a5565b60008060408385031215612c2d578081fd5b8235612c38816132a5565b91506020830135612c48816132a5565b809150509250929050565b600080600080600080600080610100898b031215612c6f578384fd5b8835612c7a816132a5565b97506020890135612c8a816132a5565b96506040890135955060608901359450608089013567ffffffffffffffff80821115612cb4578586fd5b612cc08c838d01612a80565b955060a08b0135915080821115612cd5578485fd5b50612ce28b828c01612af8565b93505060c0890135612cf3816132a5565b915060e0890135612d03816132bd565b809150509295985092959890939650565b600080600080600080600080610100898b031215612d30578384fd5b612d3989612a2b565b9750612d4760208a01612a2b565b96506040890135955060608901359450608089013567ffffffffffffffff80821115612d71578586fd5b612d7d8c838d01612b78565b955060a08b0135915080821115612d92578485fd5b612d9e8c838d01612a80565b945060c08b0135915080821115612db3578384fd5b50612dc08b828c01612af8565b925050612dcf60e08a01612a2b565b90509295985092959890939650565b60008060408385031215612df0578182fd5b8235612dfb816132a5565b91506020830135612c48816132bd565b60008060408385031215612e1d578182fd5b8235612e28816132a5565b946020939093013593505050565b600080600060608486031215612e4a578081fd5b8335612e55816132a5565b9250602084013591506040840135612e6c816132a5565b809150509250925092565b600080600080600060808688031215612e8e578283fd5b8535612e99816132a5565b9450602086013593506040860135612eb0816132a5565b9250606086013567ffffffffffffffff80821115612ecc578283fd5b818801915088601f830112612edf578283fd5b813581811115612eed578384fd5b896020828501011115612efe578384fd5b9699959850939650602001949392505050565b60008060208385031215612f23578182fd5b823567ffffffffffffffff811115612f39578283fd5b612f4585828601612a36565b90969095509350505050565b60008060008060408587031215612f66578182fd5b843567ffffffffffffffff80821115612f7d578384fd5b612f8988838901612a36565b90965094506020870135915080821115612fa1578384fd5b50612fae87828801612a36565b95989497509550505050565b600060208284031215612fcb578081fd5b813561249e816132bd565b600060208284031215612fe7578081fd5b815161249e816132bd565b600060208284031215613003578081fd5b5035919050565b60006020828403121561301b578081fd5b5051919050565b60008060408385031215613034578182fd5b505080516020909101519092909150565b8183823760009101908152919050565b60008251613067818460208701613232565b9190910192915050565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b039788168152958716602087015260408601949094526060850192909252608084015290921660a082015260c081019190915260e00190565b60208152600082518060208401526130fa816040850160208701613232565b601f01601f19169190910160400192915050565b60208082526012908201527115195b5c1bdc985c9a5b1e4814185d5cd95960721b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b604051601f8201601f1916810167ffffffffffffffff811182821017156131985761319861328f565b604052919050565b600067ffffffffffffffff8211156131ba576131ba61328f565b5060051b60200190565b600082198211156131d7576131d7613279565b500190565b6000826131f757634e487b7160e01b81526012600452602481fd5b500490565b600081600019048311821515161561321657613216613279565b500290565b60008282101561322d5761322d613279565b500390565b60005b8381101561324d578181015183820152602001613235565b838111156108095750506000910152565b600060001982141561327257613272613279565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b03811681146132ba57600080fd5b50565b80151581146132ba57600080fdfea264697066735822122019664c117108551aba1617224475ece786a6d4c8ff1daecc76c5520ddf87398264736f6c6343000804003300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
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
3487:12680:3:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4685:10:8;4699:9;4685:23;;4677:60;;;;-1:-1:-1;;;4677:60:8;;15677:2:23;4677:60:8;;;15659:21:23;15716:2;15696:18;;;15689:30;15755:26;15735:18;;;15728:54;15799:18;;4677:60:8;;;;;;;;;3487:12680:3;;;;;2521:269:8;;;;;;;;;;-1:-1:-1;2521:269:8;;;;;:::i;:::-;;:::i;3674:621::-;;;;;;;;;;-1:-1:-1;3674:621:8;;;;;:::i;:::-;;:::i;2039:84::-;;;;;;;;;;;;;:::i;565:71::-;;;;;;;;;;-1:-1:-1;565:71:8;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;23453:25:23;;;23441:2;23426:18;565:71:8;;;;;;;;665:56;;;;;;;;;;-1:-1:-1;665:56:8;;;;;:::i;:::-;;;;;;;;;;;;;;7587:1690:3;;;;;;;;;;-1:-1:-1;7587:1690:3;;;;;:::i;:::-;;:::i;2796:145:8:-;;;;;;;;;;-1:-1:-1;2796:145:8;;;;;:::i;:::-;;:::i;481:42::-;;;;;;;;;;-1:-1:-1;481:42:8;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;14710:14:23;;14703:22;14685:41;;14673:2;14658:18;481:42:8;14640:92:23;2283:232:8;;;;;;;;;;-1:-1:-1;2283:232:8;;;;;:::i;:::-;;:::i;360:23::-;;;;;;;;;;;;;;;;3014:587;;;;;;;;;;-1:-1:-1;3014:587:8;;;;;:::i;:::-;;:::i;1722:145:12:-;;;;;;;;;;;;;:::i;234:27:8:-;;;;;;;;;;-1:-1:-1;234:27:8;;;;-1:-1:-1;;;234:27:8;;;;;;15473:692:3;;;;;;;;;;-1:-1:-1;15473:692:3;;;;;:::i;:::-;;:::i;:::-;;;;23973:25:23;;;24029:2;24014:18;;24007:34;;;;-1:-1:-1;;;;;24115:15:23;;;24095:18;;;24088:43;;;;24167:15;24162:2;24147:18;;24140:43;23960:3;23945:19;15473:692:3;23927:262:23;1090:85:12;;;;;;;;;;-1:-1:-1;1136:7:12;1162:6;1090:85;;-1:-1:-1;;;;;1162:6:12;;;11749:51:23;;11737:2;11722:18;1090:85:12;11704:102:23;10686:789:3;;;;;;;;;;-1:-1:-1;10686:789:3;;;;;:::i;:::-;;:::i;4301:333:8:-;;;;;;;;;;-1:-1:-1;4301:333:8;;;;;:::i;:::-;;:::i;764:47::-;;;;;;;;;;-1:-1:-1;764:47:8;;;;;:::i;:::-;;;;;;;;;;;;;;;;9719:539:3;;;;;;;;;;-1:-1:-1;9719:539:3;;;;;:::i;:::-;;:::i;:::-;;;;23663:25:23;;;23719:2;23704:18;;23697:34;;;;23636:18;9719:539:3;23618:119:23;309:44:8;;;;;;;;;;-1:-1:-1;309:44:8;;;;;:::i;:::-;;;;;;;;;;;;;;;;4762:2309:3;;;;;;;;;;-1:-1:-1;4762:2309:3;;;;;:::i;:::-;;:::i;2016:274:12:-;;;;;;;;;;-1:-1:-1;2016:274:12;;;;;:::i;:::-;;:::i;2129:148:8:-;;;;;;;;;;-1:-1:-1;2129:148:8;;;;;:::i;:::-;;:::i;2521:269::-;1136:7:12;1162:6;-1:-1:-1;;;;;1162:6:12;665:10:19;1302:23:12;1294:68;;;;-1:-1:-1;;;1294:68:12;;;;;;;:::i;:::-;2675:3:8::1;2652:19;:26;;2631:106;;;::::0;-1:-1:-1;;;2631:106:8;;20073:2:23;2631:106:8::1;::::0;::::1;20055:21:23::0;20112:2;20092:18;;;20085:30;20151:34;20131:18;;;20124:62;-1:-1:-1;;;20202:18:23;;;20195:31;20243:19;;2631:106:8::1;20045:223:23::0;2631:106:8::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:8;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;3843:39:8;;;;;;;;;;;;;;;-1:-1:-1;3843:39:8;;;;3913:10;3896:28;;:16;:28;;;;;;3843:39;;-1:-1:-1;;;3925:6:8;;3932:1;3925:9;;;;;-1:-1:-1;;;3925:9:8;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;3896:39:8;-1:-1:-1;;;;;3896:39:8;;;;;;;;;;;;:43;;;;4055:8;4004:21;:32;4026:6;;4033:1;4026:9;;;;;-1:-1:-1;;;4026:9:8;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;4004:32:8;-1:-1:-1;;;;;4004:32:8;;;;;;;;;;;;;:59;;;;:::i;:::-;3953:21;:32;3975:6;;3982:1;3975:9;;;;;-1:-1:-1;;;3975:9:8;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;3953:32:8;;;;;;;;;;;;-1:-1:-1;3953:32:8;:110;865:42;4082:6;;4089:1;4082:9;;;;;-1:-1:-1;;;4082:9:8;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;4082:23:8;;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:8;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;4212:30:8;;:52;:30;:52::i;:::-;3813:3;;;;:::i;:::-;;;;3774:515;;;;3674:621;;;:::o;2039:84::-;1136:7:12;1162:6;-1:-1:-1;;;;;1162:6:12;665:10:19;1302:23:12;1294:68;;;;-1:-1:-1;;;1294:68:12;;;;;;;:::i;:::-;2109:7:8::1;::::0;;-1:-1:-1;;;;2098:18:8;::::1;-1:-1:-1::0;;;2109:7:8;;;::::1;;;2108:8;2098:18:::0;;::::1;;::::0;;2039:84::o;7587:1690:3:-;7900:17;1127:7:8;;-1:-1:-1;;;1127:7:8;;;;1123:98;;;1150:28;;-1:-1:-1;;;1150:28:8;;;;;;;:::i;1123:98::-;7930:15:3::1;7947::::0;7978:132:::1;8012:15;8045:10;8073:23;7978:16;:132::i;:::-;7929:181;;;;8165:167;8190:15;8219:7;8240;8261:14;8289:11;8314:8;8165:11;:167::i;:::-;8153:179;;8363:12;8350:9;:25;;8342:51;;;::::0;-1:-1:-1;;;8342:51:3;;16030:2:23;8342:51:3::1;::::0;::::1;16012:21:23::0;16069:2;16049:18;;;16042:30;-1:-1:-1;;;16088:18:23;;;16081:43;16141:18;;8342:51:3::1;16002:163:23::0;8342:51:3::1;8404:28;-1:-1:-1::0;;;;;8486:28:3;::::1;8482:629;;8553:135;865:42:8;8616:9:3;8643;8670:4;8553:17;:135::i;:::-;8530:158:::0;-1:-1:-1;8711:10:3::1;8703:62;8732:32;8530:158:::0;8732:9;:32:::1;:::i;:::-;8703:62;::::0;;::::1;::::0;;::::1;::::0;::::1;::::0;;;;;;::::1;;;;;;;;;;;;;::::0;::::1;;;;;;8482:629;;;8819:139;8854:14;8886:9;8913;8940:4;8819:17;:139::i;:::-;8796:162:::0;-1:-1:-1;8973:127:3::1;9026:10;9054:32;8796:162:::0;9054:9;:32:::1;:::i;:::-;-1:-1:-1::0;;;;;8973:35:3;::::1;::::0;:127;:35:::1;:127::i;:::-;9133:32;9145:20:::0;9133:9;:32:::1;:::i;:::-;9121:44;;9181:62;9188:10;9200:15;9217:14;9233:9;9181:62;;;;;;;;;:::i;:::-;;;;;;;;9254:16;;;7587:1690:::0;;;;;;;;;;:::o;2796:145:8:-;1136:7:12;1162:6;-1:-1:-1;;;;;1162:6:12;665:10:19;1302:23:12;1294:68;;;;-1:-1:-1;;;1294:68:12;;;;;;;:::i;:::-;-1:-1:-1;;;;;2902:22:8;;;::::1;;::::0;;;:10:::1;:22;::::0;;;;:32;;-1:-1:-1;;2902:32:8::1;::::0;::::1;;::::0;;;::::1;::::0;;2796:145::o;2283:232::-;1136:7:12;1162:6;-1:-1:-1;;;;;1162:6:12;665:10:19;1302:23:12;1294:68;;;;-1:-1:-1;;;1294:68:12;;;;;;;:::i;:::-;2419:3:8::1;2402:13;:20;;2359:115;;;::::0;-1:-1:-1;;;2359:115:8;;18668:2:23;2359:115:8::1;::::0;::::1;18650:21:23::0;18707:2;18687:18;;;18680:30;18746:28;18726:18;;;18719:56;18792:18;;2359:115:8::1;18640:176:23::0;2359:115:8::1;2484:8;:24:::0;2283:232::o;3014:587::-;1136:7:12;1162:6;-1:-1:-1;;;;;1162:6:12;665:10:19;1302:23:12;1294:68;;;;-1:-1:-1;;;1294:68:12;;;;;;;:::i;:::-;3099:9:8::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:8::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;3182:23:8::1;;3178:407;;;3255:21;:32;3277:6;;3284:1;3277:9;;;;;-1:-1:-1::0;;;3277:9:8::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;3255:32:8::1;::::0;;::::1;::::0;::::1;::::0;;;;;;-1:-1:-1;3255:32:8;;3231:56:::1;::::0;:21:::1;:56;:::i;:::-;3225:62;;3306:40;3332:7;1136::12::0;1162:6;-1:-1:-1;;;;;1162:6:12;;1090:85;3332:7:8::1;3342:3;3306:17;:40::i;:::-;3178:407;;;3476:21;:32;3498:6;;3505:1;3498:9;;;;;-1:-1:-1::0;;;3498:9:8::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;3476:32:8::1;-1:-1:-1::0;;;;;3476:32:8::1;;;;;;;;;;;;;3418:6;;3425:1;3418:9;;;;;-1:-1:-1::0;;;3418:9:8::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3411:42;::::0;-1:-1:-1;;;3411:42:8;;3447:4:::1;3411:42;::::0;::::1;11749:51:23::0;-1:-1:-1;;;;;3411:27:8;;;::::1;::::0;::::1;::::0;11722:18:23;;3411:42:8::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:97;;;;:::i;:::-;3385:123;;3526:44;3557:7;1136::12::0;1162:6;-1:-1:-1;;;;;1162:6:12;;1090:85;3557:7:8::1;3566:3;3533:6;;3540:1;3533:9;;;;;-1:-1:-1::0;;;3533:9:8::1;;;;;;;;3526:44;-1:-1:-1::0;3133:3:8;::::1;::::0;::::1;:::i;:::-;;;;3094:501;;;;3014:587:::0;;:::o;1722:145:12:-;1136:7;1162:6;-1:-1:-1;;;;;1162:6:12;665:10:19;1302:23:12;1294:68;;;;-1:-1:-1;;;1294:68:12;;;;;;;:::i;:::-;1828:1:::1;1812:6:::0;;1791:40:::1;::::0;-1:-1:-1;;;;;1812:6:12;;::::1;::::0;1791:40:::1;::::0;1828:1;;1791:40:::1;1858:1;1841:19:::0;;-1:-1:-1;;;;;;1841:19:12::1;::::0;;1722:145::o;15473:692:3:-;15608:15;15637;15666:14;15694;15733:19;15770:15;15733:53;;15805:4;-1:-1:-1;;;;;15805:11:3;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15796:22;;15837:4;-1:-1:-1;;;;;15837:11:3;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15880:41;;-1:-1:-1;;;15880:41:3;;-1:-1:-1;;;;;11767:32:23;;;15880:41:3;;;11749:51:23;15828:22:3;;-1:-1:-1;15861:16:3;;15880:24;;;;;11722:18:23;;15880:41:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15950;;-1:-1:-1;;;15950:41:3;;-1:-1:-1;;;;;11767:32:23;;;15950:41:3;;;11749:51:23;15861:60:3;;-1:-1:-1;15931:16:3;;15950:24;;;;;11722:18:23;;15950:41:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15931:60;;16002:20;16025:4;-1:-1:-1;;;;;16025:16:3;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;16002:41;-1:-1:-1;16002:41:3;16065:20;16077:8;16065:9;:20;:::i;:::-;16064:37;;;;:::i;:::-;16054:47;-1:-1:-1;16146:12:3;16122:20;16134:8;16122:9;:20;:::i;:::-;16121:37;;;;:::i;:::-;16111:47;;15473:692;;;;;;;;;;;:::o;10686:789::-;11004:7;1127::8;;-1:-1:-1;;;1127:7:8;;;;1123:98;;;1150:28;;-1:-1:-1;;;1150:28:8;;;;;;;:::i;1123:98::-;11041:30:3::1;11055:15;11041:13;:30::i;:::-;11082:12;11100:15;-1:-1:-1::0;;;;;11100:20:3::1;11121:10;11100:32;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11081:51;;;11150:7;11142:36;;;::::0;-1:-1:-1;;;11142:36:3;;19023:2:23;11142:36:3::1;::::0;::::1;19005:21:23::0;19062:2;19042:18;;;19035:30;-1:-1:-1;;;19081:18:23;;;19074:46;19137:18;;11142:36:3::1;18995:166:23::0;11142:36:3::1;11210:248;11234:14;11266:15;11299:10;11327:12;11357:11;11386:8;11412:9;11439:5;11210:6;:248::i;:::-;11189:279:::0;10686:789;-1:-1:-1;;;;;;;;;;10686:789:3:o;4301:333:8:-;1136:7:12;1162:6;-1:-1:-1;;;;;1162:6:12;665:10:19;1302:23:12;1294:68;;;;-1:-1:-1;;;1294:68:12;;;;;;;:::i;:::-;4444:35:8;;::::1;4436:68;;;::::0;-1:-1:-1;;;4436:68:8;;19724:2:23;4436:68:8::1;::::0;::::1;19706:21:23::0;19763:2;19743:18;;;19736:30;-1:-1:-1;;;19782:18:23;;;19775:50;19842:18;;4436:68:8::1;19696:170:23::0;4436:68:8::1;4520:9;4515:113;4535:18:::0;;::::1;4515:113;;;4604:10;;4615:1;4604:13;;;;;-1:-1:-1::0;;;4604:13:8::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4574:15;:27;4590:7;;4598:1;4590:10;;;;;-1:-1:-1::0;;;4590:10:8::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;4574:27:8::1;::::0;;::::1;::::0;::::1;::::0;;;;;;-1:-1:-1;4574:27:8;:43;;-1:-1:-1;;4574:43:8::1;::::0;::::1;;::::0;;;::::1;::::0;;4555:3;::::1;::::0;::::1;:::i;:::-;;;;4515:113;;;;4301:333:::0;;;;:::o;9719:539:3:-;9918:15;1127:7:8;;9918:15:3;;-1:-1:-1;;;1127:7:8;;;;1123:98;;;1150:28;;-1:-1:-1;;;1150:28:8;;;;;;;:::i;1123:98::-;9980:30:3::1;9994:15;9980:13;:30::i;:::-;10021:12;10039:15;-1:-1:-1::0;;;;;10039:20:3::1;10060:10;;10039:32;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10020:51;;;10089:7;10081:36;;;::::0;-1:-1:-1;;;10081:36:3;;19023:2:23;10081:36:3::1;::::0;::::1;19005:21:23::0;19062:2;19042:18;;;19035:30;-1:-1:-1;;;19081:18:23;;;19074:46;19137:18;;10081:36:3::1;18995:166:23::0;10081:36:3::1;10149:102;10179:15;10208:10;10232:9;10149:16;:102::i;:::-;10128:123:::0;;;;-1:-1:-1;9719:539:3;-1:-1:-1;;;;;;;9719:539:3:o;4762:2309::-;4914:15;1127:7:8;;4914:15:3;;-1:-1:-1;;;1127:7:8;;;;1123:98;;;1150:28;;-1:-1:-1;;;1150:28:8;;;;;;;:::i;1123:98::-;4995:15:3;-1:-1:-1;;;;;5030:27:3;::::1;5022:67;;;::::0;-1:-1:-1;;;5022:67:3;;19368:2:23;5022:67:3::1;::::0;::::1;19350:21:23::0;19407:2;19387:18;;;19380:30;19446:29;19426:18;;;19419:57;19493:18;;5022:67:3::1;19340:177:23::0;5022:67:3::1;5124:14;5141:4;-1:-1:-1::0;;;;;5141:11:3::1;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5124:30;;5164:14;5181:4;-1:-1:-1::0;;;;;5181:11:3::1;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5164:30:::0;-1:-1:-1;5205:125:3::1;-1:-1:-1::0;;;;;5205:40:3;::::1;5259:10;5291:4;5310:10:::0;5205:40:::1;:125::i;:::-;5341:68;5355:15;3777:42;5398:10;5341:13;:68::i;:::-;-1:-1:-1::0;;;;;5424:28:3;::::1;4018:42;5424:28;::::0;:60:::1;;-1:-1:-1::0;;;;;;5456:28:3;::::1;4018:42;5456:28;5424:60;5420:1511;;;5500:14;-1:-1:-1::0;;;;;5517:28:3;::::1;4018:42;5517:28;:46;;5557:6;5517:46;;;5548:6;5517:46;5598:195;::::0;-1:-1:-1;;;5598:195:3;;-1:-1:-1;;;;;14292:15:23;;5598:195:3::1;::::0;::::1;14274:34:23::0;14324:18;;;14317:34;;;5702:1:3::1;14367:18:23::0;;;14360:34;;;14410:18;;;14403:34;5748:4:3::1;14453:19:23::0;;;14446:44;-1:-1:-1;;;14506:19:23;;;14499:35;5500:63:3;;-1:-1:-1;3777:42:3::1;::::0;5598:34:::1;::::0;14208:19:23;;5598:195:3::1;::::0;::::1;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5577:216:::0;;-1:-1:-1;5577:216:3;-1:-1:-1;5841:21:3::1;5881:51;5899:6:::0;5577:216;5916:9;5927:4:::1;5881:17;:51::i;:::-;5841:91;;5946:19;5984:55;865:42:8;6014:7:3;6023:9;6034:4;5984:17;:55::i;:::-;5946:93:::0;-1:-1:-1;6081:64:3::1;6109:10;6121:23;6131:13:::0;6121:7;:23:::1;:::i;:::-;-1:-1:-1::0;;;;;6081:27:3;::::1;::::0;:64;:27:::1;:64::i;:::-;6159:61;6185:10;6198:21;6208:11:::0;6198:7;:21:::1;:::i;:::-;6159:17;:61::i;:::-;5420:1511;;;;;;6272:216;::::0;-1:-1:-1;;;6272:216:3;;3777:42:::1;::::0;6272:31:::1;::::0;:216:::1;::::0;6321:6;;6345;;6369:10;;6397:1:::1;::::0;;;6443:4:::1;::::0;-1:-1:-1;;;3623:66:3;6272:216:::1;;;:::i;:::-;;::::0;::::1;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6251:237:::0;;-1:-1:-1;6251:237:3;-1:-1:-1;6536:22:3::1;6577:51;6595:6:::0;6251:237;6612:9;6623:4:::1;6577:17;:51::i;:::-;6536:92;;6642:22;6683:51;6701:6;6709:7;6718:9;6729:4;6683:17;:51::i;:::-;6642:92:::0;-1:-1:-1;6776:65:3::1;6804:10;6816:24;6826:14:::0;6816:7;:24:::1;:::i;:::-;-1:-1:-1::0;;;;;6776:27:3;::::1;::::0;:65;:27:::1;:65::i;:::-;6855;6883:10;6895:24;6905:14:::0;6895:7;:24:::1;:::i;6855:65::-;5420:1511;;;6945:52;6952:10;6964:15;6981:6;6989:7;6945:52;;;;;;;;;:::i;:::-;;;;;;;;7012;7019:10;7031:15;7048:6;7056:7;7012:52;;;;;;;;;:::i;:::-;;;;;;;;1209:1:8;;;4762:2309:3::0;;;;;;:::o;2016:274:12:-;1136:7;1162:6;-1:-1:-1;;;;;1162:6:12;665:10:19;1302:23:12;1294:68;;;;-1:-1:-1;;;1294:68:12;;;;;;;:::i;:::-;-1:-1:-1;;;;;2117:22:12;::::1;2096:107;;;::::0;-1:-1:-1;;;2096:107:12;;16372:2:23;2096:107:12::1;::::0;::::1;16354:21:23::0;16411:2;16391:18;;;16384:30;16450:34;16430:18;;;16423:62;-1:-1:-1;;;16501:18:23;;;16494:36;16547:19;;2096:107:12::1;16344:228:23::0;2096:107:12::1;2239:6;::::0;;2218:38:::1;::::0;-1:-1:-1;;;;;2218:38:12;;::::1;::::0;2239:6;::::1;::::0;2218:38:::1;::::0;::::1;2266:6;:17:::0;;-1:-1:-1;;;;;;2266:17:12::1;-1:-1:-1::0;;;;;2266:17:12;;;::::1;::::0;;;::::1;::::0;;2016:274::o;2129:148:8:-;1136:7:12;1162:6;-1:-1:-1;;;;;1162:6:12;665:10:19;1302:23:12;1294:68;;;;-1:-1:-1;;;1294:68:12;;;;;;;:::i;:::-;-1:-1:-1;;;;;2237:24:8;;;::::1;;::::0;;;:12:::1;:24;::::0;;;;:33;;-1:-1:-1;;2237:33:8::1;::::0;::::1;;::::0;;;::::1;::::0;;2129:148::o;2068:459:18:-;2195:6;2170:21;:31;;2149:107;;;;-1:-1:-1;;;2149:107:18;;17903:2:23;2149:107:18;;;17885:21:23;17942:2;17922:18;;;17915:30;17981:31;17961:18;;;17954:59;18030:18;;2149:107:18;17875:179:23;2149:107:18;2345:12;2363:9;-1:-1:-1;;;;;2363:14:18;2386:6;2363:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2344:54;;;2429:7;2408:112;;;;-1:-1:-1;;;2408:112:18;;17129:2:23;2408:112:18;;;17111:21:23;17168:2;17148:18;;;17141:30;17207:34;17187:18;;;17180:62;17278:28;17258:18;;;17251:56;17324:19;;2408:112:18;17101:248:23;634:239:16;798:58;;-1:-1:-1;;;;;13846:32:23;;798:58:16;;;13828:51:23;13895:18;;;13888:34;;;746:120:16;;779:5;;-1:-1:-1;;;821:23:16;13801:18:23;;798:58:16;;;;-1:-1:-1;;798:58:16;;;;;;;;;;;;;;-1:-1:-1;;;;;798:58:16;-1:-1:-1;;;;;;798:58:16;;;;;;;;;;746:19;:120::i;11844:862:3:-;11993:15;;12074;-1:-1:-1;;;;;12109:27:3;;12101:67;;;;-1:-1:-1;;;12101:67:3;;19368:2:23;12101:67:3;;;19350:21:23;19407:2;19387:18;;;19380:30;19446:29;19426:18;;;19419:57;19493:18;;12101:67:3;19340:177:23;12101:67:3;12179:14;12196:4;-1:-1:-1;;;;;12196:11:3;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12179:30;;12219:14;12236:4;-1:-1:-1;;;;;12236:11:3;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12219:30;;12260:65;12272:15;12289:10;12301:23;12260:11;:65::i;:::-;;12336:68;12350:15;3777:42;12393:10;12336:13;:68::i;:::-;12436:184;;-1:-1:-1;;;12436:184:3;;3777:42;;12436:31;;:184;;12481:6;;12501;;12521:10;;12545:1;;;;12583:4;;-1:-1:-1;;;3623:66:3;12436:184;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12415:205;;-1:-1:-1;12415:205:3;-1:-1:-1;12638:11:3;;;;;:26;;;12663:1;12653:7;:11;12638:26;12630:69;;;;-1:-1:-1;;;12630:69:3;;21967:2:23;12630:69:3;;;21949:21:23;22006:2;21986:18;;;21979:30;22045:32;22025:18;;;22018:60;22095:18;;12630:69:3;21939:180:23;12630:69:3;11844:862;;;;;;;;;:::o;12712:1273::-;12936:20;12968:14;13000:15;-1:-1:-1;;;;;12985:38:3;;:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12968:57;;13035:14;13067:15;-1:-1:-1;;;;;13052:38:3;;:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;13035:57;;13150:7;-1:-1:-1;;;;;13140:17:3;:6;-1:-1:-1;;;;;13140:17:3;;13136:400;;;13188:22;13203:7;13188:12;:22;:::i;:::-;13173:37;;13136:400;;;13342:183;13374:6;13402:7;13431;13460:11;13472:1;13460:14;;;;;;-1:-1:-1;;;13460:14:3;;;;;;;;;;;;;;;13496:8;13505:1;13496:11;;;;;;-1:-1:-1;;;13496:11:3;;;;;;;;;;;;;;;13342:10;:183::i;:::-;13311:214;;:12;:214;:::i;:::-;13280:245;;13136:400;13593:7;-1:-1:-1;;;;;13583:17:3;:6;-1:-1:-1;;;;;13583:17:3;;13579:400;;;13631:22;13646:7;13631:12;:22;:::i;:::-;13616:37;;13579:400;;;13785:183;13817:6;13845:7;13874;13903:11;13915:1;13903:14;;;;;;-1:-1:-1;;;13903:14:3;;;;;;;;;;;;;;;13939:8;13948:1;13939:11;;;;;;-1:-1:-1;;;13939:11:3;;;;;;;;13785:183;13754:214;;:12;:214;:::i;:::-;13723:245;;13579:400;12712:1273;;;;;;;;;;:::o;1231:786:10:-;1457:10;1385:28;1444:24;;;:12;:24;;;;;;;;1482:14;:30;;;;;1501:11;1500:12;1482:30;:46;;;;;1527:1;1516:8;;:12;1482:46;1478:533;;;1589:5;1577:8;;1568:6;:17;;;;:::i;:::-;1567:27;;;;:::i;:::-;-1:-1:-1;;;;;1613:21:10;;;;;;:10;:21;;;;;;1544:50;;-1:-1:-1;1613:21:10;;1609:392;;;-1:-1:-1;;;;;1658:19:10;;1654:84;;865:42:8;1701:18:10;;1654:84;1756:24;1845:3;1827:14;;1804:20;:37;;;;:::i;:::-;1803:45;;;;:::i;:::-;-1:-1:-1;;;;;1866:27:10;;;;;;;:16;:27;;;;;;;;:34;;;;;;;;;;;:54;;1756:92;;-1:-1:-1;1756:92:10;;1866:34;;:27;:54;;1756:92;;1866:54;:::i;:::-;;;;-1:-1:-1;;;;;;;1938:28:10;;;;;;:21;:28;;;;;:48;;1970:16;;1938:28;:48;;1970:16;;1938:48;:::i;:::-;;;;-1:-1:-1;;;1609:392:10;1231:786;;;;;;;:::o;11481:357:3:-;11549:19;11586:11;11549:49;;11608:14;11625:4;-1:-1:-1;;;;;11625:11:3;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11608:30;;11648:14;11665:4;-1:-1:-1;;;;;11665:11:3;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11716:40;;-1:-1:-1;;;11716:40:3;;-1:-1:-1;;;;;12041:15:23;;;11716:40:3;;;12023:34:23;12093:15;;12073:18;;;12066:43;11648:30:3;;-1:-1:-1;11689:24:3;;3906:42;;11716:24;;11958:18:23;;11716:40:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;11689:67;;11795:11;-1:-1:-1;;;;;11775:31:3;:16;-1:-1:-1;;;;;11775:31:3;;11767:64;;;;-1:-1:-1;;;11767:64:3;;22737:2:23;11767:64:3;;;22719:21:23;22776:2;22756:18;;;22749:30;-1:-1:-1;;;22795:18:23;;;22788:50;22855:18;;11767:64:3;22709:170:23;879:275:16;1069:68;;-1:-1:-1;;;;;12839:15:23;;;1069:68:16;;;12821:34:23;12891:15;;12871:18;;;12864:43;12923:18;;;12916:34;;;1017:130:16;;1050:5;;-1:-1:-1;;;1092:27:16;12756:18:23;;1069:68:16;12738:218:23;1786:216:8;1906:37;-1:-1:-1;;;;;1906:25:8;;1932:7;1941:1;1906:25;:37::i;:::-;1953:42;-1:-1:-1;;;;;1953:25:8;;1979:7;1988:6;1953:25;:42::i;3561:867:16:-;3980:23;4018:115;4063:4;4018:115;;;;;;;;;;;;;;;;;4026:5;-1:-1:-1;;;;;4018:27:16;;;:115;;;;;:::i;:::-;4147:17;;3980:153;;-1:-1:-1;4147:21:16;4143:279;;4316:10;4305:30;;;;;;;;;;;;:::i;:::-;4280:131;;;;-1:-1:-1;;;4280:131:16;;22326:2:23;4280:131:16;;;22308:21:23;22365:2;22345:18;;;22338:30;22404:34;22384:18;;;22377:62;-1:-1:-1;;;22455:18:23;;;22448:40;22505:19;;4280:131:16;22298:232:23;483:742:10;613:7;636:23;632:587;;;719:10;1090:20:18;675:133:10;;;;-1:-1:-1;;;675:133:10;;20836:2:23;675:133:10;;;20818:21:23;20875:2;20855:18;;;20848:30;20914:34;20894:18;;;20887:62;-1:-1:-1;;;20965:18:23;;;20958:42;21017:19;;675:133:10;20808:234:23;675:133:10;859:50;;-1:-1:-1;;;859:50:10;;883:10;859:50;;;12023:34:23;903:4:10;12073:18:23;;;12066:43;823:17:10;;-1:-1:-1;;;;;859:23:10;;;;;11958:18:23;;859:50:10;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;823:86;-1:-1:-1;923:130:10;-1:-1:-1;;;;;923:30:10;;971:10;1007:4;823:86;923:30;:130::i;:::-;1075:9;-1:-1:-1;1068:16:10;;632:587;1115:65;-1:-1:-1;;;;;1115:30:10;;1146:10;1166:4;1173:6;1115:30;:65::i;:::-;-1:-1:-1;1202:6:10;632:587;483:742;;;;;:::o;13991:1003:3:-;14177:7;-1:-1:-1;;;;;14200:38:3;;4018:42;14200:38;:63;;;;-1:-1:-1;;;;;;14242:21:3;;;14200:63;14196:163;;;14279:42;;-1:-1:-1;;;14279:42:3;;;;;23453:25:23;;;4018:42:3;;14279:34;;23426:18:23;;14279:42:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14342:6;14335:13;;;;14196:163;14369:19;-1:-1:-1;;;;;14402:30:3;;14398:163;;-1:-1:-1;14462:6:3;14398:163;;;14499:51;14513:16;14531:10;14543:6;14499:13;:51::i;:::-;14571:22;14596:20;14608:7;14596:11;:20::i;:::-;-1:-1:-1;;;;;14635:27:3;;;;;;:15;:27;;;;;;14571:45;;-1:-1:-1;14635:27:3;;14627:61;;;;-1:-1:-1;;;14627:61:3;;15327:2:23;14627:61:3;;;15309:21:23;15366:2;15346:18;;;15339:30;-1:-1:-1;;;15385:18:23;;;15378:51;15446:18;;14627:61:3;15299:171:23;14627:61:3;14699:12;14717:10;-1:-1:-1;;;;;14717:15:3;14741:11;14755:8;14717:47;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14698:66;;;14782:7;14774:41;;;;-1:-1:-1;;;14774:41:3;;16779:2:23;14774:41:3;;;16761:21:23;16818:2;16798:18;;;16791:30;-1:-1:-1;;;16837:18:23;;;16830:51;16898:18;;14774:41:3;16751:171:23;14774:41:3;14826:20;14872:14;14849:20;14861:7;14849:11;:20::i;:::-;:37;;;;:::i;:::-;14826:60;;14920:1;14905:12;:16;14897:60;;;;-1:-1:-1;;;14897:60:3;;21249:2:23;14897:60:3;;;21231:21:23;21288:2;21268:18;;;21261:30;21327:33;21307:18;;;21300:61;21378:18;;14897:60:3;21221:181:23;14897:60:3;14975:12;-1:-1:-1;;;;13991:1003:3;;;;;;;;:::o;1414:690:16:-;1822:10;;;1821:62;;-1:-1:-1;1838:39:16;;-1:-1:-1;;;1838:39:16;;1862:4;1838:39;;;12023:34:23;-1:-1:-1;;;;;12093:15:23;;;12073:18;;;12066:43;1838:15:16;;;;;11958:18:23;;1838:39:16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;1821:62;1800:163;;;;-1:-1:-1;;;1800:163:16;;23086:2:23;1800:163:16;;;23068:21:23;23125:2;23105:18;;;23098:30;23164:34;23144:18;;;23137:62;-1:-1:-1;;;23215:18:23;;;23208:52;23277:19;;1800:163:16;23058:244:23;1800:163:16;2025:62;;-1:-1:-1;;;;;13846:32:23;;2025:62:16;;;13828:51:23;13895:18;;;13888:34;;;1973:124:16;;2006:5;;-1:-1:-1;;;2048:22:16;13801:18:23;;2025:62:16;13783:145:23;3683:223:18;3816:12;3847:52;3869:6;3877:4;3883:1;3886:12;3847:21;:52::i;:::-;3840:59;3683:223;-1:-1:-1;;;;3683:223:18:o;1233:280:8:-;1316:15;-1:-1:-1;;;;;1351:19:8;;1347:160;;-1:-1:-1;1396:21:8;1233:280;;;:::o;1347:160::-;1458:38;;-1:-1:-1;;;1458:38:8;;1490:4;1458:38;;;11749:51:23;-1:-1:-1;;;;;1458:23:8;;;;;11722:18:23;;1458:38:8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1448:48;;1347:160;1233:280;;;:::o;4860:607:18:-;5025:12;5095:5;5070:21;:30;;5049:115;;;;-1:-1:-1;;;5049:115:18;;18261:2:23;5049:115:18;;;18243:21:23;18300:2;18280:18;;;18273:30;18339:34;18319:18;;;18312:62;-1:-1:-1;;;18390:18:23;;;18383:36;18436:19;;5049:115:18;18233:228:23;5049:115:18;1090:20;;5174:60;;;;-1:-1:-1;;;5174:60:18;;21609:2:23;5174:60:18;;;21591:21:23;21648:2;21628:18;;;21621:30;21687:31;21667:18;;;21660:59;21736:18;;5174:60:18;21581:179:23;5174:60:18;5305:12;5319:23;5358:6;-1:-1:-1;;;;;5358:11:18;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:18:o;7683:756::-;7829:12;7857:7;7853:580;;;-1:-1:-1;7887:10:18;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:18;;;;;;;;:::i;14:134:23:-;82:20;;111:31;82:20;111:31;:::i;153:395::-;216:8;226:6;280:3;273:4;265:6;261:17;257:27;247:2;;305:8;295;288:26;247:2;-1:-1:-1;335:20:23;;378:18;367:30;;364:2;;;417:8;407;400:26;364:2;461:4;453:6;449:17;437:29;;521:3;514:4;504:6;501:1;497:14;489:6;485:27;481:38;478:47;475:2;;;538:1;535;528:12;475:2;237:311;;;;;:::o;553:768::-;607:5;660:3;653:4;645:6;641:17;637:27;627:2;;682:5;675;668:20;627:2;722:6;709:20;748:4;772:60;788:43;828:2;788:43;:::i;:::-;772:60;:::i;:::-;854:3;878:2;873:3;866:15;906:2;901:3;897:12;890:19;;941:2;933:6;929:15;993:3;988:2;982;979:1;975:10;967:6;963:23;959:32;956:41;953:2;;;1014:5;1007;1000:20;953:2;1040:5;1054:238;1068:2;1065:1;1062:9;1054:238;;;1139:3;1126:17;1156:31;1181:5;1156:31;:::i;:::-;1200:18;;1238:12;;;;1270;;;;1086:1;1079:9;1054:238;;;-1:-1:-1;1310:5:23;;617:704;-1:-1:-1;;;;;;;617:704:23:o;1326:855::-;1378:5;1431:3;1424:4;1416:6;1412:17;1408:27;1398:2;;1453:5;1446;1439:20;1398:2;1493:6;1480:20;1519:4;1543:60;1559:43;1599:2;1559:43;:::i;1543:60::-;1625:3;1649:2;1644:3;1637:15;1677:2;1672:3;1668:12;1661:19;;1712:2;1704:6;1700:15;1764:3;1759:2;1753;1750:1;1746:10;1738:6;1734:23;1730:32;1727:41;1724:2;;;1785:5;1778;1771:20;1724:2;1811:5;1825:327;1839:2;1836:1;1833:9;1825:327;;;1916:3;1903:17;1952:18;1939:11;1936:35;1933:2;;;1988:5;1981;1974:20;1933:2;2021:56;2073:3;2068:2;2054:11;2046:6;2042:24;2038:33;2021:56;:::i;:::-;2009:69;;-1:-1:-1;2098:12:23;;;;2130;;;;1857:1;1850:9;1825:327;;2186:550;2228:5;2281:3;2274:4;2266:6;2262:17;2258:27;2248:2;;2303:5;2296;2289:20;2248:2;2343:6;2330:20;2369:18;2365:2;2362:26;2359:2;;;2391:18;;:::i;:::-;2435:55;2478:2;2459:13;;-1:-1:-1;;2455:27:23;2484:4;2451:38;2435:55;:::i;:::-;2515:2;2506:7;2499:19;2561:3;2554:4;2549:2;2541:6;2537:15;2533:26;2530:35;2527:2;;;2582:5;2575;2568:20;2527:2;2651;2644:4;2636:6;2632:17;2625:4;2616:7;2612:18;2599:55;2674:16;;;2692:4;2670:27;2663:42;;;;2678:7;2238:498;-1:-1:-1;;2238:498:23:o;2741:257::-;2800:6;2853:2;2841:9;2832:7;2828:23;2824:32;2821:2;;;2874:6;2866;2859:22;2821:2;2918:9;2905:23;2937:31;2962:5;2937:31;:::i;3003:261::-;3073:6;3126:2;3114:9;3105:7;3101:23;3097:32;3094:2;;;3147:6;3139;3132:22;3094:2;3184:9;3178:16;3203:31;3228:5;3203:31;:::i;3269:398::-;3337:6;3345;3398:2;3386:9;3377:7;3373:23;3369:32;3366:2;;;3419:6;3411;3404:22;3366:2;3463:9;3450:23;3482:31;3507:5;3482:31;:::i;:::-;3532:5;-1:-1:-1;3589:2:23;3574:18;;3561:32;3602:33;3561:32;3602:33;:::i;:::-;3654:7;3644:17;;;3356:311;;;;;:::o;3672:1325::-;3850:6;3858;3866;3874;3882;3890;3898;3906;3959:3;3947:9;3938:7;3934:23;3930:33;3927:2;;;3981:6;3973;3966:22;3927:2;4025:9;4012:23;4044:31;4069:5;4044:31;:::i;:::-;4094:5;-1:-1:-1;4151:2:23;4136:18;;4123:32;4164:33;4123:32;4164:33;:::i;:::-;4216:7;-1:-1:-1;4270:2:23;4255:18;;4242:32;;-1:-1:-1;4321:2:23;4306:18;;4293:32;;-1:-1:-1;4376:3:23;4361:19;;4348:33;4400:18;4430:14;;;4427:2;;;4462:6;4454;4447:22;4427:2;4490:61;4543:7;4534:6;4523:9;4519:22;4490:61;:::i;:::-;4480:71;;4604:3;4593:9;4589:19;4576:33;4560:49;;4634:2;4624:8;4621:16;4618:2;;;4655:6;4647;4640:22;4618:2;;4683:61;4736:7;4725:8;4714:9;4710:24;4683:61;:::i;:::-;4673:71;;;4796:3;4785:9;4781:19;4768:33;4810;4835:7;4810:33;:::i;:::-;4862:7;-1:-1:-1;4921:3:23;4906:19;;4893:33;4935:30;4893:33;4935:30;:::i;:::-;4984:7;4974:17;;;3917:1080;;;;;;;;;;;:::o;5002:1203::-;5192:6;5200;5208;5216;5224;5232;5240;5248;5301:3;5289:9;5280:7;5276:23;5272:33;5269:2;;;5323:6;5315;5308:22;5269:2;5351:29;5370:9;5351:29;:::i;:::-;5341:39;;5399:38;5433:2;5422:9;5418:18;5399:38;:::i;:::-;5389:48;;5484:2;5473:9;5469:18;5456:32;5446:42;;5535:2;5524:9;5520:18;5507:32;5497:42;;5590:3;5579:9;5575:19;5562:33;5614:18;5655:2;5647:6;5644:14;5641:2;;;5676:6;5668;5661:22;5641:2;5704:49;5745:7;5736:6;5725:9;5721:22;5704:49;:::i;:::-;5694:59;;5806:3;5795:9;5791:19;5778:33;5762:49;;5836:2;5826:8;5823:16;5820:2;;;5857:6;5849;5842:22;5820:2;5885:63;5940:7;5929:8;5918:9;5914:24;5885:63;:::i;:::-;5875:73;;6001:3;5990:9;5986:19;5973:33;5957:49;;6031:2;6021:8;6018:16;6015:2;;;6052:6;6044;6037:22;6015:2;;6080:61;6133:7;6122:8;6111:9;6107:24;6080:61;:::i;:::-;6070:71;;;6160:39;6194:3;6183:9;6179:19;6160:39;:::i;:::-;6150:49;;5259:946;;;;;;;;;;;:::o;6210:392::-;6275:6;6283;6336:2;6324:9;6315:7;6311:23;6307:32;6304:2;;;6357:6;6349;6342:22;6304:2;6401:9;6388:23;6420:31;6445:5;6420:31;:::i;:::-;6470:5;-1:-1:-1;6527:2:23;6512:18;;6499:32;6540:30;6499:32;6540:30;:::i;6607:325::-;6675:6;6683;6736:2;6724:9;6715:7;6711:23;6707:32;6704:2;;;6757:6;6749;6742:22;6704:2;6801:9;6788:23;6820:31;6845:5;6820:31;:::i;:::-;6870:5;6922:2;6907:18;;;;6894:32;;-1:-1:-1;;;6694:238:23:o;6937:466::-;7014:6;7022;7030;7083:2;7071:9;7062:7;7058:23;7054:32;7051:2;;;7104:6;7096;7089:22;7051:2;7148:9;7135:23;7167:31;7192:5;7167:31;:::i;:::-;7217:5;-1:-1:-1;7269:2:23;7254:18;;7241:32;;-1:-1:-1;7325:2:23;7310:18;;7297:32;7338:33;7297:32;7338:33;:::i;:::-;7390:7;7380:17;;;7041:362;;;;;:::o;7408:986::-;7505:6;7513;7521;7529;7537;7590:3;7578:9;7569:7;7565:23;7561:33;7558:2;;;7612:6;7604;7597:22;7558:2;7656:9;7643:23;7675:31;7700:5;7675:31;:::i;:::-;7725:5;-1:-1:-1;7777:2:23;7762:18;;7749:32;;-1:-1:-1;7833:2:23;7818:18;;7805:32;7846:33;7805:32;7846:33;:::i;:::-;7898:7;-1:-1:-1;7956:2:23;7941:18;;7928:32;7979:18;8009:14;;;8006:2;;;8041:6;8033;8026:22;8006:2;8084:6;8073:9;8069:22;8059:32;;8129:7;8122:4;8118:2;8114:13;8110:27;8100:2;;8156:6;8148;8141:22;8100:2;8201;8188:16;8227:2;8219:6;8216:14;8213:2;;;8248:6;8240;8233:22;8213:2;8298:7;8293:2;8284:6;8280:2;8276:15;8272:24;8269:37;8266:2;;;8324:6;8316;8309:22;8266:2;7548:846;;;;-1:-1:-1;7548:846:23;;-1:-1:-1;8360:2:23;8352:11;;8382:6;7548:846;-1:-1:-1;;;7548:846:23:o;8399:457::-;8485:6;8493;8546:2;8534:9;8525:7;8521:23;8517:32;8514:2;;;8567:6;8559;8552:22;8514:2;8612:9;8599:23;8645:18;8637:6;8634:30;8631:2;;;8682:6;8674;8667:22;8631:2;8726:70;8788:7;8779:6;8768:9;8764:22;8726:70;:::i;:::-;8815:8;;8700:96;;-1:-1:-1;8504:352:23;-1:-1:-1;;;;8504:352:23:o;8861:800::-;8980:6;8988;8996;9004;9057:2;9045:9;9036:7;9032:23;9028:32;9025:2;;;9078:6;9070;9063:22;9025:2;9123:9;9110:23;9152:18;9193:2;9185:6;9182:14;9179:2;;;9214:6;9206;9199:22;9179:2;9258:70;9320:7;9311:6;9300:9;9296:22;9258:70;:::i;:::-;9347:8;;-1:-1:-1;9232:96:23;-1:-1:-1;9435:2:23;9420:18;;9407:32;;-1:-1:-1;9451:16:23;;;9448:2;;;9485:6;9477;9470:22;9448:2;;9529:72;9593:7;9582:8;9571:9;9567:24;9529:72;:::i;:::-;9015:646;;;;-1:-1:-1;9620:8:23;-1:-1:-1;;;;9015:646:23:o;9666:251::-;9722:6;9775:2;9763:9;9754:7;9750:23;9746:32;9743:2;;;9796:6;9788;9781:22;9743:2;9840:9;9827:23;9859:28;9881:5;9859:28;:::i;9922:255::-;9989:6;10042:2;10030:9;10021:7;10017:23;10013:32;10010:2;;;10063:6;10055;10048:22;10010:2;10100:9;10094:16;10119:28;10141:5;10119:28;:::i;10182:190::-;10241:6;10294:2;10282:9;10273:7;10269:23;10265:32;10262:2;;;10315:6;10307;10300:22;10262:2;-1:-1:-1;10343:23:23;;10252:120;-1:-1:-1;10252:120:23:o;10377:194::-;10447:6;10500:2;10488:9;10479:7;10475:23;10471:32;10468:2;;;10521:6;10513;10506:22;10468:2;-1:-1:-1;10549:16:23;;10458:113;-1:-1:-1;10458:113:23:o;10576:255::-;10655:6;10663;10716:2;10704:9;10695:7;10691:23;10687:32;10684:2;;;10737:6;10729;10722:22;10684:2;-1:-1:-1;;10765:16:23;;10821:2;10806:18;;;10800:25;10765:16;;10800:25;;-1:-1:-1;10674:157:23:o;10836:273::-;11019:6;11011;11006:3;10993:33;10975:3;11045:16;;11070:15;;;11045:16;10983:126;-1:-1:-1;10983:126:23:o;11114:274::-;11243:3;11281:6;11275:13;11297:53;11343:6;11338:3;11331:4;11323:6;11319:17;11297:53;:::i;:::-;11366:16;;;;;11251:137;-1:-1:-1;;11251:137:23:o;12120:456::-;-1:-1:-1;;;;;12407:15:23;;;12389:34;;12459:15;;;12454:2;12439:18;;12432:43;12511:15;;12506:2;12491:18;;12484:43;12558:2;12543:18;;12536:34;;;;12338:3;12323:19;;12305:271::o;12961:688::-;-1:-1:-1;;;;;13348:15:23;;;13330:34;;13400:15;;;13395:2;13380:18;;13373:43;13447:2;13432:18;;13425:34;;;;13490:2;13475:18;;13468:34;;;;13533:3;13518:19;;13511:35;13583:15;;;13310:3;13562:19;;13555:44;13630:3;13615:19;;13608:35;;;;13279:3;13264:19;;13246:403::o;14737:383::-;14886:2;14875:9;14868:21;14849:4;14918:6;14912:13;14961:6;14956:2;14945:9;14941:18;14934:34;14977:66;15036:6;15031:2;15020:9;15016:18;15011:2;15003:6;14999:15;14977:66;:::i;:::-;15104:2;15083:15;-1:-1:-1;;15079:29:23;15064:45;;;;15111:2;15060:54;;14858:262;-1:-1:-1;;14858:262:23:o;17354:342::-;17556:2;17538:21;;;17595:2;17575:18;;;17568:30;-1:-1:-1;;;17629:2:23;17614:18;;17607:48;17687:2;17672:18;;17528:168::o;20273:356::-;20475:2;20457:21;;;20494:18;;;20487:30;20553:34;20548:2;20533:18;;20526:62;20620:2;20605:18;;20447:182::o;24194:275::-;24265:2;24259:9;24330:2;24311:13;;-1:-1:-1;;24307:27:23;24295:40;;24365:18;24350:34;;24386:22;;;24347:62;24344:2;;;24412:18;;:::i;:::-;24448:2;24441:22;24239:230;;-1:-1:-1;24239:230:23:o;24474:183::-;24534:4;24567:18;24559:6;24556:30;24553:2;;;24589:18;;:::i;:::-;-1:-1:-1;24634:1:23;24630:14;24646:4;24626:25;;24543:114::o;24662:128::-;24702:3;24733:1;24729:6;24726:1;24723:13;24720:2;;;24739:18;;:::i;:::-;-1:-1:-1;24775:9:23;;24710:80::o;24795:217::-;24835:1;24861;24851:2;;-1:-1:-1;;;24886:31:23;;24940:4;24937:1;24930:15;24968:4;24893:1;24958:15;24851:2;-1:-1:-1;24997:9:23;;24841:171::o;25017:168::-;25057:7;25123:1;25119;25115:6;25111:14;25108:1;25105:21;25100:1;25093:9;25086:17;25082:45;25079:2;;;25130:18;;:::i;:::-;-1:-1:-1;25170:9:23;;25069:116::o;25190:125::-;25230:4;25258:1;25255;25252:8;25249:2;;;25263:18;;:::i;:::-;-1:-1:-1;25300:9:23;;25239:76::o;25320:258::-;25392:1;25402:113;25416:6;25413:1;25410:13;25402:113;;;25492:11;;;25486:18;25473:11;;;25466:39;25438:2;25431:10;25402:113;;;25533:6;25530:1;25527:13;25524:2;;;-1:-1:-1;;25568:1:23;25550:16;;25543:27;25373:205::o;25583:135::-;25622:3;-1:-1:-1;;25643:17:23;;25640:2;;;25663:18;;:::i;:::-;-1:-1:-1;25710:1:23;25699:13;;25630:88::o;25723:127::-;25784:10;25779:3;25775:20;25772:1;25765:31;25815:4;25812:1;25805:15;25839:4;25836:1;25829:15;25855:127;25916:10;25911:3;25907:20;25904:1;25897:31;25947:4;25944:1;25937:15;25971:4;25968:1;25961:15;25987:131;-1:-1:-1;;;;;26062:31:23;;26052:42;;26042:2;;26108:1;26105;26098:12;26042:2;26032:86;:::o;26123:118::-;26209:5;26202:13;26195:21;26188:5;26185:32;26175:2;;26231:1;26228;26221:12
Swarm Source
ipfs://19664c117108551aba1617224475ece786a6d4c8ff1daecc76c5520ddf873982
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.