My Name Tag:
Not Available, login to update
[ Download CSV Export ]
Latest 25 internal transaction
[ Download CSV Export ]
Contract Name:
Sushiswap_ZapOut_Polygon_V3
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. // ///@author Zapper ///@notice This contract removes liquidity from yEarn Vaults to ETH or ERC20 Tokens. // SPDX-License-Identifier: GPL-2.0 pragma solidity ^0.8.0; import "../_base/ZapOutBaseV3.sol"; interface IWETH { function withdraw(uint256 wad) external; } interface IYVault { function deposit(uint256) external; function withdraw(uint256) external; function getPricePerFullShare() external view returns (uint256); function token() external view returns (address); function decimals() external view returns (uint256); // V2 function pricePerShare() external view returns (uint256); function permit( address owner, address spender, uint256 amount, uint256 expiry, bytes calldata signature ) external returns (bool); function name() external pure returns (string memory); function nonces(address owner) external view returns (uint256); } interface IYVaultV1Registry { function getVaults() external view returns (address[] memory); function getVaultsLength() external view returns (uint256); } // -- Aave -- interface IAToken { function redeem(uint256 _amount) external; function underlyingAssetAddress() external returns (address); } contract yVault_ZapOut_V3_0_1 is ZapOutBaseV3 { using SafeERC20 for IERC20; IYVaultV1Registry V1Registry = IYVaultV1Registry(0x3eE41C098f9666ed2eA246f4D2558010e59d63A0); address private constant wethTokenAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; uint256 private constant deadline = 0xf000000000000000000000000000000000000000000000000000000000000000; uint256 private constant permitAllowance = 79228162514260000000000000000; event zapOut( address sender, address pool, address token, uint256 tokensRec ); constructor( address _curveZapOut, uint256 _goodwill, uint256 _affiliateSplit ) ZapBaseV2(_goodwill, _affiliateSplit) { // Curve ZapOut approvedTargets[_curveZapOut] = true; // 0x exchange approvedTargets[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] = true; } /** @notice Zap out in to a single token with permit @param fromVault Vault from which to remove liquidity @param amountIn Quantity of vault tokens to remove @param toToken Address of desired token @param isAaveUnderlying True if vault contains aave token @param minToTokens Minimum quantity of tokens to receive, reverts otherwise @param permitSig Encoded permit hash, which contains r,s,v values @param swapTarget Execution targets for swap or Zap @param swapData DEX or Zap data @param affiliate Affiliate address @param shouldSellEntireBalance If True transfers entrire allowable amount from another contract @return tokensReceived Quantity of tokens or ETH received */ function ZapOutWithPermit( address fromVault, uint256 amountIn, address toToken, bool isAaveUnderlying, uint256 minToTokens, bytes calldata permitSig, address swapTarget, bytes calldata swapData, address affiliate, bool shouldSellEntireBalance ) external returns (uint256 tokensReceived) { // permit _permit(fromVault, permitAllowance, permitSig); return ZapOut( fromVault, amountIn, toToken, isAaveUnderlying, minToTokens, swapTarget, swapData, affiliate, shouldSellEntireBalance ); } function _permit( address fromVault, uint256 amountIn, bytes memory permitSig ) internal { bool success = IYVault(fromVault).permit( msg.sender, address(this), amountIn, deadline, permitSig ); require(success, "Could Not Permit"); } /** @notice Zap out in to a single token with permit @param fromVault Vault from which to remove liquidity @param amountIn Quantity of vault tokens to remove @param toToken Address of desired token @param isAaveUnderlying True if vault contains aave token @param minToTokens Minimum quantity of tokens to receive, reverts otherwise @param swapTarget Execution targets for swap or Zap @param swapData DEX or Zap data @param affiliate Affiliate address @param shouldSellEntireBalance If True transfers entrire allowable amount from another contract @return tokensReceived Quantity of tokens or ETH received */ function ZapOut( address fromVault, uint256 amountIn, address toToken, bool isAaveUnderlying, uint256 minToTokens, address swapTarget, bytes memory swapData, address affiliate, bool shouldSellEntireBalance ) public stopInEmergency returns (uint256 tokensReceived) { _pullTokens(fromVault, amountIn, shouldSellEntireBalance); // get underlying token from vault address underlyingToken = IYVault(fromVault).token(); uint256 underlyingTokenReceived = _vaultWithdraw(fromVault, amountIn, underlyingToken); // swap to toToken uint256 toTokenAmt; if (isAaveUnderlying) { address underlyingAsset = IAToken(underlyingToken).underlyingAssetAddress(); // unwrap atoken IAToken(underlyingToken).redeem(underlyingTokenReceived); // aTokens are 1:1 if (underlyingAsset == toToken) { toTokenAmt = underlyingTokenReceived; } else { toTokenAmt = _fillQuote( underlyingAsset, toToken, underlyingTokenReceived, swapTarget, swapData ); } } else { toTokenAmt = _fillQuote( underlyingToken, toToken, underlyingTokenReceived, swapTarget, swapData ); } require(toTokenAmt >= minToTokens, "Err: High Slippage"); uint256 totalGoodwillPortion = _subtractGoodwill(toToken, toTokenAmt, affiliate, true); tokensReceived = toTokenAmt - totalGoodwillPortion; // send toTokens if (toToken == address(0)) { Address.sendValue(payable(msg.sender), tokensReceived); } else { IERC20(toToken).safeTransfer(msg.sender, tokensReceived); } emit zapOut(msg.sender, fromVault, toToken, tokensReceived); } function _vaultWithdraw( address fromVault, uint256 amount, address underlyingVaultToken ) internal returns (uint256 underlyingReceived) { uint256 iniUnderlyingBal = _getBalance(underlyingVaultToken); IYVault(fromVault).withdraw(amount); underlyingReceived = _getBalance(underlyingVaultToken) - iniUnderlyingBal; } function _fillQuote( address _fromTokenAddress, address toToken, uint256 _amount, address _swapTarget, bytes memory swapData ) internal returns (uint256 amtBought) { if (_fromTokenAddress == toToken) { return _amount; } 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 iniBal = _getBalance(toToken); require(approvedTargets[_swapTarget], "Target not Authorized"); (bool success, ) = _swapTarget.call{ value: valueToSend }(swapData); require(success, "Error Swapping Tokens 1"); uint256 finalBal = _getBalance(toToken); require(finalBal > 0, "ERR: Swapped to wrong token"); amtBought = finalBal - iniBal; } /** @notice Utility function to determine the quantity of underlying tokens removed from vault @param fromVault Yearn vault from which to remove liquidity @param liquidity Quantity of vault tokens to remove @return Quantity of underlying LP or token removed */ function removeLiquidityReturn(address fromVault, uint256 liquidity) external view returns (uint256) { IYVault vault = IYVault(fromVault); address[] memory V1Vaults = V1Registry.getVaults(); for (uint256 i = 0; i < V1Registry.getVaultsLength(); i++) { if (V1Vaults[i] == fromVault) return (liquidity * (vault.getPricePerFullShare())) / (10**18); } return (liquidity * (vault.pricePerShare())) / (10**vault.decimals()); } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // 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_V5 is ZapOutBaseV3 { using SafeERC20 for IERC20; uint256 private constant deadline = 0xf000000000000000000000000000000000000000000000000000000000000000; uint256 private constant permitAllowance = 79228162514260000000000000000; 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 permitSig Signature for permit @return amountA Quantity of tokenA received @return amountB Quantity of tokenB received */ function ZapOut2PairTokenWithPermit( address fromPoolAddress, uint256 incomingLP, address affiliate, bytes calldata permitSig ) external stopInEmergency returns (uint256 amountA, uint256 amountB) { _permit(fromPoolAddress, permitAllowance, permitSig); (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 permitSig Signature for permit @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 calldata permitSig, address[] memory swapTargets, bytes[] memory swapData, address affiliate ) public stopInEmergency returns (uint256) { // permit _permit(fromPoolAddress, permitAllowance, permitSig); return ( ZapOut( toTokenAddress, fromPoolAddress, incomingLP, minTokensRec, swapTargets, swapData, affiliate, false ) ); } function _permit( address fromPoolAddress, uint256 amountIn, bytes memory permitSig ) internal { require(permitSig.length == 65, "Invalid signature length"); bytes32 r; bytes32 s; uint8 v; assembly { r := mload(add(permitSig, 32)) s := mload(add(permitSig, 64)) v := byte(0, mload(add(permitSig, 96))) } IUniswapV2Pair(fromPoolAddress).permit( msg.sender, address(this), amountIn, deadline, v, r, s ); } 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_V4 is ZapOutBaseV3 { using SafeERC20 for IERC20; uint256 private constant deadline = 0xf000000000000000000000000000000000000000000000000000000000000000; uint256 private constant permitAllowance = 79228162514260000000000000000; 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 permitSig Signature for permit @return amountA Quantity of tokenA received @return amountB Quantity of tokenB received */ function ZapOut2PairTokenWithPermit( address fromPoolAddress, uint256 incomingLP, address affiliate, bytes calldata permitSig ) external stopInEmergency returns (uint256 amountA, uint256 amountB) { // permit _permit(fromPoolAddress, permitAllowance, permitSig); (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 calldata permitSig, address[] memory swapTargets, bytes[] memory swapData, address affiliate ) public stopInEmergency returns (uint256) { // permit _permit(fromPoolAddress, permitAllowance, permitSig); return ( ZapOut( toTokenAddress, fromPoolAddress, incomingLP, minTokensRec, swapTargets, swapData, affiliate, false ) ); } function _permit( address fromPoolAddress, uint256 amountIn, bytes memory permitSig ) internal { require(permitSig.length == 65, "Invalid signature length"); bytes32 r; bytes32 s; uint8 v; assembly { r := mload(add(permitSig, 32)) s := mload(add(permitSig, 64)) v := byte(0, mload(add(permitSig, 96))) } IUniswapV2Pair(fromPoolAddress).permit( msg.sender, address(this), amountIn, deadline, v, r, s ); } 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_V3 is ZapOutBaseV3 { using SafeERC20 for IERC20; uint256 private constant deadline = 0xf000000000000000000000000000000000000000000000000000000000000000; uint256 private constant permitAllowance = 79228162514260000000000000000; 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 permitSig Signature for permit @return amountA Quantity of tokenA received @return amountB Quantity of tokenB received */ function ZapOut2PairTokenWithPermit( address fromPoolAddress, uint256 incomingLP, address affiliate, bytes calldata permitSig ) external stopInEmergency returns (uint256 amountA, uint256 amountB) { // permit _permit(fromPoolAddress, permitAllowance, permitSig); (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 permitSig Signature for permit @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 calldata permitSig, address[] memory swapTargets, bytes[] memory swapData, address affiliate ) public stopInEmergency returns (uint256) { // permit _permit(fromPoolAddress, permitAllowance, permitSig); return ( ZapOut( toTokenAddress, fromPoolAddress, incomingLP, minTokensRec, swapTargets, swapData, affiliate, false ) ); } function _permit( address fromPoolAddress, uint256 amountIn, bytes memory permitSig ) internal { require(permitSig.length == 65, "Invalid signature length"); bytes32 r; bytes32 s; uint8 v; assembly { r := mload(add(permitSig, 32)) s := mload(add(permitSig, 64)) v := byte(0, mload(add(permitSig, 96))) } IUniswapV2Pair(fromPoolAddress).permit( msg.sender, address(this), amountIn, deadline, v, r, s ); } 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; } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // 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 Quickswap 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 Quickswap_ZapOut_V1 is ZapOutBaseV3 { using SafeERC20 for IERC20; uint256 private constant deadline = 0xf000000000000000000000000000000000000000000000000000000000000000; IUniswapV2Router02 private constant quickswapRouter = IUniswapV2Router02(0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff); IUniswapV2Factory private constant quickswapFactory = IUniswapV2Factory(0x5757371414417b8C6CAad45bAeF941aBc7d3Ab32); 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(quickswapRouter), incomingLP); if (token0 == wmaticTokenAddress || token1 == wmaticTokenAddress) { address _token = token0 == wmaticTokenAddress ? token1 : token0; (amountA, amountB) = quickswapRouter.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) = quickswapRouter.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 = quickswapFactory.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(quickswapRouter), incomingLP); (amount0, amount1) = quickswapRouter.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; } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // 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 Pancakeswap pools on BSC, receiving ETH, tokens 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 Pancakeswap_ZapOut_V2_1 is ZapOutBaseV3 { using SafeERC20 for IERC20; uint256 private constant deadline = 0xf000000000000000000000000000000000000000000000000000000000000000; IUniswapV2Router02 private constant pancakeswapRouter = IUniswapV2Router02(0x10ED43C718714eb63d5aA57B78B54704E256024E); IUniswapV2Factory private constant pancakeswapFactoryAddress = IUniswapV2Factory(0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73); address private constant wbnbTokenAddress = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c; 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(pancakeswapRouter), incomingLP); if (token0 == wbnbTokenAddress || token1 == wbnbTokenAddress) { address _token = token0 == wbnbTokenAddress ? token1 : token0; (amountA, amountB) = pancakeswapRouter.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) = pancakeswapRouter.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 = pancakeswapFactoryAddress.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(pancakeswapRouter), incomingLP); (amount0, amount1) = pancakeswapRouter.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 == wbnbTokenAddress && toToken == address(0)) { IWETH(wbnbTokenAddress).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 Yearn Vaults using ETH or ERC20 Tokens. // SPDX-License-Identifier: GPL-2.0 pragma solidity ^0.8.0; import "../_base/ZapInBaseV3.sol"; interface IWETH { function deposit() external payable; function transfer(address to, uint256 value) external returns (bool); function withdraw(uint256) external; } interface IYVault { function deposit(uint256) external; function withdraw(uint256) external; function getPricePerFullShare() external view returns (uint256); function token() external view returns (address); // V2 function pricePerShare() external view returns (uint256); } // -- Aave -- interface IAaveLendingPoolAddressesProvider { function getLendingPool() external view returns (address); function getLendingPoolCore() external view returns (address payable); } interface IAaveLendingPoolCore { function getReserveATokenAddress(address _reserve) external view returns (address); } interface IAaveLendingPool { function deposit( address _reserve, uint256 _amount, uint16 _referralCode ) external payable; } contract yVault_ZapIn_V4 is ZapInBaseV3 { using SafeERC20 for IERC20; IAaveLendingPoolAddressesProvider private constant lendingPoolAddressProvider = IAaveLendingPoolAddressesProvider( 0x24a42fD28C976A61Df5D00D0599C34c4f90748c8 ); address private constant wethTokenAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; event zapIn(address sender, address pool, uint256 tokensRec); constructor( address _curveZapIn, uint256 _goodwill, uint256 _affiliateSplit ) ZapBaseV2(_goodwill, _affiliateSplit) { // Curve ZapIn approvedTargets[_curveZapIn] = true; // 0x exchange approvedTargets[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] = true; } /** @notice This function adds liquidity to a Yearn vaults with ETH or ERC20 tokens @param fromToken The token used for entry (address(0) if ether) @param amountIn The amount of fromToken to invest @param toVault Yearn vault address @param superVault Super vault to depoist toVault tokens into (address(0) if none) @param isAaveUnderlying True if vault contains aave token @param minYVTokens The minimum acceptable quantity vault tokens to receive. Reverts otherwise @param intermediateToken Token to swap fromToken to before entering vault @param swapTarget Excecution target for the swap or Zap @param swapData DEX quote or Zap data @param affiliate Affiliate address @param shouldSellEntireBalance If True transfers entrire allowable amount from another contract @return tokensReceived Quantity of Vault tokens received */ function ZapIn( address fromToken, uint256 amountIn, address toVault, address superVault, bool isAaveUnderlying, uint256 minYVTokens, address intermediateToken, address swapTarget, bytes calldata swapData, address affiliate, bool shouldSellEntireBalance ) external payable stopInEmergency returns (uint256 tokensReceived) { // get incoming tokens uint256 toInvest = _pullTokens( fromToken, amountIn, affiliate, true, shouldSellEntireBalance ); // get intermediate token uint256 intermediateAmt = _fillQuote( fromToken, intermediateToken, toInvest, swapTarget, swapData ); // get 'aIntermediateToken' if (isAaveUnderlying) { address aaveLendingPoolCore = lendingPoolAddressProvider.getLendingPoolCore(); _approveToken(intermediateToken, aaveLendingPoolCore); IAaveLendingPool(lendingPoolAddressProvider.getLendingPool()) .deposit(intermediateToken, intermediateAmt, 0); intermediateToken = IAaveLendingPoolCore(aaveLendingPoolCore) .getReserveATokenAddress(intermediateToken); } return _zapIn( toVault, superVault, minYVTokens, intermediateToken, intermediateAmt ); } function _zapIn( address toVault, address superVault, uint256 minYVTokens, address intermediateToken, uint256 intermediateAmt ) internal returns (uint256 tokensReceived) { // Deposit to Vault if (superVault == address(0)) { tokensReceived = _vaultDeposit( intermediateToken, intermediateAmt, toVault, minYVTokens, true ); } else { uint256 intermediateYVTokens = _vaultDeposit( intermediateToken, intermediateAmt, toVault, 0, false ); // deposit to super vault tokensReceived = _vaultDeposit( IYVault(superVault).token(), intermediateYVTokens, superVault, minYVTokens, true ); } } function _vaultDeposit( address underlyingVaultToken, uint256 amount, address toVault, uint256 minTokensRec, bool shouldTransfer ) internal returns (uint256 tokensReceived) { _approveToken(underlyingVaultToken, toVault); uint256 iniYVaultBal = IERC20(toVault).balanceOf(address(this)); IYVault(toVault).deposit(amount); tokensReceived = IERC20(toVault).balanceOf(address(this)) - iniYVaultBal; require(tokensReceived >= minTokensRec, "Err: High Slippage"); if (shouldTransfer) { IERC20(toVault).safeTransfer(msg.sender, tokensReceived); emit zapIn(msg.sender, toVault, tokensReceived); } } function _fillQuote( address _fromTokenAddress, address toToken, uint256 _amount, address _swapTarget, bytes memory swapData ) internal returns (uint256 amtBought) { if (_fromTokenAddress == toToken) { return _amount; } if (_fromTokenAddress == address(0) && toToken == wethTokenAddress) { IWETH(wethTokenAddress).deposit{ value: _amount }(); return _amount; } uint256 valueToSend; if (_fromTokenAddress == address(0)) { valueToSend = _amount; } else { _approveToken(_fromTokenAddress, _swapTarget); } uint256 iniBal = _getBalance(toToken); require(approvedTargets[_swapTarget], "Target not Authorized"); (bool success, ) = _swapTarget.call{ value: valueToSend }(swapData); require(success, "Error Swapping Tokens 1"); uint256 finalBal = _getBalance(toToken); amtBought = finalBal - iniBal; } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // 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 enters Pool Together Prize 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 IPoolTogether { function depositTo( address to, uint256 amount, address controlledToken, address referrer ) external; function tokens() external returns (address[] memory); function token() external returns (address); } contract PoolTogether_ZapIn_V2 is ZapInBaseV3 { using SafeERC20 for IERC20; address private constant wethTokenAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address private constant zGoodwillAddress = 0x3CE37278de6388532C3949ce4e886F365B14fB56; constructor(uint256 _goodwill, uint256 _affiliateSplit) ZapBaseV2(_goodwill, _affiliateSplit) { // 0x exchange approvedTargets[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] = true; } event zapIn(address sender, address pool, uint256 tokensRec); /** @notice This function adds liquidity to a PoolTogether prize pool with ETH or ERC20 tokens @param fromToken The token used for entry (address(0) if ether) @param toToken The intermediate ERC20 token to swap to @param prizePool Prize pool to enter @param amountIn The quantity of fromToken to invest @param minTickets The minimum acceptable quantity of tickets to acquire. Reverts otherwise @param swapTarget Excecution target for swap @param swapData DEX quote data @param affiliate Affiliate address @param shouldSellEntireBalance If True transfers entrire allowable amount from another contract */ function ZapIn( address fromToken, address toToken, address prizePool, uint256 amountIn, uint256 minTickets, address swapTarget, bytes calldata swapData, address affiliate, bool shouldSellEntireBalance ) external payable stopInEmergency { uint256 toInvest = _pullTokens( fromToken, amountIn, affiliate, true, shouldSellEntireBalance ); IPoolTogether _prizePool = IPoolTogether(prizePool); if (_prizePool.token() == fromToken) { _enterPrizePool(_prizePool, toInvest, minTickets); } else { uint256 tokensBought = _fillQuote(fromToken, toToken, toInvest, swapTarget, swapData); _enterPrizePool(_prizePool, tokensBought, minTickets); } } function _enterPrizePool( IPoolTogether prizePool, uint256 amount, uint256 minTickets ) internal { address poolToken = prizePool.token(); address ticket = prizePool.tokens()[1]; _approveToken(poolToken, address(prizePool)); uint256 iniTicketBal = _getBalance(ticket); prizePool.depositTo(address(this), amount, ticket, zGoodwillAddress); uint256 ticketsRec = _getBalance(ticket) - iniTicketBal; require(ticketsRec >= minTickets, "High Slippage"); IERC20(ticket).safeTransfer(msg.sender, ticketsRec); emit zapIn(msg.sender, address(prizePool), amount); } function _fillQuote( address fromToken, address toToken, uint256 _amount, address swapTarget, bytes memory swapData ) internal returns (uint256 amountBought) { if (fromToken == toToken) { return _amount; } if (fromToken == address(0) && toToken == wethTokenAddress) { IWETH(wethTokenAddress).deposit{ value: _amount }(); return _amount; } uint256 valueToSend; if (fromToken == address(0)) { valueToSend = _amount; } else { _approveToken(fromToken, swapTarget); } uint256 initialBalance = _getBalance(toToken); require(approvedTargets[swapTarget], "Target not Authorized"); (bool success, ) = swapTarget.call{ value: valueToSend }(swapData); require(success, "Error Swapping Tokens"); amountBought = _getBalance(toToken) - initialBalance; require(amountBought > 0, "Swapped To Invalid Intermediate"); } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // 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 Quickswap pools on Polygon (Matic) using ETH or any ERC20 Tokens. // 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 Quickswap_ZapIn_V2 is ZapInBaseV3 { using SafeERC20 for IERC20; IUniswapV2Factory private constant quickswapFactory = IUniswapV2Factory(0x5757371414417b8C6CAad45bAeF941aBc7d3Ab32); IUniswapV2Router02 private constant quickswapRouter = IUniswapV2Router02(0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff); 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 Quickswap pools with ETH/ERC20 Tokens @param _FromTokenContractAddress The ERC20 token used (address(0x00) if ether) @param _pairAddress The Quickswap 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(quickswapRouter), token0Bought); _approveToken(_ToUnipoolToken1, address(quickswapRouter), token1Bought); (uint256 amountA, uint256 amountB, uint256 LP) = quickswapRouter.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( quickswapFactory.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(quickswapRouter), tokens2Trade ); address pair = quickswapFactory.getPair( _FromTokenContractAddress, _ToTokenContractAddress ); require(pair != address(0), "No Swap Available"); address[] memory path = new address[](2); path[0] = _FromTokenContractAddress; path[1] = _ToTokenContractAddress; tokenBought = quickswapRouter.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 Mushroom Vaults using ETH or ERC20 Tokens. // SPDX-License-Identifier: GPL-2.0 pragma solidity ^0.8.0; import "../_base/ZapInBaseV3.sol"; interface IWETH { function deposit() external payable; } interface IMVault { function deposit(uint256) external; function token() external view returns (address); } contract Mushroom_ZapIn_V2 is ZapInBaseV3 { using SafeERC20 for IERC20; address private constant wethTokenAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; constructor( address _curveZapIn, address _uniZapIn, uint256 _goodwill, uint256 _affiliateSplit ) ZapBaseV2(_goodwill, _affiliateSplit) { // 0x exchange approvedTargets[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] = true; // Curve ZapIn approvedTargets[_curveZapIn] = true; // Uniswap ZapIn approvedTargets[_uniZapIn] = true; } event zapIn(address sender, address pool, uint256 tokensRec); /** @notice This function adds liquidity to Mushroom vaults with ETH or ERC20 tokens @param fromToken The token used for entry (address(0) if ether) @param amountIn The amount of fromToken to invest @param toVault Harvest vault address @param minMVTokens The minimum acceptable quantity vault tokens to receive. Reverts otherwise @param intermediateToken Token to swap fromToken to before entering vault @param swapTarget Excecution target for the swap or zap @param swapData DEX or Zap data @param affiliate Affiliate address @param shouldSellEntireBalance True if amountIn is determined at execution time (i.e. contract is caller) @return tokensReceived Quantity of Vault tokens received */ function ZapIn( address fromToken, uint256 amountIn, address toVault, uint256 minMVTokens, address intermediateToken, address swapTarget, bytes calldata swapData, address affiliate, bool shouldSellEntireBalance ) external payable stopInEmergency returns (uint256 tokensReceived) { // get incoming tokens uint256 toInvest = _pullTokens( fromToken, amountIn, affiliate, true, shouldSellEntireBalance ); // get intermediate token uint256 intermediateAmt = _fillQuote( fromToken, intermediateToken, toInvest, swapTarget, swapData ); // Deposit to Vault tokensReceived = _vaultDeposit(intermediateAmt, toVault, minMVTokens); } function _vaultDeposit( uint256 amount, address toVault, uint256 minTokensRec ) internal returns (uint256 tokensReceived) { address underlyingVaultToken = IMVault(toVault).token(); _approveToken(underlyingVaultToken, toVault); uint256 iniVaultBal = IERC20(toVault).balanceOf(address(this)); IMVault(toVault).deposit(amount); tokensReceived = IERC20(toVault).balanceOf(address(this)) - iniVaultBal; require(tokensReceived >= minTokensRec, "High Slippage"); IERC20(toVault).safeTransfer(msg.sender, tokensReceived); emit zapIn(msg.sender, toVault, tokensReceived); } function _fillQuote( address _fromTokenAddress, address toToken, uint256 _amount, address _swapTarget, bytes memory swapData ) internal returns (uint256 amtBought) { if (_fromTokenAddress == toToken) { return _amount; } if (_fromTokenAddress == address(0) && toToken == wethTokenAddress) { IWETH(wethTokenAddress).deposit{ value: _amount }(); return _amount; } uint256 valueToSend; if (_fromTokenAddress == address(0)) { valueToSend = _amount; } else { _approveToken(_fromTokenAddress, _swapTarget); } uint256 iniBal = _getBalance(toToken); require(approvedTargets[_swapTarget], "Target not Authorized"); (bool success, ) = _swapTarget.call{ value: valueToSend }(swapData); require(success, "Error Swapping Tokens 1"); uint256 finalBal = _getBalance(toToken); amtBought = finalBal - iniBal; } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // 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 deposits ETH or ERC20 tokens into Harvest Vaults // SPDX-License-Identifier: GPL-2.0 pragma solidity ^0.8.0; import "../_base/ZapInBaseV3.sol"; interface IWETH { function deposit() external payable; } // -- Harvest -- interface IHVault { function underlying() external view returns (address); function deposit(uint256 amountWei) external; } contract Harvest_ZapIn_V3 is ZapInBaseV3 { using SafeERC20 for IERC20; address private constant wethTokenAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; event zapIn(address sender, address pool, uint256 tokensRec); constructor( address _curveZapIn, address _uniZapIn, address _sushiZapIn, uint256 _goodwill, uint256 _affiliateSplit ) ZapBaseV2(_goodwill, _affiliateSplit) { // 0x exchange approvedTargets[0xDef1C0ded9bec7F1a1670819833240f027b25EfF] = true; approvedTargets[_curveZapIn] = true; approvedTargets[_uniZapIn] = true; approvedTargets[_sushiZapIn] = true; } /** @notice This function adds liquidity to harvest vaults with ETH or ERC20 tokens @param fromToken The token used for entry (address(0) if ether) @param amountIn The amount of fromToken to invest @param vault Harvest vault address @param minVaultTokens The minimum acceptable quantity vault tokens to receive. Reverts otherwise @param intermediateToken Token to swap fromToken to before entering vault @param swapTarget Excecution target for the swap or zap @param swapData DEX or Zap data @param affiliate Affiliate address @param shouldSellEntireBalance True if amountIn is determined at execution time (i.e. contract is caller) @return tokensReceived Quantity of Vault tokens received */ function ZapIn( address fromToken, uint256 amountIn, address vault, uint256 minVaultTokens, address intermediateToken, address swapTarget, bytes calldata swapData, address affiliate, bool shouldSellEntireBalance ) external payable stopInEmergency returns (uint256 tokensReceived) { // get incoming tokens uint256 toInvest = _pullTokens( fromToken, amountIn, affiliate, true, shouldSellEntireBalance ); // get intermediate token uint256 intermediateAmt = _fillQuote( fromToken, intermediateToken, toInvest, swapTarget, swapData ); // Deposit to Vault tokensReceived = _vaultDeposit(intermediateAmt, vault, minVaultTokens); } function _vaultDeposit( uint256 amount, address toVault, uint256 minTokensRec ) internal returns (uint256 tokensReceived) { address underlyingVaultToken = IHVault(toVault).underlying(); _approveToken(underlyingVaultToken, toVault); uint256 iniYVaultBal = IERC20(toVault).balanceOf(address(this)); IHVault(toVault).deposit(amount); tokensReceived = IERC20(toVault).balanceOf(address(this)) - iniYVaultBal; require(tokensReceived >= minTokensRec, "High Slippage"); IERC20(toVault).safeTransfer(msg.sender, tokensReceived); emit zapIn(msg.sender, toVault, tokensReceived); } function _fillQuote( address _fromTokenAddress, address toToken, uint256 _amount, address _swapTarget, bytes memory swapData ) internal returns (uint256 amtBought) { if (_fromTokenAddress == toToken) { return _amount; } if (_fromTokenAddress == address(0) && toToken == wethTokenAddress) { IWETH(wethTokenAddress).deposit{ value: _amount }(); return _amount; } uint256 valueToSend; if (_fromTokenAddress == address(0)) { valueToSend = _amount; } else { _approveToken(_fromTokenAddress, _swapTarget); } uint256 iniBal = _getBalance(toToken); require(approvedTargets[_swapTarget], "Target not Authorized"); (bool success, ) = _swapTarget.call{ value: valueToSend }(swapData); require(success, "Error Swapping Tokens 1"); uint256 finalBal = _getBalance(toToken); amtBought = finalBal - iniBal; } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // 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; } }
// ███████╗░█████╗░██████╗░██████╗░███████╗██████╗░░░░███████╗██╗ // ╚════██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗░░░██╔════╝██║ // ░░███╔═╝███████║██████╔╝██████╔╝█████╗░░██████╔╝░░░█████╗░░██║ // ██╔══╝░░██╔══██║██╔═══╝░██╔═══╝░██╔══╝░░██╔══██╗░░░██╔══╝░░██║ // ███████╗██║░░██║██║░░░░░██║░░░░░███████╗██║░░██║██╗██║░░░░░██║ // ╚══════╝╚═╝░░╚═╝╚═╝░░░░░╚═╝░░░░░╚══════╝╚═╝░░╚═╝╚═╝╚═╝░░░░░╚═╝ // 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 Pancakeswap (BSC) pools using ETH or any 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 Pancakeswap_ZapIn_V3_1 is ZapInBaseV3 { using SafeERC20 for IERC20; IUniswapV2Factory private constant pancakeswapFactoryAddress = IUniswapV2Factory(0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73); IUniswapV2Router02 private constant pancakeswapRouter = IUniswapV2Router02(0x10ED43C718714eb63d5aA57B78B54704E256024E); address private constant wbnbTokenAddress = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c; 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 Pancakeswap pools with ETH/ERC20 Tokens @param _FromTokenContractAddress The ERC20 token used (address(0x00) if ether) @param _pairAddress The Pancakeswap 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(pancakeswapRouter), token0Bought ); _approveToken( _ToUnipoolToken1, address(pancakeswapRouter), token1Bought ); (uint256 amountA, uint256 amountB, uint256 LP) = pancakeswapRouter.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 == wbnbTokenAddress) { IWETH(wbnbTokenAddress).deposit{ value: _amount }(); return (_amount, wbnbTokenAddress); } 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( pancakeswapFactoryAddress.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(pancakeswapRouter), tokens2Trade ); address pair = pancakeswapFactoryAddress.getPair( _FromTokenContractAddress, _ToTokenContractAddress ); require(pair != address(0), "No Swap Available"); address[] memory path = new address[](2); path[0] = _FromTokenContractAddress; path[1] = _ToTokenContractAddress; tokenBought = pancakeswapRouter.swapExactTokensForTokens( tokens2Trade, 1, path, address(this), deadline )[path.length - 1]; require(tokenBought > 0, "Error Swapping Tokens 2"); } }
// 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":"permitSig","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":"permitSig","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
60806040526000805460ff60a01b191690553480156200001e57600080fd5b5060405162003271380380620032718339810160408190526200004191620000e0565b600080546001600160a01b03191633908117825560405184928492918291907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350600291909155600355505073def1c0ded9bec7f1a1670819833240f027b25eff60005260076020527ff6019cd1944dc466e824190b288e5a63528dd4c9a6d8cbd707956fd30d2f1e0d805460ff1916600117905562000104565b60008060408385031215620000f3578182fd5b505080516020909101519092909150565b61315d80620001146000396000f3fe6080604052600436106101445760003560e01c8063715018a6116100b65780639779d1a61161006f5780639779d1a614610435578063cfd7789c14610465578063d408f6571461049a578063f21d3ab5146104ca578063f2fde38b146104ea578063fbec27bf1461050a57600080fd5b8063715018a61461034857806375f12b211461035d5780637ee992831461037e5780638da5cb5b146103cd57806391027c5b146103f55780639735a6341461041557600080fd5b8063247482ba11610108578063247482ba146102725780633ff428c7146102925780634f51e294146102b2578063550bfa56146102f25780635de0398e146103125780635ecb16cd1461032857600080fd5b806301e980d4146101a55780630dc9de85146101c55780631385d24c146101e55780631781261f146101fa57806318b135e31461024557600080fd5b366101a0573332141561019e5760405162461bcd60e51b815260206004820152601860248201527f446f206e6f742073656e6420455448206469726563746c79000000000000000060448201526064015b60405180910390fd5b005b600080fd5b3480156101b157600080fd5b5061019e6101c0366004612e5e565b61052a565b3480156101d157600080fd5b5061019e6101e0366004612d7d565b6105b4565b3480156101f157600080fd5b5061019e61080f565b34801561020657600080fd5b50610232610215366004612aab565b600560209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b34801561025157600080fd5b50610232610260366004612a73565b60066020526000908152604090205481565b34801561027e57600080fd5b5061023261028d366004612ae3565b61085a565b34801561029e57600080fd5b5061019e6102ad366004612c73565b6109dc565b3480156102be57600080fd5b506102e26102cd366004612a73565b60046020526000908152604090205460ff1681565b604051901515815260200161023c565b3480156102fe57600080fd5b5061019e61030d366004612e5e565b610a31565b34801561031e57600080fd5b5061023260025481565b34801561033457600080fd5b5061019e610343366004612d7d565b610ab1565b34801561035457600080fd5b5061019e610d22565b34801561036957600080fd5b506000546102e290600160a01b900460ff1681565b34801561038a57600080fd5b5061039e610399366004612ca0565b610d96565b6040805194855260208501939093526001600160a01b039182169284019290925216606082015260800161023c565b3480156103d957600080fd5b506000546040516001600160a01b03909116815260200161023c565b34801561040157600080fd5b50610232610410366004612ba4565b611035565b34801561042157600080fd5b5061019e610430366004612dbd565b6110cc565b34801561044157600080fd5b506102e2610450366004612a73565b60076020526000908152604090205460ff1681565b34801561047157600080fd5b50610485610480366004612d0c565b6111f6565b6040805192835260208301919091520161023c565b3480156104a657600080fd5b506102e26104b5366004612a73565b60016020526000908152604090205460ff1681565b3480156104d657600080fd5b506104856104e5366004612ccb565b611289565b3480156104f657600080fd5b5061019e610505366004612a73565b611742565b34801561051657600080fd5b5061019e610525366004612c73565b61182c565b6000546001600160a01b031633146105545760405162461bcd60e51b815260040161019590612f96565b60648111156105af5760405162461bcd60e51b815260206004820152602160248201527f416666696c696174652053706c69742056616c7565206e6f7420616c6c6f77656044820152601960fa1b6064820152608401610195565b600355565b6000805b8281101561080957336000908152600560205260408120908585848181106105f057634e487b7160e01b600052603260045260246000fd5b90506020020160208101906106059190612a73565b6001600160a01b0316815260208082019290925260409081016000908120543382526005909352908120919350908186868581811061065457634e487b7160e01b600052603260045260246000fd5b90506020020160208101906106699190612a73565b6001600160a01b03166001600160a01b031681526020019081526020016000208190555081600660008686858181106106b257634e487b7160e01b600052603260045260246000fd5b90506020020160208101906106c79190612a73565b6001600160a01b03166001600160a01b03168152602001908152602001600020546106f29190613077565b6006600086868581811061071657634e487b7160e01b600052603260045260246000fd5b905060200201602081019061072b9190612a73565b6001600160a01b0316815260208101919091526040016000205573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee84848381811061077a57634e487b7160e01b600052603260045260246000fd5b905060200201602081019061078f9190612a73565b6001600160a01b031614156107ad576107a83383611881565b6107f7565b6107f733838686858181106107d257634e487b7160e01b600052603260045260246000fd5b90506020020160208101906107e79190612a73565b6001600160a01b0316919061199a565b80610801816130ba565b9150506105b8565b50505050565b6000546001600160a01b031633146108395760405162461bcd60e51b815260040161019590612f96565b6000805460ff60a01b198116600160a01b9182900460ff1615909102179055565b60008054600160a01b900460ff16156108855760405162461bcd60e51b815260040161019590612f6a565b6000806108938a8a866119fd565b915091506108a58a83838e8b8b611c70565b9250878310156108e75760405162461bcd60e51b815260206004820152600d60248201526c4869676820536c69707061676560981b6044820152606401610195565b60006001600160a01b038c166109565761091873eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee85886001611e84565b9050336108fc6109288387613077565b6040518115909202916000818181858888f19350505050158015610950573d6000803e3d6000fd5b50610984565b6109638c85886001611e84565b9050610984336109738387613077565b6001600160a01b038f16919061199a565b61098e8185613077565b93507ff2d3e32195f8631c70e1d996c9bd5d4a3369d0580786dcd662bf13139310355d338c8e876040516109c59493929190612ecd565b60405180910390a150505098975050505050505050565b6000546001600160a01b03163314610a065760405162461bcd60e51b815260040161019590612f96565b6001600160a01b03919091166000908152600460205260409020805460ff1916911515919091179055565b6000546001600160a01b03163314610a5b5760405162461bcd60e51b815260040161019590612f96565b6064811115610aac5760405162461bcd60e51b815260206004820152601a60248201527f476f6f6457696c6c2056616c7565206e6f7420616c6c6f7765640000000000006044820152606401610195565b600255565b6000546001600160a01b03163314610adb5760405162461bcd60e51b815260040161019590612f96565b60005b81811015610d1d57600073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee848484818110610b1d57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610b329190612a73565b6001600160a01b03161415610bc05760066000858585818110610b6557634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610b7a9190612a73565b6001600160a01b03168152602081019190915260400160002054610b9e9047613077565b9050610bbb610bb56000546001600160a01b031690565b82611881565b610d0a565b60066000858585818110610be457634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610bf99190612a73565b6001600160a01b03166001600160a01b0316815260200190815260200160002054848484818110610c3a57634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610c4f9190612a73565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a082319060240160206040518083038186803b158015610c9057600080fd5b505afa158015610ca4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc89190612e76565b610cd29190613077565b9050610d0a610ce96000546001600160a01b031690565b828686868181106107d257634e487b7160e01b600052603260045260246000fd5b5080610d15816130ba565b915050610ade565b505050565b6000546001600160a01b03163314610d4c5760405162461bcd60e51b815260040161019590612f96565b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000806000806000869050806001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b158015610dda57600080fd5b505afa158015610dee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e129190612a8f565b9250806001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b158015610e4d57600080fd5b505afa158015610e61573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e859190612a8f565b6040516370a0823160e01b81526001600160a01b0389811660048301529193506000918516906370a082319060240160206040518083038186803b158015610ecc57600080fd5b505afa158015610ee0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f049190612e76565b6040516370a0823160e01b81526001600160a01b038a811660048301529192506000918516906370a082319060240160206040518083038186803b158015610f4b57600080fd5b505afa158015610f5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f839190612e76565b90506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610fc057600080fd5b505afa158015610fd4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff89190612e76565b905080611005848b613058565b61100f9190613038565b97508061101c838b613058565b6110269190613038565b96505050505092959194509250565b60008054600160a01b900460ff16156110605760405162461bcd60e51b815260040161019590612f6a565b6110ad896bfffffffffff096fb4da2000088888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611faf92505050565b6110be8a8a8a8a888888600061085a565b9a9950505050505050505050565b6000546001600160a01b031633146110f65760405162461bcd60e51b815260040161019590612f96565b82811461113c5760405162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c84092dce0eae840d8cadccee8d60631b6044820152606401610195565b60005b838110156111ef5782828281811061116757634e487b7160e01b600052603260045260246000fd5b905060200201602081019061117c9190612e26565b600760008787858181106111a057634e487b7160e01b600052603260045260246000fd5b90506020020160208101906111b59190612a73565b6001600160a01b031681526020810191909152604001600020805460ff1916911515919091179055806111e7816130ba565b91505061113f565b5050505050565b600080548190600160a01b900460ff16156112235760405162461bcd60e51b815260040161019590612f6a565b611270876bfffffffffff096fb4da2000086868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611faf92505050565b61127b878787611289565b909890975095505050505050565b600080548190600160a01b900460ff16156112b65760405162461bcd60e51b815260040161019590612f6a565b846001600160a01b03811661130d5760405162461bcd60e51b815260206004820152601b60248201527f506f6f6c2043616e6e6f74206265205a65726f204164647265737300000000006044820152606401610195565b6000816001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b15801561134857600080fd5b505afa15801561135c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113809190612a8f565b90506000826001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b1580156113bd57600080fd5b505afa1580156113d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113f59190612a8f565b905061140c6001600160a01b03891633308a6120a4565b61142b88731b02da8cb0d097eb8d57a175b88c7d8b47997506896120dc565b6001600160a01b038216730d500b1d8e8ef31e21c99d1db9a6444d3adf1270148061147257506001600160a01b038116730d500b1d8e8ef31e21c99d1db9a6444d3adf1270145b156115cd5760006001600160a01b038316730d500b1d8e8ef31e21c99d1db9a6444d3adf1270146114a357826114a5565b815b604051629d473b60e21b81526001600160a01b0382166004820152602481018a90526001604482018190526064820152306084820152600f60fc1b60a4820152909150731b02da8cb0d097eb8d57a175b88c7d8b47997506906302751cec9060c4016040805180830381600087803b15801561152057600080fd5b505af1158015611534573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115589190612e8e565b9096509450600061156c82888a6001611e84565b9050600061159173eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee888b6001611e84565b90506115b2336115a1848b613077565b6001600160a01b038616919061199a565b6115c5336115c0838a613077565b611881565b5050506116bd565b604051635d5155ef60e11b8152731b02da8cb0d097eb8d57a175b88c7d8b479975069063baa2abde9061161590859085908c9060019081903090600f60fc1b90600401612ef7565b6040805180830381600087803b15801561162e57600080fd5b505af1158015611642573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116669190612e8e565b9095509350600061167a8387896001611e84565b9050600061168b83878a6001611e84565b90506116ac3361169b848a613077565b6001600160a01b038716919061199a565b6116ba336115a18389613077565b50505b7ff2d3e32195f8631c70e1d996c9bd5d4a3369d0580786dcd662bf13139310355d338984886040516116f29493929190612ecd565b60405180910390a17ff2d3e32195f8631c70e1d996c9bd5d4a3369d0580786dcd662bf13139310355d3389838760405161172f9493929190612ecd565b60405180910390a1505050935093915050565b6000546001600160a01b0316331461176c5760405162461bcd60e51b815260040161019590612f96565b6001600160a01b0381166117d15760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610195565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146118565760405162461bcd60e51b815260040161019590612f96565b6001600160a01b03919091166000908152600160205260409020805460ff1916911515919091179055565b804710156118d15760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e63650000006044820152606401610195565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461191e576040519150601f19603f3d011682016040523d82523d6000602084013e611923565b606091505b5050905080610d1d5760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d617920686176652072657665727465640000000000006064820152608401610195565b6040516001600160a01b038316602482015260448101829052610d1d90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612105565b600080846001600160a01b038116611a575760405162461bcd60e51b815260206004820152601b60248201527f506f6f6c2043616e6e6f74206265205a65726f204164647265737300000000006044820152606401610195565b6000816001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b158015611a9257600080fd5b505afa158015611aa6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aca9190612a8f565b90506000826001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b158015611b0757600080fd5b505afa158015611b1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3f9190612a8f565b9050611b4c8888886121d7565b50611b6c88731b02da8cb0d097eb8d57a175b88c7d8b47997506896120dc565b604051635d5155ef60e11b8152731b02da8cb0d097eb8d57a175b88c7d8b479975069063baa2abde90611bb490859085908c9060019081903090600f60fc1b90600401612ef7565b6040805180830381600087803b158015611bcd57600080fd5b505af1158015611be1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c059190612e8e565b90955093508415801590611c195750600084115b611c655760405162461bcd60e51b815260206004820152601e60248201527f52656d6f76656420496e73756666696369656e74204c697175696469747900006044820152606401610195565b505050935093915050565b600080876001600160a01b0316630dfe16816040518163ffffffff1660e01b815260040160206040518083038186803b158015611cac57600080fd5b505afa158015611cc0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ce49190612a8f565b90506000886001600160a01b031663d21220a76040518163ffffffff1660e01b815260040160206040518083038186803b158015611d2157600080fd5b505afa158015611d35573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d599190612a8f565b9050856001600160a01b0316826001600160a01b03161415611d8657611d7f8884613020565b9250611df0565b611de382878a88600081518110611dad57634e487b7160e01b600052603260045260246000fd5b602002602001015188600081518110611dd657634e487b7160e01b600052603260045260246000fd5b60200260200101516122ff565b611ded9084613020565b92505b856001600160a01b0316816001600160a01b03161415611e1b57611e148784613020565b9250611e78565b611e6b81878988600181518110611e4257634e487b7160e01b600052603260045260246000fd5b602002602001015188600181518110611dd657634e487b7160e01b600052603260045260246000fd5b611e759084613020565b92505b50509695505050505050565b3360009081526001602052604081205460ff16828015611ea2575080155b8015611eb057506000600254115b15611fa65761271060025486611ec69190613058565b611ed09190613038565b6001600160a01b03851660009081526004602052604090205490925060ff1615611fa6576001600160a01b038616611f1a5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee95505b6000606460035484611f2c9190613058565b611f369190613038565b6001600160a01b038087166000908152600560209081526040808320938c16835292905290812080549293508392909190611f72908490613020565b90915550506001600160a01b03871660009081526006602052604081208054839290611f9f908490613020565b9091555050505b50949350505050565b80516041146120005760405162461bcd60e51b815260206004820152601860248201527f496e76616c6964207369676e6174757265206c656e67746800000000000000006044820152606401610195565b60208101516040808301516060840151915163d505accf60e01b815233600482015230602482015260448101869052600f60fc1b606482015260009290921a6084830181905260a4830184905260c4830182905290916001600160a01b0387169063d505accf9060e401600060405180830381600087803b15801561208457600080fd5b505af1158015612098573d6000803e3d6000fd5b50505050505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526108099085906323b872dd60e01b906084016119c6565b6120f16001600160a01b038416836000612553565b610d1d6001600160a01b0384168383612553565b600061215a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166126779092919063ffffffff16565b805190915015610d1d57808060200190518101906121789190612e42565b610d1d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610195565b600081156122e057333b6122425760405162461bcd60e51b815260206004820152602c60248201527f4552523a2073686f756c6453656c6c456e7469726542616c616e63652069732060448201526b7472756520666f7220454f4160a01b6064820152608401610195565b604051636eb1769f60e11b81523360048201523060248201526000906001600160a01b0386169063dd62ed3e9060440160206040518083038186803b15801561228a57600080fd5b505afa15801561229e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122c29190612e76565b90506122d96001600160a01b0386163330846120a4565b90506122f8565b6122f56001600160a01b0385163330866120a4565b50815b9392505050565b60006001600160a01b038616730d500b1d8e8ef31e21c99d1db9a6444d3adf127014801561233457506001600160a01b038516155b156123a657604051632e1a7d4d60e01b815260048101859052730d500b1d8e8ef31e21c99d1db9a6444d3adf127090632e1a7d4d90602401600060405180830381600087803b15801561238657600080fd5b505af115801561239a573d6000803e3d6000fd5b5050505083905061254a565b60006001600160a01b0387166123bd5750836123c8565b6123c88785876120dc565b60006123d38761268e565b6001600160a01b03861660009081526007602052604090205490915060ff166124365760405162461bcd60e51b815260206004820152601560248201527415185c99d95d081b9bdd08105d5d1a1bdc9a5e9959605a1b6044820152606401610195565b6000856001600160a01b031683866040516124519190612eb1565b60006040518083038185875af1925050503d806000811461248e576040519150601f19603f3d011682016040523d82523d6000602084013e612493565b606091505b50509050806124dc5760405162461bcd60e51b81526020600482015260156024820152744572726f72205377617070696e6720546f6b656e7360581b6044820152606401610195565b6000826124e88a61268e565b6124f29190613077565b9050600081116125445760405162461bcd60e51b815260206004820152601f60248201527f5377617070656420746f20496e76616c696420496e7465726d656469617465006044820152606401610195565b93505050505b95945050505050565b8015806125dc5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b1580156125a257600080fd5b505afa1580156125b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125da9190612e76565b155b6126475760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610195565b6040516001600160a01b038316602482015260448101829052610d1d90849063095ea7b360e01b906064016119c6565b60606126868484600085612724565b949350505050565b60006001600160a01b0382166126a5575047919050565b6040516370a0823160e01b81523060048201526001600160a01b038316906370a082319060240160206040518083038186803b1580156126e457600080fd5b505afa1580156126f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061271c9190612e76565b90505b919050565b6060824710156127855760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610195565b843b6127d35760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610195565b600080866001600160a01b031685876040516127ef9190612eb1565b60006040518083038185875af1925050503d806000811461282c576040519150601f19603f3d011682016040523d82523d6000602084013e612831565b606091505b509150915061284182828661284c565b979650505050505050565b6060831561285b5750816122f8565b82511561286b5782518084602001fd5b8160405162461bcd60e51b81526004016101959190612f37565b803561271f81613101565b60008083601f8401126128a1578182fd5b50813567ffffffffffffffff8111156128b8578182fd5b6020830191508360208260051b85010111156128d357600080fd5b9250929050565b600082601f8301126128ea578081fd5b813560206128ff6128fa83612ffc565b612fcb565b80838252828201915082860187848660051b890101111561291e578586fd5b855b8581101561294557813561293381613101565b84529284019290840190600101612920565b5090979650505050505050565b6000601f8381840112612963578182fd5b823560206129736128fa83612ffc565b80838252828201915082870188848660051b8a01011115612992578687fd5b865b85811015612a2557813567ffffffffffffffff808211156129b357898afd5b818b0191508b603f8301126129c657898afd5b868201356040828211156129dc576129dc6130eb565b6129ed828c01601f19168a01612fcb565b92508183528d81838601011115612a02578b8cfd5b818185018a85013750810187018a90528552509284019290840190600101612994565b509098975050505050505050565b60008083601f840112612a44578182fd5b50813567ffffffffffffffff811115612a5b578182fd5b6020830191508360208285010111156128d357600080fd5b600060208284031215612a84578081fd5b81356122f881613101565b600060208284031215612aa0578081fd5b81516122f881613101565b60008060408385031215612abd578081fd5b8235612ac881613101565b91506020830135612ad881613101565b809150509250929050565b600080600080600080600080610100898b031215612aff578384fd5b8835612b0a81613101565b97506020890135612b1a81613101565b96506040890135955060608901359450608089013567ffffffffffffffff80821115612b44578586fd5b612b508c838d016128da565b955060a08b0135915080821115612b65578485fd5b50612b728b828c01612952565b93505060c0890135612b8381613101565b915060e0890135612b9381613119565b809150509295985092959890939650565b60008060008060008060008060006101008a8c031215612bc2578081fd5b612bcb8a612885565b9850612bd960208b01612885565b975060408a0135965060608a0135955060808a013567ffffffffffffffff80821115612c03578283fd5b612c0f8d838e01612a33565b909750955060a08c0135915080821115612c27578283fd5b612c338d838e016128da565b945060c08c0135915080821115612c48578283fd5b50612c558c828d01612952565b925050612c6460e08b01612885565b90509295985092959850929598565b60008060408385031215612c85578182fd5b8235612c9081613101565b91506020830135612ad881613119565b60008060408385031215612cb2578182fd5b8235612cbd81613101565b946020939093013593505050565b600080600060608486031215612cdf578081fd5b8335612cea81613101565b9250602084013591506040840135612d0181613101565b809150509250925092565b600080600080600060808688031215612d23578283fd5b8535612d2e81613101565b9450602086013593506040860135612d4581613101565b9250606086013567ffffffffffffffff811115612d60578182fd5b612d6c88828901612a33565b969995985093965092949392505050565b60008060208385031215612d8f578182fd5b823567ffffffffffffffff811115612da5578283fd5b612db185828601612890565b90969095509350505050565b60008060008060408587031215612dd2578182fd5b843567ffffffffffffffff80821115612de9578384fd5b612df588838901612890565b90965094506020870135915080821115612e0d578384fd5b50612e1a87828801612890565b95989497509550505050565b600060208284031215612e37578081fd5b81356122f881613119565b600060208284031215612e53578081fd5b81516122f881613119565b600060208284031215612e6f578081fd5b5035919050565b600060208284031215612e87578081fd5b5051919050565b60008060408385031215612ea0578182fd5b505080516020909101519092909150565b60008251612ec381846020870161308e565b9190910192915050565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b039788168152958716602087015260408601949094526060850192909252608084015290921660a082015260c081019190915260e00190565b6020815260008251806020840152612f5681604085016020870161308e565b601f01601f19169190910160400192915050565b60208082526012908201527115195b5c1bdc985c9a5b1e4814185d5cd95960721b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b604051601f8201601f1916810167ffffffffffffffff81118282101715612ff457612ff46130eb565b604052919050565b600067ffffffffffffffff821115613016576130166130eb565b5060051b60200190565b60008219821115613033576130336130d5565b500190565b60008261305357634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615613072576130726130d5565b500290565b600082821015613089576130896130d5565b500390565b60005b838110156130a9578181015183820152602001613091565b838111156108095750506000910152565b60006000198214156130ce576130ce6130d5565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461311657600080fd5b50565b801515811461311657600080fdfea26469706673582212204371d265ee1c9d7d75f4283fb42e15df2fd0c6eae192e028972253ead643c17864736f6c6343000804003300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
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:12831:9:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4685:10:15;4699:9;4685:23;;4677:60;;;;-1:-1:-1;;;4677:60:15;;16306:2:32;4677:60:15;;;16288:21:32;16345:2;16325:18;;;16318:30;16384:26;16364:18;;;16357:54;16428:18;;4677:60:15;;;;;;;;;3487:12831:9;;;;;2521:269:15;;;;;;;;;;-1:-1:-1;2521:269:15;;;;;:::i;:::-;;:::i;3674:621::-;;;;;;;;;;-1:-1:-1;3674:621:15;;;;;:::i;:::-;;:::i;2039:84::-;;;;;;;;;;;;;:::i;565:71::-;;;;;;;;;;-1:-1:-1;565:71:15;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;23741:25:32;;;23729:2;23714:18;565:71:15;;;;;;;;665:56;;;;;;;;;;-1:-1:-1;665:56:15;;;;;:::i;:::-;;;;;;;;;;;;;;7666:1690:9;;;;;;;;;;-1:-1:-1;7666:1690:9;;;;;:::i;:::-;;:::i;2796:145:15:-;;;;;;;;;;-1:-1:-1;2796:145:15;;;;;:::i;:::-;;:::i;481:42::-;;;;;;;;;;-1:-1:-1;481:42:15;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;15339:14:32;;15332:22;15314:41;;15302:2;15287:18;481:42:15;15269:92:32;2283:232:15;;;;;;;;;;-1:-1:-1;2283:232:15;;;;;:::i;:::-;;:::i;360:23::-;;;;;;;;;;;;;;;;3014:587;;;;;;;;;;-1:-1:-1;3014:587:15;;;;;:::i;:::-;;:::i;1722:145:19:-;;;;;;;;;;;;;:::i;234:27:15:-;;;;;;;;;;-1:-1:-1;234:27:15;;;;-1:-1:-1;;;234:27:15;;;;;;15624:692:9;;;;;;;;;;-1:-1:-1;15624:692:9;;;;;:::i;:::-;;:::i;:::-;;;;24261:25:32;;;24317:2;24302:18;;24295:34;;;;-1:-1:-1;;;;;24403:15:32;;;24383:18;;;24376:43;;;;24455:15;24450:2;24435:18;;24428:43;24248:3;24233:19;15624:692:9;24215:262:32;1090:85:19;;;;;;;;;;-1:-1:-1;1136:7:19;1162:6;1090:85;;-1:-1:-1;;;;;1162:6:19;;;11703:51:32;;11691:2;11676:18;1090:85:19;11658:102:32;10658:705:9;;;;;;;;;;-1:-1:-1;10658:705:9;;;;;:::i;:::-;;:::i;4301:333:15:-;;;;;;;;;;-1:-1:-1;4301:333:15;;;;;:::i;:::-;;:::i;764:47::-;;;;;;;;;;-1:-1:-1;764:47:15;;;;;:::i;:::-;;;;;;;;;;;;;;;;9735:453:9;;;;;;;;;;-1:-1:-1;9735:453:9;;;;;:::i;:::-;;:::i;:::-;;;;23951:25:32;;;24007:2;23992:18;;23985:34;;;;23924:18;9735:453:9;23906:119:32;309:44:15;;;;;;;;;;-1:-1:-1;309:44:15;;;;;:::i;:::-;;;;;;;;;;;;;;;;4841:2309:9;;;;;;;;;;-1:-1:-1;4841:2309:9;;;;;:::i;:::-;;:::i;2016:274:19:-;;;;;;;;;;-1:-1:-1;2016:274:19;;;;;:::i;:::-;;:::i;2129:148:15:-;;;;;;;;;;-1:-1:-1;2129:148:15;;;;;:::i;:::-;;:::i;2521:269::-;1136:7:19;1162:6;-1:-1:-1;;;;;1162:6:19;665:10:26;1302:23:19;1294:68;;;;-1:-1:-1;;;1294:68:19;;;;;;;:::i;:::-;2675:3:15::1;2652:19;:26;;2631:106;;;::::0;-1:-1:-1;;;2631:106:15;;20357:2:32;2631:106:15::1;::::0;::::1;20339:21:32::0;20396:2;20376:18;;;20369:30;20435:34;20415:18;;;20408:62;-1:-1:-1;;;20486:18:32;;;20479:31;20527:19;;2631:106:15::1;20329:223:32::0;2631:106:15::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:15;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;3843:39:15;;;;;;;;;;;;;;;-1:-1:-1;3843:39:15;;;;3913:10;3896:28;;:16;:28;;;;;;3843:39;;-1:-1:-1;;;3925:6:15;;3932:1;3925:9;;;;;-1:-1:-1;;;3925:9:15;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;3896:39:15;-1:-1:-1;;;;;3896:39:15;;;;;;;;;;;;:43;;;;4055:8;4004:21;:32;4026:6;;4033:1;4026:9;;;;;-1:-1:-1;;;4026:9:15;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;4004:32:15;-1:-1:-1;;;;;4004:32:15;;;;;;;;;;;;;:59;;;;:::i;:::-;3953:21;:32;3975:6;;3982:1;3975:9;;;;;-1:-1:-1;;;3975:9:15;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;3953:32:15;;;;;;;;;;;;-1:-1:-1;3953:32:15;:110;865:42;4082:6;;4089:1;4082:9;;;;;-1:-1:-1;;;4082:9:15;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;4082:23:15;;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:15;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;;;;4212:30:15;;:52;:30;:52::i;:::-;3813:3;;;;:::i;:::-;;;;3774:515;;;;3674:621;;;:::o;2039:84::-;1136:7:19;1162:6;-1:-1:-1;;;;;1162:6:19;665:10:26;1302:23:19;1294:68;;;;-1:-1:-1;;;1294:68:19;;;;;;;:::i;:::-;2109:7:15::1;::::0;;-1:-1:-1;;;;2098:18:15;::::1;-1:-1:-1::0;;;2109:7:15;;;::::1;;;2108:8;2098:18:::0;;::::1;;::::0;;2039:84::o;7666:1690:9:-;7979:17;1127:7:15;;-1:-1:-1;;;1127:7:15;;;;1123:98;;;1150:28;;-1:-1:-1;;;1150:28:15;;;;;;;:::i;1123:98::-;8009:15:9::1;8026::::0;8057:132:::1;8091:15;8124:10;8152:23;8057:16;:132::i;:::-;8008:181;;;;8244:167;8269:15;8298:7;8319;8340:14;8368:11;8393:8;8244:11;:167::i;:::-;8232:179;;8442:12;8429:9;:25;;8421:51;;;::::0;-1:-1:-1;;;8421:51:9;;16659:2:32;8421:51:9::1;::::0;::::1;16641:21:32::0;16698:2;16678:18;;;16671:30;-1:-1:-1;;;16717:18:32;;;16710:43;16770:18;;8421:51:9::1;16631:163:32::0;8421:51:9::1;8483:28;-1:-1:-1::0;;;;;8565:28:9;::::1;8561:629;;8632:135;865:42:15;8695:9:9;8722;8749:4;8632:17;:135::i;:::-;8609:158:::0;-1:-1:-1;8790:10:9::1;8782:62;8811:32;8609:158:::0;8811:9;:32:::1;:::i;:::-;8782:62;::::0;;::::1;::::0;;::::1;::::0;::::1;::::0;;;;;;::::1;;;;;;;;;;;;;::::0;::::1;;;;;;8561:629;;;8898:139;8933:14;8965:9;8992;9019:4;8898:17;:139::i;:::-;8875:162:::0;-1:-1:-1;9052:127:9::1;9105:10;9133:32;8875:162:::0;9133:9;:32:::1;:::i;:::-;-1:-1:-1::0;;;;;9052:35:9;::::1;::::0;:127;:35:::1;:127::i;:::-;9212:32;9224:20:::0;9212:9;:32:::1;:::i;:::-;9200:44;;9260:62;9267:10;9279:15;9296:14;9312:9;9260:62;;;;;;;;;:::i;:::-;;;;;;;;9333:16;;;7666:1690:::0;;;;;;;;;;:::o;2796:145:15:-;1136:7:19;1162:6;-1:-1:-1;;;;;1162:6:19;665:10:26;1302:23:19;1294:68;;;;-1:-1:-1;;;1294:68:19;;;;;;;:::i;:::-;-1:-1:-1;;;;;2902:22:15;;;::::1;;::::0;;;:10:::1;:22;::::0;;;;:32;;-1:-1:-1;;2902:32:15::1;::::0;::::1;;::::0;;;::::1;::::0;;2796:145::o;2283:232::-;1136:7:19;1162:6;-1:-1:-1;;;;;1162:6:19;665:10:26;1302:23:19;1294:68;;;;-1:-1:-1;;;1294:68:19;;;;;;;:::i;:::-;2419:3:15::1;2402:13;:20;;2359:115;;;::::0;-1:-1:-1;;;2359:115:15;;19297:2:32;2359:115:15::1;::::0;::::1;19279:21:32::0;19336:2;19316:18;;;19309:30;19375:28;19355:18;;;19348:56;19421:18;;2359:115:15::1;19269:176:32::0;2359:115:15::1;2484:8;:24:::0;2283:232::o;3014:587::-;1136:7:19;1162:6;-1:-1:-1;;;;;1162:6:19;665:10:26;1302:23:19;1294:68;;;;-1:-1:-1;;;1294:68:19;;;;;;;:::i;:::-;3099:9:15::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:15::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;3182:23:15::1;;3178:407;;;3255:21;:32;3277:6;;3284:1;3277:9;;;;;-1:-1:-1::0;;;3277:9:15::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;3255:32:15::1;::::0;;::::1;::::0;::::1;::::0;;;;;;-1:-1:-1;3255:32:15;;3231:56:::1;::::0;:21:::1;:56;:::i;:::-;3225:62;;3306:40;3332:7;1136::19::0;1162:6;-1:-1:-1;;;;;1162:6:19;;1090:85;3332:7:15::1;3342:3;3306:17;:40::i;:::-;3178:407;;;3476:21;:32;3498:6;;3505:1;3498:9;;;;;-1:-1:-1::0;;;3498:9:15::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;3476:32:15::1;-1:-1:-1::0;;;;;3476:32:15::1;;;;;;;;;;;;;3418:6;;3425:1;3418:9;;;;;-1:-1:-1::0;;;3418:9:15::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3411:42;::::0;-1:-1:-1;;;3411:42:15;;3447:4:::1;3411:42;::::0;::::1;11703:51:32::0;-1:-1:-1;;;;;3411:27:15;;;::::1;::::0;::::1;::::0;11676:18:32;;3411:42:15::1;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:97;;;;:::i;:::-;3385:123;;3526:44;3557:7;1136::19::0;1162:6;-1:-1:-1;;;;;1162:6:19;;1090:85;3557:7:15::1;3566:3;3533:6;;3540:1;3533:9;;;;;-1:-1:-1::0;;;3533:9:15::1;;;;;;;;3526:44;-1:-1:-1::0;3133:3:15;::::1;::::0;::::1;:::i;:::-;;;;3094:501;;;;3014:587:::0;;:::o;1722:145:19:-;1136:7;1162:6;-1:-1:-1;;;;;1162:6:19;665:10:26;1302:23:19;1294:68;;;;-1:-1:-1;;;1294:68:19;;;;;;;:::i;:::-;1828:1:::1;1812:6:::0;;1791:40:::1;::::0;-1:-1:-1;;;;;1812:6:19;;::::1;::::0;1791:40:::1;::::0;1828:1;;1791:40:::1;1858:1;1841:19:::0;;-1:-1:-1;;;;;;1841:19:19::1;::::0;;1722:145::o;15624:692:9:-;15759:15;15788;15817:14;15845;15884:19;15921:15;15884:53;;15956:4;-1:-1:-1;;;;;15956:11:9;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15947:22;;15988:4;-1:-1:-1;;;;;15988:11:9;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;16031:41;;-1:-1:-1;;;16031:41:9;;-1:-1:-1;;;;;11721:32:32;;;16031:41:9;;;11703:51:32;15979:22:9;;-1:-1:-1;16012:16:9;;16031:24;;;;;11676:18:32;;16031:41:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;16101;;-1:-1:-1;;;16101:41:9;;-1:-1:-1;;;;;11721:32:32;;;16101:41:9;;;11703:51:32;16012:60:9;;-1:-1:-1;16082:16:9;;16101:24;;;;;11676:18:32;;16101:41:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;16082:60;;16153:20;16176:4;-1:-1:-1;;;;;16176:16:9;;:18;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;16153:41;-1:-1:-1;16153:41:9;16216:20;16228:8;16216:9;:20;:::i;:::-;16215:37;;;;:::i;:::-;16205:47;-1:-1:-1;16297:12:9;16273:20;16285:8;16273:9;:20;:::i;:::-;16272:37;;;;:::i;:::-;16262:47;;15624:692;;;;;;;;;;;:::o;10658:705::-;10977:7;1127::15;;-1:-1:-1;;;1127:7:15;;;;1123:98;;;1150:28;;-1:-1:-1;;;1150:28:15;;;;;;;:::i;1123:98::-;11014:52:9::1;11022:15;3739:29;11056:9;;11014:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;11014:7:9::1;::::0;-1:-1:-1;;;11014:52:9:i:1;:::-;11098:248;11122:14;11154:15;11187:10;11215:12;11245:11;11274:8;11300:9;11327:5;11098:6;:248::i;:::-;11077:279:::0;10658:705;-1:-1:-1;;;;;;;;;;10658:705:9:o;4301:333:15:-;1136:7:19;1162:6;-1:-1:-1;;;;;1162:6:19;665:10:26;1302:23:19;1294:68;;;;-1:-1:-1;;;1294:68:19;;;;;;;:::i;:::-;4444:35:15;;::::1;4436:68;;;::::0;-1:-1:-1;;;4436:68:15;;20008:2:32;4436:68:15::1;::::0;::::1;19990:21:32::0;20047:2;20027:18;;;20020:30;-1:-1:-1;;;20066:18:32;;;20059:50;20126:18;;4436:68:15::1;19980:170:32::0;4436:68:15::1;4520:9;4515:113;4535:18:::0;;::::1;4515:113;;;4604:10;;4615:1;4604:13;;;;;-1:-1:-1::0;;;4604:13:15::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4574:15;:27;4590:7;;4598:1;4590:10;;;;;-1:-1:-1::0;;;4590:10:15::1;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;4574:27:15::1;::::0;;::::1;::::0;::::1;::::0;;;;;;-1:-1:-1;4574:27:15;:43;;-1:-1:-1;;4574:43:15::1;::::0;::::1;;::::0;;;::::1;::::0;;4555:3;::::1;::::0;::::1;:::i;:::-;;;;4515:113;;;;4301:333:::0;;;;:::o;9735:453:9:-;9933:15;1127:7:15;;9933:15:9;;-1:-1:-1;;;1127:7:15;;;;1123:98;;;1150:28;;-1:-1:-1;;;1150:28:15;;;;;;;:::i;1123:98::-;9995:52:9::1;10003:15;3739:29;10037:9;;9995:52;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;::::0;;;;-1:-1:-1;9995:7:9::1;::::0;-1:-1:-1;;;9995:52:9:i:1;:::-;10079:102;10109:15;10138:10;10162:9;10079:16;:102::i;:::-;10058:123:::0;;;;-1:-1:-1;9735:453:9;-1:-1:-1;;;;;;9735:453:9:o;4841:2309::-;4993:15;1127:7:15;;4993:15:9;;-1:-1:-1;;;1127:7:15;;;;1123:98;;;1150:28;;-1:-1:-1;;;1150:28:15;;;;;;;:::i;1123:98::-;5074:15:9;-1:-1:-1;;;;;5109:27:9;::::1;5101:67;;;::::0;-1:-1:-1;;;5101:67:9;;19652:2:32;5101:67:9::1;::::0;::::1;19634:21:32::0;19691:2;19671:18;;;19664:30;19730:29;19710:18;;;19703:57;19777:18;;5101:67:9::1;19624:177:32::0;5101:67:9::1;5203:14;5220:4;-1:-1:-1::0;;;;;5220:11:9::1;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5203:30;;5243:14;5260:4;-1:-1:-1::0;;;;;5260:11:9::1;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5243:30:::0;-1:-1:-1;5284:125:9::1;-1:-1:-1::0;;;;;5284:40:9;::::1;5338:10;5370:4;5389:10:::0;5284:40:::1;:125::i;:::-;5420:68;5434:15;3856:42;5477:10;5420:13;:68::i;:::-;-1:-1:-1::0;;;;;5503:28:9;::::1;4097:42;5503:28;::::0;:60:::1;;-1:-1:-1::0;;;;;;5535:28:9;::::1;4097:42;5535:28;5503:60;5499:1511;;;5579:14;-1:-1:-1::0;;;;;5596:28:9;::::1;4097:42;5596:28;:46;;5636:6;5596:46;;;5627:6;5596:46;5677:195;::::0;-1:-1:-1;;;5677:195:9;;-1:-1:-1;;;;;14921:15:32;;5677:195:9::1;::::0;::::1;14903:34:32::0;14953:18;;;14946:34;;;5781:1:9::1;14996:18:32::0;;;14989:34;;;15039:18;;;15032:34;5827:4:9::1;15082:19:32::0;;;15075:44;-1:-1:-1;;;15135:19:32;;;15128:35;5579:63:9;;-1:-1:-1;3856:42:9::1;::::0;5677:34:::1;::::0;14837:19:32;;5677:195:9::1;::::0;::::1;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;5656:216:::0;;-1:-1:-1;5656:216:9;-1:-1:-1;5920:21:9::1;5960:51;5978:6:::0;5656:216;5995:9;6006:4:::1;5960:17;:51::i;:::-;5920:91;;6025:19;6063:55;865:42:15;6093:7:9;6102:9;6113:4;6063:17;:55::i;:::-;6025:93:::0;-1:-1:-1;6160:64:9::1;6188:10;6200:23;6210:13:::0;6200:7;:23:::1;:::i;:::-;-1:-1:-1::0;;;;;6160:27:9;::::1;::::0;:64;:27:::1;:64::i;:::-;6238:61;6264:10;6277:21;6287:11:::0;6277:7;:21:::1;:::i;:::-;6238:17;:61::i;:::-;5499:1511;;;;;;6351:216;::::0;-1:-1:-1;;;6351:216:9;;3856:42:::1;::::0;6351:31:::1;::::0;:216:::1;::::0;6400:6;;6424;;6448:10;;6476:1:::1;::::0;;;6522:4:::1;::::0;-1:-1:-1;;;3623:66:9;6351:216:::1;;;:::i;:::-;;::::0;::::1;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6330:237:::0;;-1:-1:-1;6330:237:9;-1:-1:-1;6615:22:9::1;6656:51;6674:6:::0;6330:237;6691:9;6702:4:::1;6656:17;:51::i;:::-;6615:92;;6721:22;6762:51;6780:6;6788:7;6797:9;6808:4;6762:17;:51::i;:::-;6721:92:::0;-1:-1:-1;6855:65:9::1;6883:10;6895:24;6905:14:::0;6895:7;:24:::1;:::i;:::-;-1:-1:-1::0;;;;;6855:27:9;::::1;::::0;:65;:27:::1;:65::i;:::-;6934;6962:10;6974:24;6984:14:::0;6974:7;:24:::1;:::i;6934:65::-;5499:1511;;;7024:52;7031:10;7043:15;7060:6;7068:7;7024:52;;;;;;;;;:::i;:::-;;;;;;;;7091;7098:10;7110:15;7127:6;7135:7;7091:52;;;;;;;;;:::i;:::-;;;;;;;;1209:1:15;;;4841:2309:9::0;;;;;;:::o;2016:274:19:-;1136:7;1162:6;-1:-1:-1;;;;;1162:6:19;665:10:26;1302:23:19;1294:68;;;;-1:-1:-1;;;1294:68:19;;;;;;;:::i;:::-;-1:-1:-1;;;;;2117:22:19;::::1;2096:107;;;::::0;-1:-1:-1;;;2096:107:19;;17001:2:32;2096:107:19::1;::::0;::::1;16983:21:32::0;17040:2;17020:18;;;17013:30;17079:34;17059:18;;;17052:62;-1:-1:-1;;;17130:18:32;;;17123:36;17176:19;;2096:107:19::1;16973:228:32::0;2096:107:19::1;2239:6;::::0;;2218:38:::1;::::0;-1:-1:-1;;;;;2218:38:19;;::::1;::::0;2239:6;::::1;::::0;2218:38:::1;::::0;::::1;2266:6;:17:::0;;-1:-1:-1;;;;;;2266:17:19::1;-1:-1:-1::0;;;;;2266:17:19;;;::::1;::::0;;;::::1;::::0;;2016:274::o;2129:148:15:-;1136:7:19;1162:6;-1:-1:-1;;;;;1162:6:19;665:10:26;1302:23:19;1294:68;;;;-1:-1:-1;;;1294:68:19;;;;;;;:::i;:::-;-1:-1:-1;;;;;2237:24:15;;;::::1;;::::0;;;:12:::1;:24;::::0;;;;:33;;-1:-1:-1;;2237:33:15::1;::::0;::::1;;::::0;;;::::1;::::0;;2129:148::o;2068:459:25:-;2195:6;2170:21;:31;;2149:107;;;;-1:-1:-1;;;2149:107:25;;18532:2:32;2149:107:25;;;18514:21:32;18571:2;18551:18;;;18544:30;18610:31;18590:18;;;18583:59;18659:18;;2149:107:25;18504:179:32;2149:107:25;2345:12;2363:9;-1:-1:-1;;;;;2363:14:25;2386:6;2363:35;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2344:54;;;2429:7;2408:112;;;;-1:-1:-1;;;2408:112:25;;17758:2:32;2408:112:25;;;17740:21:32;17797:2;17777:18;;;17770:30;17836:34;17816:18;;;17809:62;17907:28;17887:18;;;17880:56;17953:19;;2408:112:25;17730:248:32;634:239:23;798:58;;-1:-1:-1;;;;;14475:32:32;;798:58:23;;;14457:51:32;14524:18;;;14517:34;;;746:120:23;;779:5;;-1:-1:-1;;;821:23:23;14430:18:32;;798:58:23;;;;-1:-1:-1;;798:58:23;;;;;;;;;;;;;;-1:-1:-1;;;;;798:58:23;-1:-1:-1;;;;;;798:58:23;;;;;;;;;;746:19;:120::i;11995:862:9:-;12144:15;;12225;-1:-1:-1;;;;;12260:27:9;;12252:67;;;;-1:-1:-1;;;12252:67:9;;19652:2:32;12252:67:9;;;19634:21:32;19691:2;19671:18;;;19664:30;19730:29;19710:18;;;19703:57;19777:18;;12252:67:9;19624:177:32;12252:67:9;12330:14;12347:4;-1:-1:-1;;;;;12347:11:9;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12330:30;;12370:14;12387:4;-1:-1:-1;;;;;12387:11:9;;:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12370:30;;12411:65;12423:15;12440:10;12452:23;12411:11;:65::i;:::-;;12487:68;12501:15;3856:42;12544:10;12487:13;:68::i;:::-;12587:184;;-1:-1:-1;;;12587:184:9;;3856:42;;12587:31;;:184;;12632:6;;12652;;12672:10;;12696:1;;;;12734:4;;-1:-1:-1;;;3623:66:9;12587:184;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12566:205;;-1:-1:-1;12566:205:9;-1:-1:-1;12789:11:9;;;;;:26;;;12814:1;12804:7;:11;12789:26;12781:69;;;;-1:-1:-1;;;12781:69:9;;22604:2:32;12781:69:9;;;22586:21:32;22643:2;22623:18;;;22616:30;22682:32;22662:18;;;22655:60;22732:18;;12781:69:9;22576:180:32;12781:69:9;11995:862;;;;;;;;;:::o;12863:1273::-;13087:20;13119:14;13151:15;-1:-1:-1;;;;;13136:38:9;;:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;13119:57;;13186:14;13218:15;-1:-1:-1;;;;;13203:38:9;;:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;13186:57;;13301:7;-1:-1:-1;;;;;13291:17:9;:6;-1:-1:-1;;;;;13291:17:9;;13287:400;;;13339:22;13354:7;13339:12;:22;:::i;:::-;13324:37;;13287:400;;;13493:183;13525:6;13553:7;13582;13611:11;13623:1;13611:14;;;;;;-1:-1:-1;;;13611:14:9;;;;;;;;;;;;;;;13647:8;13656:1;13647:11;;;;;;-1:-1:-1;;;13647:11:9;;;;;;;;;;;;;;;13493:10;:183::i;:::-;13462:214;;:12;:214;:::i;:::-;13431:245;;13287:400;13744:7;-1:-1:-1;;;;;13734:17:9;:6;-1:-1:-1;;;;;13734:17:9;;13730:400;;;13782:22;13797:7;13782:12;:22;:::i;:::-;13767:37;;13730:400;;;13936:183;13968:6;13996:7;14025;14054:11;14066:1;14054:14;;;;;;-1:-1:-1;;;14054:14:9;;;;;;;;;;;;;;;14090:8;14099:1;14090:11;;;;;;-1:-1:-1;;;14090:11:9;;;;;;;;13936:183;13905:214;;:12;:214;:::i;:::-;13874:245;;13730:400;12863:1273;;;;;;;;;;:::o;1231:786:17:-;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:17;;;;;;:10;:21;;;;;;1544:50;;-1:-1:-1;1613:21:17;;1609:392;;;-1:-1:-1;;;;;1658:19:17;;1654:84;;865:42:15;1701:18:17;;1654:84;1756:24;1845:3;1827:14;;1804:20;:37;;;;:::i;:::-;1803:45;;;;:::i;:::-;-1:-1:-1;;;;;1866:27:17;;;;;;;:16;:27;;;;;;;;:34;;;;;;;;;;;:54;;1756:92;;-1:-1:-1;1756:92:17;;1866:34;;:27;:54;;1756:92;;1866:54;:::i;:::-;;;;-1:-1:-1;;;;;;;1938:28:17;;;;;;:21;:28;;;;;:48;;1970:16;;1938:28;:48;;1970:16;;1938:48;:::i;:::-;;;;-1:-1:-1;;;1609:392:17;1231:786;;;;;;;:::o;11369:620:9:-;11510:9;:16;11530:2;11510:22;11502:59;;;;-1:-1:-1;;;11502:59:9;;22251:2:32;11502:59:9;;;22233:21:32;22290:2;22270:18;;;22263:30;22329:26;22309:18;;;22302:54;22373:18;;11502:59:9;22223:174:32;11502:59:9;11676:2;11661:18;;11655:25;11719:2;11704:18;;;11698:25;11770:2;11755:18;;11749:25;11794:188;;-1:-1:-1;;;11794:188:9;;11846:10;11794:188;;;13957:34:32;11878:4:9;14007:18:32;;;14000:43;14059:18;;;14052:34;;;-1:-1:-1;;;14102:18:32;;;14095:34;11572:9:9;11741:34;;;;14145:19:32;;;14138:46;;;14200:19;;;14193:35;;;14244:19;;;14237:35;;;11698:25:9;;-1:-1:-1;;;;;11794:38:9;;;;;13891:19:32;;11794:188:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11369:620;;;;;;:::o;879:275:23:-;1069:68;;-1:-1:-1;;;;;12793:15:32;;;1069:68:23;;;12775:34:32;12845:15;;12825:18;;;12818:43;12877:18;;;12870:34;;;1017:130:23;;1050:5;;-1:-1:-1;;;1092:27:23;12710:18:32;;1069:68:23;12692:218:32;1786:216:15;1906:37;-1:-1:-1;;;;;1906:25:15;;1932:7;1941:1;1906:25;:37::i;:::-;1953:42;-1:-1:-1;;;;;1953:25:15;;1979:7;1988:6;1953:25;:42::i;3561:867:23:-;3980:23;4018:115;4063:4;4018:115;;;;;;;;;;;;;;;;;4026:5;-1:-1:-1;;;;;4018:27:23;;;:115;;;;;:::i;:::-;4147:17;;3980:153;;-1:-1:-1;4147:21:23;4143:279;;4316:10;4305:30;;;;;;;;;;;;:::i;:::-;4280:131;;;;-1:-1:-1;;;4280:131:23;;22963:2:32;4280:131:23;;;22945:21:32;23002:2;22982:18;;;22975:30;23041:34;23021:18;;;23014:62;-1:-1:-1;;;23092:18:32;;;23085:40;23142:19;;4280:131:23;22935:232:32;483:742:17;613:7;636:23;632:587;;;719:10;1090:20:25;675:133:17;;;;-1:-1:-1;;;675:133:17;;21120:2:32;675:133:17;;;21102:21:32;21159:2;21139:18;;;21132:30;21198:34;21178:18;;;21171:62;-1:-1:-1;;;21249:18:32;;;21242:42;21301:19;;675:133:17;21092:234:32;675:133:17;859:50;;-1:-1:-1;;;859:50:17;;883:10;859:50;;;11977:34:32;903:4:17;12027:18:32;;;12020:43;823:17:17;;-1:-1:-1;;;;;859:23:17;;;;;11912:18:32;;859:50:17;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;823:86;-1:-1:-1;923:130:17;-1:-1:-1;;;;;923:30:17;;971:10;1007:4;823:86;923:30;:130::i;:::-;1075:9;-1:-1:-1;1068:16:17;;632:587;1115:65;-1:-1:-1;;;;;1115:30:17;;1146:10;1166:4;1173:6;1115:30;:65::i;:::-;-1:-1:-1;1202:6:17;632:587;483:742;;;;;:::o;14142:1003:9:-;14328:7;-1:-1:-1;;;;;14351:38:9;;4097:42;14351:38;:63;;;;-1:-1:-1;;;;;;14393:21:9;;;14351:63;14347:163;;;14430:42;;-1:-1:-1;;;14430:42:9;;;;;23741:25:32;;;4097:42:9;;14430:34;;23714:18:32;;14430:42:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14493:6;14486:13;;;;14347:163;14520:19;-1:-1:-1;;;;;14553:30:9;;14549:163;;-1:-1:-1;14613:6:9;14549:163;;;14650:51;14664:16;14682:10;14694:6;14650:13;:51::i;:::-;14722:22;14747:20;14759:7;14747:11;:20::i;:::-;-1:-1:-1;;;;;14786:27:9;;;;;;:15;:27;;;;;;14722:45;;-1:-1:-1;14786:27:9;;14778:61;;;;-1:-1:-1;;;14778:61:9;;15956:2:32;14778:61:9;;;15938:21:32;15995:2;15975:18;;;15968:30;-1:-1:-1;;;16014:18:32;;;16007:51;16075:18;;14778:61:9;15928:171:32;14778:61:9;14850:12;14868:10;-1:-1:-1;;;;;14868:15:9;14892:11;14906:8;14868:47;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14849:66;;;14933:7;14925:41;;;;-1:-1:-1;;;14925:41:9;;17408:2:32;14925:41:9;;;17390:21:32;17447:2;17427:18;;;17420:30;-1:-1:-1;;;17466:18:32;;;17459:51;17527:18;;14925:41:9;17380:171:32;14925:41:9;14977:20;15023:14;15000:20;15012:7;15000:11;:20::i;:::-;:37;;;;:::i;:::-;14977:60;;15071:1;15056:12;:16;15048:60;;;;-1:-1:-1;;;15048:60:9;;21533:2:32;15048:60:9;;;21515:21:32;21572:2;21552:18;;;21545:30;21611:33;21591:18;;;21584:61;21662:18;;15048:60:9;21505:181:32;15048:60:9;15126:12;-1:-1:-1;;;;14142:1003:9;;;;;;;;:::o;1414:690:23:-;1822:10;;;1821:62;;-1:-1:-1;1838:39:23;;-1:-1:-1;;;1838:39:23;;1862:4;1838:39;;;11977:34:32;-1:-1:-1;;;;;12047:15:32;;;12027:18;;;12020:43;1838:15:23;;;;;11912:18:32;;1838:39:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;1821:62;1800:163;;;;-1:-1:-1;;;1800:163:23;;23374:2:32;1800:163:23;;;23356:21:32;23413:2;23393:18;;;23386:30;23452:34;23432:18;;;23425:62;-1:-1:-1;;;23503:18:32;;;23496:52;23565:19;;1800:163:23;23346:244:32;1800:163:23;2025:62;;-1:-1:-1;;;;;14475:32:32;;2025:62:23;;;14457:51:32;14524:18;;;14517:34;;;1973:124:23;;2006:5;;-1:-1:-1;;;2048:22:23;14430:18:32;;2025:62:23;14412:145:32;3683:223:25;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:25:o;1233:280:15:-;1316:15;-1:-1:-1;;;;;1351:19:15;;1347:160;;-1:-1:-1;1396:21:15;1233:280;;;:::o;1347:160::-;1458:38;;-1:-1:-1;;;1458:38:15;;1490:4;1458:38;;;11703:51:32;-1:-1:-1;;;;;1458:23:15;;;;;11676:18:32;;1458:38:15;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1448:48;;1347:160;1233:280;;;:::o;4860:607:25:-;5025:12;5095:5;5070:21;:30;;5049:115;;;;-1:-1:-1;;;5049:115:25;;18890:2:32;5049:115:25;;;18872:21:32;18929:2;18909:18;;;18902:30;18968:34;18948:18;;;18941:62;-1:-1:-1;;;19019:18:32;;;19012:36;19065:19;;5049:115:25;18862:228:32;5049:115:25;1090:20;;5174:60;;;;-1:-1:-1;;;5174:60:25;;21893:2:32;5174:60:25;;;21875:21:32;21932:2;21912:18;;;21905:30;21971:31;21951:18;;;21944:59;22020:18;;5174:60:25;21865:179:32;5174:60:25;5305:12;5319:23;5358:6;-1:-1:-1;;;;;5358:11:25;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:25:o;7683:756::-;7829:12;7857:7;7853:580;;;-1:-1:-1;7887:10:25;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:25;;;;;;;;:::i;14:134:32:-;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:32;;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:32;;617:704;-1:-1:-1;;;;;;;617:704:32:o;1326:1385::-;1378:5;1408:4;1452:3;1447:2;1439:6;1435:15;1431:25;1421:2;;1474:5;1467;1460:20;1421:2;1514:6;1501:20;1540:4;1564:60;1580:43;1620:2;1580:43;:::i;1564:60::-;1646:3;1670:2;1665:3;1658:15;1698:2;1693:3;1689:12;1682:19;;1733:2;1725:6;1721:15;1785:3;1780:2;1774;1771:1;1767:10;1759:6;1755:23;1751:32;1748:41;1745:2;;;1806:5;1799;1792:20;1745:2;1832:5;1846:836;1860:2;1857:1;1854:9;1846:836;;;1937:3;1924:17;1964:18;2014:2;2001:11;1998:19;1995:2;;;2034:5;2027;2020:20;1995:2;2077:11;2069:6;2065:24;2055:34;;2129:3;2124:2;2120;2116:11;2112:21;2102:2;;2151:5;2144;2137:20;2102:2;2203;2199;2195:11;2182:25;2230:2;2255;2251;2248:10;2245:2;;;2261:18;;:::i;:::-;2309:51;2333:11;;;-1:-1:-1;;2329:25:32;2325:34;;2309:51;:::i;:::-;2294:66;;2389:2;2380:7;2373:19;2433:3;2428:2;2423;2419;2415:11;2411:20;2408:29;2405:2;;;2454:5;2447;2440:20;2405:2;2519;2514;2510;2506:11;2501:2;2492:7;2488:16;2475:47;-1:-1:-1;2546:16:32;;2542:25;;2535:40;;;2588:20;;-1:-1:-1;2628:12:32;;;;2660;;;;1878:1;1871:9;1846:836;;;-1:-1:-1;2700:5:32;;1388:1323;-1:-1:-1;;;;;;;;1388:1323:32:o;2716:375::-;2767:8;2777:6;2831:3;2824:4;2816:6;2812:17;2808:27;2798:2;;2856:8;2846;2839:26;2798:2;-1:-1:-1;2886:20:32;;2929:18;2918:30;;2915:2;;;2968:8;2958;2951:26;2915:2;3012:4;3004:6;3000:17;2988:29;;3064:3;3057:4;3048:6;3040;3036:19;3032:30;3029:39;3026:2;;;3081:1;3078;3071:12;3096:257;3155:6;3208:2;3196:9;3187:7;3183:23;3179:32;3176:2;;;3229:6;3221;3214:22;3176:2;3273:9;3260:23;3292:31;3317:5;3292:31;:::i;3358:261::-;3428:6;3481:2;3469:9;3460:7;3456:23;3452:32;3449:2;;;3502:6;3494;3487:22;3449:2;3539:9;3533:16;3558:31;3583:5;3558:31;:::i;3624:398::-;3692:6;3700;3753:2;3741:9;3732:7;3728:23;3724:32;3721:2;;;3774:6;3766;3759:22;3721:2;3818:9;3805:23;3837:31;3862:5;3837:31;:::i;:::-;3887:5;-1:-1:-1;3944:2:32;3929:18;;3916:32;3957:33;3916:32;3957:33;:::i;:::-;4009:7;3999:17;;;3711:311;;;;;:::o;4027:1325::-;4205:6;4213;4221;4229;4237;4245;4253;4261;4314:3;4302:9;4293:7;4289:23;4285:33;4282:2;;;4336:6;4328;4321:22;4282:2;4380:9;4367:23;4399:31;4424:5;4399:31;:::i;:::-;4449:5;-1:-1:-1;4506:2:32;4491:18;;4478:32;4519:33;4478:32;4519:33;:::i;:::-;4571:7;-1:-1:-1;4625:2:32;4610:18;;4597:32;;-1:-1:-1;4676:2:32;4661:18;;4648:32;;-1:-1:-1;4731:3:32;4716:19;;4703:33;4755:18;4785:14;;;4782:2;;;4817:6;4809;4802:22;4782:2;4845:61;4898:7;4889:6;4878:9;4874:22;4845:61;:::i;:::-;4835:71;;4959:3;4948:9;4944:19;4931:33;4915:49;;4989:2;4979:8;4976:16;4973:2;;;5010:6;5002;4995:22;4973:2;;5038:61;5091:7;5080:8;5069:9;5065:24;5038:61;:::i;:::-;5028:71;;;5151:3;5140:9;5136:19;5123:33;5165;5190:7;5165:33;:::i;:::-;5217:7;-1:-1:-1;5276:3:32;5261:19;;5248:33;5290:30;5248:33;5290:30;:::i;:::-;5339:7;5329:17;;;4272:1080;;;;;;;;;;;:::o;5357:1292::-;5549:6;5557;5565;5573;5581;5589;5597;5605;5613;5666:3;5654:9;5645:7;5641:23;5637:33;5634:2;;;5688:6;5680;5673:22;5634:2;5716:29;5735:9;5716:29;:::i;:::-;5706:39;;5764:38;5798:2;5787:9;5783:18;5764:38;:::i;:::-;5754:48;;5849:2;5838:9;5834:18;5821:32;5811:42;;5900:2;5889:9;5885:18;5872:32;5862:42;;5955:3;5944:9;5940:19;5927:33;5979:18;6020:2;6012:6;6009:14;6006:2;;;6041:6;6033;6026:22;6006:2;6085:58;6135:7;6126:6;6115:9;6111:22;6085:58;:::i;:::-;6162:8;;-1:-1:-1;6059:84:32;-1:-1:-1;6250:3:32;6235:19;;6222:33;;-1:-1:-1;6267:16:32;;;6264:2;;;6301:6;6293;6286:22;6264:2;6329:63;6384:7;6373:8;6362:9;6358:24;6329:63;:::i;:::-;6319:73;;6445:3;6434:9;6430:19;6417:33;6401:49;;6475:2;6465:8;6462:16;6459:2;;;6496:6;6488;6481:22;6459:2;;6524:61;6577:7;6566:8;6555:9;6551:24;6524:61;:::i;:::-;6514:71;;;6604:39;6638:3;6627:9;6623:19;6604:39;:::i;:::-;6594:49;;5624:1025;;;;;;;;;;;:::o;6654:392::-;6719:6;6727;6780:2;6768:9;6759:7;6755:23;6751:32;6748:2;;;6801:6;6793;6786:22;6748:2;6845:9;6832:23;6864:31;6889:5;6864:31;:::i;:::-;6914:5;-1:-1:-1;6971:2:32;6956:18;;6943:32;6984:30;6943:32;6984:30;:::i;7051:325::-;7119:6;7127;7180:2;7168:9;7159:7;7155:23;7151:32;7148:2;;;7201:6;7193;7186:22;7148:2;7245:9;7232:23;7264:31;7289:5;7264:31;:::i;:::-;7314:5;7366:2;7351:18;;;;7338:32;;-1:-1:-1;;;7138:238:32:o;7381:466::-;7458:6;7466;7474;7527:2;7515:9;7506:7;7502:23;7498:32;7495:2;;;7548:6;7540;7533:22;7495:2;7592:9;7579:23;7611:31;7636:5;7611:31;:::i;:::-;7661:5;-1:-1:-1;7713:2:32;7698:18;;7685:32;;-1:-1:-1;7769:2:32;7754:18;;7741:32;7782:33;7741:32;7782:33;:::i;:::-;7834:7;7824:17;;;7485:362;;;;;:::o;7852:774::-;7949:6;7957;7965;7973;7981;8034:3;8022:9;8013:7;8009:23;8005:33;8002:2;;;8056:6;8048;8041:22;8002:2;8100:9;8087:23;8119:31;8144:5;8119:31;:::i;:::-;8169:5;-1:-1:-1;8221:2:32;8206:18;;8193:32;;-1:-1:-1;8277:2:32;8262:18;;8249:32;8290:33;8249:32;8290:33;:::i;:::-;8342:7;-1:-1:-1;8400:2:32;8385:18;;8372:32;8427:18;8416:30;;8413:2;;;8464:6;8456;8449:22;8413:2;8508:58;8558:7;8549:6;8538:9;8534:22;8508:58;:::i;:::-;7992:634;;;;-1:-1:-1;7992:634:32;;-1:-1:-1;8585:8:32;;8482:84;7992:634;-1:-1:-1;;;7992:634:32:o;8631:457::-;8717:6;8725;8778:2;8766:9;8757:7;8753:23;8749:32;8746:2;;;8799:6;8791;8784:22;8746:2;8844:9;8831:23;8877:18;8869:6;8866:30;8863:2;;;8914:6;8906;8899:22;8863:2;8958:70;9020:7;9011:6;9000:9;8996:22;8958:70;:::i;:::-;9047:8;;8932:96;;-1:-1:-1;8736:352:32;-1:-1:-1;;;;8736:352:32:o;9093:800::-;9212:6;9220;9228;9236;9289:2;9277:9;9268:7;9264:23;9260:32;9257:2;;;9310:6;9302;9295:22;9257:2;9355:9;9342:23;9384:18;9425:2;9417:6;9414:14;9411:2;;;9446:6;9438;9431:22;9411:2;9490:70;9552:7;9543:6;9532:9;9528:22;9490:70;:::i;:::-;9579:8;;-1:-1:-1;9464:96:32;-1:-1:-1;9667:2:32;9652:18;;9639:32;;-1:-1:-1;9683:16:32;;;9680:2;;;9717:6;9709;9702:22;9680:2;;9761:72;9825:7;9814:8;9803:9;9799:24;9761:72;:::i;:::-;9247:646;;;;-1:-1:-1;9852:8:32;-1:-1:-1;;;;9247:646:32:o;9898:251::-;9954:6;10007:2;9995:9;9986:7;9982:23;9978:32;9975:2;;;10028:6;10020;10013:22;9975:2;10072:9;10059:23;10091:28;10113:5;10091:28;:::i;10154:255::-;10221:6;10274:2;10262:9;10253:7;10249:23;10245:32;10242:2;;;10295:6;10287;10280:22;10242:2;10332:9;10326:16;10351:28;10373:5;10351:28;:::i;10414:190::-;10473:6;10526:2;10514:9;10505:7;10501:23;10497:32;10494:2;;;10547:6;10539;10532:22;10494:2;-1:-1:-1;10575:23:32;;10484:120;-1:-1:-1;10484:120:32:o;10609:194::-;10679:6;10732:2;10720:9;10711:7;10707:23;10703:32;10700:2;;;10753:6;10745;10738:22;10700:2;-1:-1:-1;10781:16:32;;10690:113;-1:-1:-1;10690:113:32:o;10808:255::-;10887:6;10895;10948:2;10936:9;10927:7;10923:23;10919:32;10916:2;;;10969:6;10961;10954:22;10916:2;-1:-1:-1;;10997:16:32;;11053:2;11038:18;;;11032:25;10997:16;;11032:25;;-1:-1:-1;10906:157:32:o;11068:274::-;11197:3;11235:6;11229:13;11251:53;11297:6;11292:3;11285:4;11277:6;11273:17;11251:53;:::i;:::-;11320:16;;;;;11205:137;-1:-1:-1;;11205:137:32:o;12074:456::-;-1:-1:-1;;;;;12361:15:32;;;12343:34;;12413:15;;;12408:2;12393:18;;12386:43;12465:15;;12460:2;12445:18;;12438:43;12512:2;12497:18;;12490:34;;;;12292:3;12277:19;;12259:271::o;12915:688::-;-1:-1:-1;;;;;13302:15:32;;;13284:34;;13354:15;;;13349:2;13334:18;;13327:43;13401:2;13386:18;;13379:34;;;;13444:2;13429:18;;13422:34;;;;13487:3;13472:19;;13465:35;13537:15;;;13264:3;13516:19;;13509:44;13584:3;13569:19;;13562:35;;;;13233:3;13218:19;;13200:403::o;15366:383::-;15515:2;15504:9;15497:21;15478:4;15547:6;15541:13;15590:6;15585:2;15574:9;15570:18;15563:34;15606:66;15665:6;15660:2;15649:9;15645:18;15640:2;15632:6;15628:15;15606:66;:::i;:::-;15733:2;15712:15;-1:-1:-1;;15708:29:32;15693:45;;;;15740:2;15689:54;;15487:262;-1:-1:-1;;15487:262:32:o;17983:342::-;18185:2;18167:21;;;18224:2;18204:18;;;18197:30;-1:-1:-1;;;18258:2:32;18243:18;;18236:48;18316:2;18301:18;;18157:168::o;20557:356::-;20759:2;20741:21;;;20778:18;;;20771:30;20837:34;20832:2;20817:18;;20810:62;20904:2;20889:18;;20731:182::o;24482:275::-;24553:2;24547:9;24618:2;24599:13;;-1:-1:-1;;24595:27:32;24583:40;;24653:18;24638:34;;24674:22;;;24635:62;24632:2;;;24700:18;;:::i;:::-;24736:2;24729:22;24527:230;;-1:-1:-1;24527:230:32:o;24762:183::-;24822:4;24855:18;24847:6;24844:30;24841:2;;;24877:18;;:::i;:::-;-1:-1:-1;24922:1:32;24918:14;24934:4;24914:25;;24831:114::o;24950:128::-;24990:3;25021:1;25017:6;25014:1;25011:13;25008:2;;;25027:18;;:::i;:::-;-1:-1:-1;25063:9:32;;24998:80::o;25083:217::-;25123:1;25149;25139:2;;-1:-1:-1;;;25174:31:32;;25228:4;25225:1;25218:15;25256:4;25181:1;25246:15;25139:2;-1:-1:-1;25285:9:32;;25129:171::o;25305:168::-;25345:7;25411:1;25407;25403:6;25399:14;25396:1;25393:21;25388:1;25381:9;25374:17;25370:45;25367:2;;;25418:18;;:::i;:::-;-1:-1:-1;25458:9:32;;25357:116::o;25478:125::-;25518:4;25546:1;25543;25540:8;25537:2;;;25551:18;;:::i;:::-;-1:-1:-1;25588:9:32;;25527:76::o;25608:258::-;25680:1;25690:113;25704:6;25701:1;25698:13;25690:113;;;25780:11;;;25774:18;25761:11;;;25754:39;25726:2;25719:10;25690:113;;;25821:6;25818:1;25815:13;25812:2;;;-1:-1:-1;;25856:1:32;25838:16;;25831:27;25661:205::o;25871:135::-;25910:3;-1:-1:-1;;25931:17:32;;25928:2;;;25951:18;;:::i;:::-;-1:-1:-1;25998:1:32;25987:13;;25918:88::o;26011:127::-;26072:10;26067:3;26063:20;26060:1;26053:31;26103:4;26100:1;26093:15;26127:4;26124:1;26117:15;26143:127;26204:10;26199:3;26195:20;26192:1;26185:31;26235:4;26232:1;26225:15;26259:4;26256:1;26249:15;26275:131;-1:-1:-1;;;;;26350:31:32;;26340:42;;26330:2;;26396:1;26393;26386:12;26330:2;26320:86;:::o;26411:118::-;26497:5;26490:13;26483:21;26476:5;26473:32;26463:2;;26519:1;26516;26509:12
Swarm Source
ipfs://4371d265ee1c9d7d75f4283fb42e15df2fd0c6eae192e028972253ead643c178
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.