Source Code
Overview
ETH Balance
0.021718098000055857 ETH
Token Holdings
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 11,913 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Settle | 7241761 | 5 hrs ago | IN | 0 ETH | 0.00233568 | ||||
Settle | 7238548 | 16 hrs ago | IN | 0 ETH | 0.00031739 | ||||
Settle | 7238444 | 17 hrs ago | IN | 0 ETH | 0.00082227 | ||||
Settle | 7238431 | 17 hrs ago | IN | 0 ETH | 0.00064373 | ||||
Settle | 7238395 | 17 hrs ago | IN | 0 ETH | 0.00070547 | ||||
Settle | 7238382 | 17 hrs ago | IN | 0 ETH | 0.0006754 | ||||
Settle | 7236327 | 24 hrs ago | IN | 0 ETH | 0.00044113 | ||||
Settle | 7236180 | 25 hrs ago | IN | 0 ETH | 0.00043959 | ||||
Settle | 7235956 | 26 hrs ago | IN | 0 ETH | 0.00030894 | ||||
Settle | 7235597 | 27 hrs ago | IN | 0 ETH | 0.0000939 | ||||
Settle | 7233530 | 34 hrs ago | IN | 0 ETH | 0.00002131 | ||||
Settle | 7232766 | 37 hrs ago | IN | 0 ETH | 0.00002378 | ||||
Settle | 7232631 | 37 hrs ago | IN | 0 ETH | 0.00002149 | ||||
Settle | 7232596 | 37 hrs ago | IN | 0 ETH | 0.0000215 | ||||
Settle | 7232174 | 39 hrs ago | IN | 0 ETH | 0.00002191 | ||||
Settle | 7231649 | 41 hrs ago | IN | 0 ETH | 0.00003433 | ||||
Settle | 7231624 | 41 hrs ago | IN | 0 ETH | 0.00003491 | ||||
Settle | 7231115 | 43 hrs ago | IN | 0 ETH | 0.0000968 | ||||
Settle | 7229940 | 47 hrs ago | IN | 0 ETH | 0.00033044 | ||||
Settle | 7227090 | 2 days ago | IN | 0 ETH | 0.00002408 | ||||
Settle | 7225792 | 2 days ago | IN | 0 ETH | 0.00003974 | ||||
Settle | 7225759 | 2 days ago | IN | 0 ETH | 0.00004855 | ||||
Settle | 7225752 | 2 days ago | IN | 0 ETH | 0.00006697 | ||||
Settle | 7225120 | 2 days ago | IN | 0 ETH | 0.00198689 | ||||
Settle | 7224980 | 2 days ago | IN | 0 ETH | 0.00040796 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
7233530 | 34 hrs ago | 24.23162744 ETH | ||||
7233530 | 34 hrs ago | 24.23162744 ETH | ||||
7232631 | 37 hrs ago | 0.14576312 ETH | ||||
7232631 | 37 hrs ago | 0.14576312 ETH | ||||
7232596 | 37 hrs ago | 0.14589713 ETH | ||||
7232596 | 37 hrs ago | 0.14589713 ETH | ||||
7232174 | 39 hrs ago | 0.14600868 ETH | ||||
7232174 | 39 hrs ago | 0.14600868 ETH | ||||
7204039 | 5 days ago | 0.09515917 ETH | ||||
7204039 | 5 days ago | 0.09515917 ETH | ||||
7197041 | 6 days ago | 0.12429693 ETH | ||||
7197041 | 6 days ago | 0.12429693 ETH | ||||
7191987 | 7 days ago | 0.06757224 ETH | ||||
7191987 | 7 days ago | 0.06757224 ETH | ||||
7184894 | 8 days ago | 0.231392 ETH | ||||
7184894 | 8 days ago | 0.231392 ETH | ||||
7176855 | 9 days ago | 0.13085682 ETH | ||||
7176855 | 9 days ago | 0.13085682 ETH | ||||
7145714 | 14 days ago | 0.13937289 ETH | ||||
7145714 | 14 days ago | 0.13937289 ETH | ||||
7143856 | 14 days ago | 0.03262254 ETH | ||||
7143856 | 14 days ago | 0.03262254 ETH | ||||
7125723 | 17 days ago | 4.96385849 ETH | ||||
7125723 | 17 days ago | 4.96385849 ETH | ||||
7114595 | 19 days ago | 0.00158103 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
GPv2Settlement
Compiler Version
v0.7.6+commit.7338295f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.7.6; pragma abicoder v2; import "./GPv2VaultRelayer.sol"; import "./interfaces/GPv2Authentication.sol"; import "./interfaces/IERC20.sol"; import "./interfaces/IVault.sol"; import "./libraries/GPv2Interaction.sol"; import "./libraries/GPv2Order.sol"; import "./libraries/GPv2Trade.sol"; import "./libraries/GPv2Transfer.sol"; import "./libraries/SafeCast.sol"; import "./libraries/SafeMath.sol"; import "./mixins/GPv2Signing.sol"; import "./mixins/ReentrancyGuard.sol"; import "./mixins/StorageAccessible.sol"; /// @title Gnosis Protocol v2 Settlement Contract /// @author Gnosis Developers contract GPv2Settlement is GPv2Signing, ReentrancyGuard, StorageAccessible { using GPv2Order for bytes; using GPv2Transfer for IVault; using SafeCast for int256; using SafeCast for uint256; using SafeMath for uint256; /// @dev The authenticator is used to determine who can call the settle function. /// That is, only authorised solvers have the ability to invoke settlements. /// Any valid authenticator implements an isSolver method called by the onlySolver /// modifier below. GPv2Authentication public immutable authenticator; /// @dev The Balancer Vault the protocol uses for managing user funds. IVault public immutable vault; /// @dev The Balancer Vault relayer which can interact on behalf of users. /// This contract is created during deployment GPv2VaultRelayer public immutable vaultRelayer; /// @dev Map each user order by UID to the amount that has been filled so /// far. If this amount is larger than or equal to the amount traded in the /// order (amount sold for sell orders, amount bought for buy orders) then /// the order cannot be traded anymore. If the order is fill or kill, then /// this value is only used to determine whether the order has already been /// executed. mapping(bytes => uint256) public filledAmount; /// @dev Event emitted for each executed trade. event Trade( address indexed owner, IERC20 sellToken, IERC20 buyToken, uint256 sellAmount, uint256 buyAmount, uint256 feeAmount, bytes orderUid ); /// @dev Event emitted for each executed interaction. /// /// For gas effeciency, only the interaction calldata selector (first 4 /// bytes) is included in the event. For interactions without calldata or /// whose calldata is shorter than 4 bytes, the selector will be `0`. event Interaction(address indexed target, uint256 value, bytes4 selector); /// @dev Event emitted when a settlement complets event Settlement(address indexed solver); /// @dev Event emitted when an order is invalidated. event OrderInvalidated(address indexed owner, bytes orderUid); constructor(GPv2Authentication authenticator_, IVault vault_) { authenticator = authenticator_; vault = vault_; vaultRelayer = new GPv2VaultRelayer(vault_); } // solhint-disable-next-line no-empty-blocks receive() external payable { // NOTE: Include an empty receive function so that the settlement // contract can receive Ether from contract interactions. } /// @dev This modifier is called by settle function to block any non-listed /// senders from settling batches. modifier onlySolver { require(authenticator.isSolver(msg.sender), "GPv2: not a solver"); _; } /// @dev Modifier to ensure that an external function is only callable as a /// settlement interaction. modifier onlyInteraction { require(address(this) == msg.sender, "GPv2: not an interaction"); _; } /// @dev Settle the specified orders at a clearing price. Note that it is /// the responsibility of the caller to ensure that all GPv2 invariants are /// upheld for the input settlement, otherwise this call will revert. /// Namely: /// - All orders are valid and signed /// - Accounts have sufficient balance and approval. /// - Settlement contract has sufficient balance to execute trades. Note /// this implies that the accumulated fees held in the contract can also /// be used for settlement. This is OK since: /// - Solvers need to be authorized /// - Misbehaving solvers will be slashed for abusing accumulated fees for /// settlement /// - Critically, user orders are entirely protected /// /// @param tokens An array of ERC20 tokens to be traded in the settlement. /// Trades encode tokens as indices into this array. /// @param clearingPrices An array of clearing prices where the `i`-th price /// is for the `i`-th token in the [`tokens`] array. /// @param trades Trades for signed orders. /// @param interactions Smart contract interactions split into three /// separate lists to be run before the settlement, during the settlement /// and after the settlement respectively. function settle( IERC20[] calldata tokens, uint256[] calldata clearingPrices, GPv2Trade.Data[] calldata trades, GPv2Interaction.Data[][3] calldata interactions ) external nonReentrant onlySolver { executeInteractions(interactions[0]); ( GPv2Transfer.Data[] memory inTransfers, GPv2Transfer.Data[] memory outTransfers ) = computeTradeExecutions(tokens, clearingPrices, trades); vaultRelayer.transferFromAccounts(inTransfers); executeInteractions(interactions[1]); vault.transferToAccounts(outTransfers); executeInteractions(interactions[2]); emit Settlement(msg.sender); } /// @dev Settle an order directly against Balancer V2 pools. /// /// @param swaps The Balancer V2 swap steps to use for trading. /// @param tokens An array of ERC20 tokens to be traded in the settlement. /// Swaps and the trade encode tokens as indices into this array. /// @param trade The trade to match directly against Balancer liquidity. The /// order will always be fully executed, so the trade's `executedAmount` /// field is used to represent a swap limit amount. function swap( IVault.BatchSwapStep[] calldata swaps, IERC20[] calldata tokens, GPv2Trade.Data calldata trade ) external nonReentrant onlySolver { RecoveredOrder memory recoveredOrder = allocateRecoveredOrder(); GPv2Order.Data memory order = recoveredOrder.data; recoverOrderFromTrade(recoveredOrder, tokens, trade); IVault.SwapKind kind = order.kind == GPv2Order.KIND_SELL ? IVault.SwapKind.GIVEN_IN : IVault.SwapKind.GIVEN_OUT; IVault.FundManagement memory funds; funds.sender = recoveredOrder.owner; funds.fromInternalBalance = order.sellTokenBalance == GPv2Order.BALANCE_INTERNAL; funds.recipient = payable(recoveredOrder.receiver); funds.toInternalBalance = order.buyTokenBalance == GPv2Order.BALANCE_INTERNAL; int256[] memory limits = new int256[](tokens.length); uint256 limitAmount = trade.executedAmount; // NOTE: Array allocation initializes elements to 0, so we only need to // set the limits we care about. This ensures that the swap will respect // the order's limit price. if (order.kind == GPv2Order.KIND_SELL) { require(limitAmount >= order.buyAmount, "GPv2: limit too low"); limits[trade.sellTokenIndex] = order.sellAmount.toInt256(); limits[trade.buyTokenIndex] = -limitAmount.toInt256(); } else { require(limitAmount <= order.sellAmount, "GPv2: limit too high"); limits[trade.sellTokenIndex] = limitAmount.toInt256(); limits[trade.buyTokenIndex] = -order.buyAmount.toInt256(); } GPv2Transfer.Data memory feeTransfer; feeTransfer.account = recoveredOrder.owner; feeTransfer.token = order.sellToken; feeTransfer.amount = order.feeAmount; feeTransfer.balance = order.sellTokenBalance; int256[] memory tokenDeltas = vaultRelayer.batchSwapWithFee( kind, swaps, tokens, funds, limits, // NOTE: Specify a deadline to ensure that an expire order // cannot be used to trade. order.validTo, feeTransfer ); bytes memory orderUid = recoveredOrder.uid; uint256 executedSellAmount = tokenDeltas[trade.sellTokenIndex].toUint256(); uint256 executedBuyAmount = (-tokenDeltas[trade.buyTokenIndex]).toUint256(); // NOTE: Check that the orders were completely filled and update their // filled amounts to avoid replaying them. The limit price and order // validity have already been verified when executing the swap through // the `limit` and `deadline` parameters. require(filledAmount[orderUid] == 0, "GPv2: order filled"); if (order.kind == GPv2Order.KIND_SELL) { require( executedSellAmount == order.sellAmount, "GPv2: sell amount not respected" ); filledAmount[orderUid] = order.sellAmount; } else { require( executedBuyAmount == order.buyAmount, "GPv2: buy amount not respected" ); filledAmount[orderUid] = order.buyAmount; } emit Trade( recoveredOrder.owner, order.sellToken, order.buyToken, executedSellAmount, executedBuyAmount, order.feeAmount, orderUid ); emit Settlement(msg.sender); } /// @dev Invalidate onchain an order that has been signed offline. /// /// @param orderUid The unique identifier of the order that is to be made /// invalid after calling this function. The user that created the order /// must be the the sender of this message. See [`extractOrderUidParams`] /// for details on orderUid. function invalidateOrder(bytes calldata orderUid) external { (, address owner, ) = orderUid.extractOrderUidParams(); require(owner == msg.sender, "GPv2: caller does not own order"); filledAmount[orderUid] = uint256(-1); emit OrderInvalidated(owner, orderUid); } /// @dev Free storage from the filled amounts of **expired** orders to claim /// a gas refund. This method can only be called as an interaction. /// /// @param orderUids The unique identifiers of the expired order to free /// storage for. function freeFilledAmountStorage(bytes[] calldata orderUids) external onlyInteraction { freeOrderStorage(filledAmount, orderUids); } /// @dev Free storage from the pre signatures of **expired** orders to claim /// a gas refund. This method can only be called as an interaction. /// /// @param orderUids The unique identifiers of the expired order to free /// storage for. function freePreSignatureStorage(bytes[] calldata orderUids) external onlyInteraction { freeOrderStorage(preSignature, orderUids); } /// @dev Process all trades one at a time returning the computed net in and /// out transfers for the trades. /// /// This method reverts if processing of any single trade fails. See /// [`computeTradeExecution`] for more details. /// /// @param tokens An array of ERC20 tokens to be traded in the settlement. /// @param clearingPrices An array of token clearing prices. /// @param trades Trades for signed orders. /// @return inTransfers Array of in transfers of executed sell amounts. /// @return outTransfers Array of out transfers of executed buy amounts. function computeTradeExecutions( IERC20[] calldata tokens, uint256[] calldata clearingPrices, GPv2Trade.Data[] calldata trades ) internal returns ( GPv2Transfer.Data[] memory inTransfers, GPv2Transfer.Data[] memory outTransfers ) { RecoveredOrder memory recoveredOrder = allocateRecoveredOrder(); inTransfers = new GPv2Transfer.Data[](trades.length); outTransfers = new GPv2Transfer.Data[](trades.length); for (uint256 i = 0; i < trades.length; i++) { GPv2Trade.Data calldata trade = trades[i]; recoverOrderFromTrade(recoveredOrder, tokens, trade); computeTradeExecution( recoveredOrder, clearingPrices[trade.sellTokenIndex], clearingPrices[trade.buyTokenIndex], trade.executedAmount, inTransfers[i], outTransfers[i] ); } } /// @dev Compute the in and out transfer amounts for a single trade. /// This function reverts if: /// - The order has expired /// - The order's limit price is not respected /// - The order gets over-filled /// - The fee discount is larger than the executed fee /// /// @param recoveredOrder The recovered order to process. /// @param sellPrice The price of the order's sell token. /// @param buyPrice The price of the order's buy token. /// @param executedAmount The portion of the order to execute. This will be /// ignored for fill-or-kill orders. /// @param inTransfer Memory location for computed executed sell amount /// transfer. /// @param outTransfer Memory location for computed executed buy amount /// transfer. function computeTradeExecution( RecoveredOrder memory recoveredOrder, uint256 sellPrice, uint256 buyPrice, uint256 executedAmount, GPv2Transfer.Data memory inTransfer, GPv2Transfer.Data memory outTransfer ) internal { GPv2Order.Data memory order = recoveredOrder.data; bytes memory orderUid = recoveredOrder.uid; // solhint-disable-next-line not-rely-on-time require(order.validTo >= block.timestamp, "GPv2: order expired"); // NOTE: The following computation is derived from the equation: // ``` // amount_x * price_x = amount_y * price_y // ``` // Intuitively, if a chocolate bar is 0,50€ and a beer is 4€, 1 beer // is roughly worth 8 chocolate bars (`1 * 4 = 8 * 0.5`). From this // equation, we can derive: // - The limit price for selling `x` and buying `y` is respected iff // ``` // limit_x * price_x >= limit_y * price_y // ``` // - The executed amount of token `y` given some amount of `x` and // clearing prices is: // ``` // amount_y = amount_x * price_x / price_y // ``` require( order.sellAmount.mul(sellPrice) >= order.buyAmount.mul(buyPrice), "GPv2: limit price not respected" ); uint256 executedSellAmount; uint256 executedBuyAmount; uint256 executedFeeAmount; uint256 currentFilledAmount; if (order.kind == GPv2Order.KIND_SELL) { if (order.partiallyFillable) { executedSellAmount = executedAmount; executedFeeAmount = order.feeAmount.mul(executedSellAmount).div( order.sellAmount ); } else { executedSellAmount = order.sellAmount; executedFeeAmount = order.feeAmount; } executedBuyAmount = executedSellAmount.mul(sellPrice).ceilDiv( buyPrice ); currentFilledAmount = filledAmount[orderUid].add( executedSellAmount ); require( currentFilledAmount <= order.sellAmount, "GPv2: order filled" ); } else { if (order.partiallyFillable) { executedBuyAmount = executedAmount; executedFeeAmount = order.feeAmount.mul(executedBuyAmount).div( order.buyAmount ); } else { executedBuyAmount = order.buyAmount; executedFeeAmount = order.feeAmount; } executedSellAmount = executedBuyAmount.mul(buyPrice).div(sellPrice); currentFilledAmount = filledAmount[orderUid].add(executedBuyAmount); require( currentFilledAmount <= order.buyAmount, "GPv2: order filled" ); } executedSellAmount = executedSellAmount.add(executedFeeAmount); filledAmount[orderUid] = currentFilledAmount; emit Trade( recoveredOrder.owner, order.sellToken, order.buyToken, executedSellAmount, executedBuyAmount, executedFeeAmount, orderUid ); inTransfer.account = recoveredOrder.owner; inTransfer.token = order.sellToken; inTransfer.amount = executedSellAmount; inTransfer.balance = order.sellTokenBalance; outTransfer.account = recoveredOrder.receiver; outTransfer.token = order.buyToken; outTransfer.amount = executedBuyAmount; outTransfer.balance = order.buyTokenBalance; } /// @dev Execute a list of arbitrary contract calls from this contract. /// @param interactions The list of interactions to execute. function executeInteractions(GPv2Interaction.Data[] calldata interactions) internal { for (uint256 i; i < interactions.length; i++) { GPv2Interaction.Data calldata interaction = interactions[i]; // To prevent possible attack on user funds, we explicitly disable // any interactions with the vault relayer contract. require( interaction.target != address(vaultRelayer), "GPv2: forbidden interaction" ); GPv2Interaction.execute(interaction); emit Interaction( interaction.target, interaction.value, GPv2Interaction.selector(interaction) ); } } /// @dev Claims refund for the specified storage and order UIDs. /// /// This method reverts if any of the orders are still valid. /// /// @param orderUids Order refund data for freeing storage. /// @param orderStorage Order storage mapped on a UID. function freeOrderStorage( mapping(bytes => uint256) storage orderStorage, bytes[] calldata orderUids ) internal { for (uint256 i = 0; i < orderUids.length; i++) { bytes calldata orderUid = orderUids[i]; (, , uint32 validTo) = orderUid.extractOrderUidParams(); // solhint-disable-next-line not-rely-on-time require(validTo < block.timestamp, "GPv2: order still valid"); orderStorage[orderUid] = 0; } } }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.7.6; pragma abicoder v2; import "./interfaces/IERC20.sol"; import "./interfaces/IVault.sol"; import "./libraries/GPv2Transfer.sol"; /// @title Gnosis Protocol v2 Vault Relayer Contract /// @author Gnosis Developers contract GPv2VaultRelayer { using GPv2Transfer for IVault; /// @dev The creator of the contract which has special permissions. This /// value is set at creation time and cannot change. address private immutable creator; /// @dev The vault this relayer is for. IVault private immutable vault; constructor(IVault vault_) { creator = msg.sender; vault = vault_; } /// @dev Modifier that ensures that a function can only be called by the /// creator of this contract. modifier onlyCreator { require(msg.sender == creator, "GPv2: not creator"); _; } /// @dev Transfers all sell amounts for the executed trades from their /// owners to the caller. /// /// This function reverts if: /// - The caller is not the creator of the vault relayer /// - Any ERC20 transfer fails /// /// @param transfers The transfers to execute. function transferFromAccounts(GPv2Transfer.Data[] calldata transfers) external onlyCreator { vault.transferFromAccounts(transfers, msg.sender); } /// @dev Performs a Balancer batched swap on behalf of a user and sends a /// fee to the caller. /// /// This function reverts if: /// - The caller is not the creator of the vault relayer /// - The swap fails /// - The fee transfer fails /// /// @param kind The Balancer swap kind, this can either be `GIVEN_IN` for /// sell orders or `GIVEN_OUT` for buy orders. /// @param swaps The swaps to perform. /// @param tokens The tokens for the swaps. Swaps encode to and from tokens /// as indices into this array. /// @param funds The fund management settings, specifying the user the swap /// is being performed for as well as the recipient of the proceeds. /// @param limits Swap limits for encoding limit prices. /// @param deadline The deadline for the swap. /// @param feeTransfer The transfer data for the caller fee. /// @return tokenDeltas The executed swap amounts. function batchSwapWithFee( IVault.SwapKind kind, IVault.BatchSwapStep[] calldata swaps, IERC20[] memory tokens, IVault.FundManagement memory funds, int256[] memory limits, uint256 deadline, GPv2Transfer.Data calldata feeTransfer ) external onlyCreator returns (int256[] memory tokenDeltas) { tokenDeltas = vault.batchSwap( kind, swaps, tokens, funds, limits, deadline ); vault.fastTransferFromAccount(feeTransfer, msg.sender); } }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.7.6; /// @title Gnosis Protocol v2 Authentication Interface /// @author Gnosis Developers interface GPv2Authentication { /// @dev determines whether the provided address is an authenticated solver. /// @param prospectiveSolver the address of prospective solver. /// @return true when prospectiveSolver is an authenticated solver, otherwise false. function isSolver(address prospectiveSolver) external view returns (bool); }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.7.6; library GPv2EIP1271 { /// @dev Value returned by a call to `isValidSignature` if the signature /// was verified successfully. The value is defined in EIP-1271 as: /// bytes4(keccak256("isValidSignature(bytes32,bytes)")) bytes4 internal constant MAGICVALUE = 0x1626ba7e; } /// @title EIP1271 Interface /// @dev Standardized interface for an implementation of smart contract /// signatures as described in EIP-1271. The code that follows is identical to /// the code in the standard with the exception of formatting and syntax /// changes to adapt the code to our Solidity version. interface EIP1271Verifier { /// @dev Should return whether the signature provided is valid for the /// provided data /// @param _hash Hash of the data to be signed /// @param _signature Signature byte array associated with _data /// /// MUST return the bytes4 magic value 0x1626ba7e when function passes. /// MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for /// solc > 0.5) /// MUST allow external calls /// function isValidSignature(bytes32 _hash, bytes memory _signature) external view returns (bytes4 magicValue); }
// SPDX-License-Identifier: MIT // Vendored from OpenZeppelin contracts with minor modifications: // - Modified Solidity version // - Formatted code // - Added `name`, `symbol` and `decimals` function declarations // <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/token/ERC20/IERC20.sol> pragma solidity ^0.7.6; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface 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 number of decimals the token uses. */ function decimals() external view returns (uint8); /** * @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: GPL-3.0-or-later // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 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 General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. pragma solidity ^0.7.6; pragma abicoder v2; import "./IERC20.sol"; /** * @dev Minimal interface for the Vault core contract only containing methods * used by Gnosis Protocol V2. Original source: * <https://github.com/balancer-labs/balancer-core-v2/blob/v1.0.0/contracts/vault/interfaces/IVault.sol> */ interface IVault { // Internal Balance // // Users can deposit tokens into the Vault, where they are allocated to their Internal Balance, and later // transferred or withdrawn. It can also be used as a source of tokens when joining Pools, as a destination // when exiting them, and as either when performing swaps. This usage of Internal Balance results in greatly reduced // gas costs when compared to relying on plain ERC20 transfers, leading to large savings for frequent users. // // Internal Balance management features batching, which means a single contract call can be used to perform multiple // operations of different kinds, with different senders and recipients, at once. /** * @dev Performs a set of user balance operations, which involve Internal Balance (deposit, withdraw or transfer) * and plain ERC20 transfers using the Vault's allowance. This last feature is particularly useful for relayers, as * it lets integrators reuse a user's Vault allowance. * * For each operation, if the caller is not `sender`, it must be an authorized relayer for them. */ function manageUserBalance(UserBalanceOp[] memory ops) external payable; /** * @dev Data for `manageUserBalance` operations, which include the possibility for ETH to be sent and received without manual WETH wrapping or unwrapping. */ struct UserBalanceOp { UserBalanceOpKind kind; IERC20 asset; uint256 amount; address sender; address payable recipient; } // There are four possible operations in `manageUserBalance`: // // - DEPOSIT_INTERNAL // Increases the Internal Balance of the `recipient` account by transferring tokens from the corresponding // `sender`. The sender must have allowed the Vault to use their tokens via `IERC20.approve()`. // // ETH can be used by passing the ETH sentinel value as the asset and forwarding ETH in the call: it will be wrapped // and deposited as WETH. Any ETH amount remaining will be sent back to the caller (not the sender, which is // relevant for relayers). // // Emits an `InternalBalanceChanged` event. // // // - WITHDRAW_INTERNAL // Decreases the Internal Balance of the `sender` account by transferring tokens to the `recipient`. // // ETH can be used by passing the ETH sentinel value as the asset. This will deduct WETH instead, unwrap it and send // it to the recipient as ETH. // // Emits an `InternalBalanceChanged` event. // // // - TRANSFER_INTERNAL // Transfers tokens from the Internal Balance of the `sender` account to the Internal Balance of `recipient`. // // Reverts if the ETH sentinel value is passed. // // Emits an `InternalBalanceChanged` event. // // // - TRANSFER_EXTERNAL // Transfers tokens from `sender` to `recipient`, using the Vault's ERC20 allowance. This is typically used by // relayers, as it lets them reuse a user's Vault allowance. // // Reverts if the ETH sentinel value is passed. // // Emits an `ExternalBalanceTransfer` event. enum UserBalanceOpKind { DEPOSIT_INTERNAL, WITHDRAW_INTERNAL, TRANSFER_INTERNAL, TRANSFER_EXTERNAL } // Swaps // // Users can swap tokens with Pools by calling the `swap` and `batchSwap` functions. To do this, // they need not trust Pool contracts in any way: all security checks are made by the Vault. They must however be // aware of the Pools' pricing algorithms in order to estimate the prices Pools will quote. // // The `swap` function executes a single swap, while `batchSwap` can perform multiple swaps in sequence. // In each individual swap, tokens of one kind are sent from the sender to the Pool (this is the 'token in'), // and tokens of another kind are sent from the Pool to the recipient in exchange (this is the 'token out'). // More complex swaps, such as one token in to multiple tokens out can be achieved by batching together // individual swaps. // // There are two swap kinds: // - 'given in' swaps, where the amount of tokens in (sent to the Pool) is known, and the Pool determines (via the // `onSwap` hook) the amount of tokens out (to send to the recipient). // - 'given out' swaps, where the amount of tokens out (received from the Pool) is known, and the Pool determines // (via the `onSwap` hook) the amount of tokens in (to receive from the sender). // // Additionally, it is possible to chain swaps using a placeholder input amount, which the Vault replaces with // the calculated output of the previous swap. If the previous swap was 'given in', this will be the calculated // tokenOut amount. If the previous swap was 'given out', it will use the calculated tokenIn amount. These extended // swaps are known as 'multihop' swaps, since they 'hop' through a number of intermediate tokens before arriving at // the final intended token. // // In all cases, tokens are only transferred in and out of the Vault (or withdrawn from and deposited into Internal // Balance) after all individual swaps have been completed, and the net token balance change computed. This makes // certain swap patterns, such as multihops, or swaps that interact with the same token pair in multiple Pools, cost // much less gas than they would otherwise. // // It also means that under certain conditions it is possible to perform arbitrage by swapping with multiple // Pools in a way that results in net token movement out of the Vault (profit), with no tokens being sent in (only // updating the Pool's internal accounting). // // To protect users from front-running or the market changing rapidly, they supply a list of 'limits' for each token // involved in the swap, where either the maximum number of tokens to send (by passing a positive value) or the // minimum amount of tokens to receive (by passing a negative value) is specified. // // Additionally, a 'deadline' timestamp can also be provided, forcing the swap to fail if it occurs after // this point in time (e.g. if the transaction failed to be included in a block promptly). // // If interacting with Pools that hold WETH, it is possible to both send and receive ETH directly: the Vault will do // the wrapping and unwrapping. To enable this mechanism, the IAsset sentinel value (the zero address) must be // passed in the `assets` array instead of the WETH address. Note that it is possible to combine ETH and WETH in the // same swap. Any excess ETH will be sent back to the caller (not the sender, which is relevant for relayers). // // Finally, Internal Balance can be used when either sending or receiving tokens. enum SwapKind {GIVEN_IN, GIVEN_OUT} /** * @dev Performs a swap with a single Pool. * * If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens * taken from the Pool, which must be greater than or equal to `limit`. * * If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens * sent to the Pool, which must be less than or equal to `limit`. * * Internal Balance usage and the recipient are determined by the `funds` struct. * * Emits a `Swap` event. */ function swap( SingleSwap memory singleSwap, FundManagement memory funds, uint256 limit, uint256 deadline ) external payable returns (uint256); /** * @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on * the `kind` value. * * `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address). * Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault. * * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be * used to extend swap behavior. */ struct SingleSwap { bytes32 poolId; SwapKind kind; IERC20 assetIn; IERC20 assetOut; uint256 amount; bytes userData; } /** * @dev Performs a series of swaps with one or multiple Pools. In each individual swap, the caller determines either * the amount of tokens sent to or received from the Pool, depending on the `kind` value. * * Returns an array with the net Vault asset balance deltas. Positive amounts represent tokens (or ETH) sent to the * Vault, and negative amounts represent tokens (or ETH) sent by the Vault. Each delta corresponds to the asset at * the same index in the `assets` array. * * Swaps are executed sequentially, in the order specified by the `swaps` array. Each array element describes a * Pool, the token to be sent to this Pool, the token to receive from it, and an amount that is either `amountIn` or * `amountOut` depending on the swap kind. * * Multihop swaps can be executed by passing an `amount` value of zero for a swap. This will cause the amount in/out * of the previous swap to be used as the amount in for the current one. In a 'given in' swap, 'tokenIn' must equal * the previous swap's `tokenOut`. For a 'given out' swap, `tokenOut` must equal the previous swap's `tokenIn`. * * The `assets` array contains the addresses of all assets involved in the swaps. These are either token addresses, * or the IAsset sentinel value for ETH (the zero address). Each entry in the `swaps` array specifies tokens in and * out by referencing an index in `assets`. Note that Pools never interact with ETH directly: it will be wrapped to * or unwrapped from WETH by the Vault. * * Internal Balance usage, sender, and recipient are determined by the `funds` struct. The `limits` array specifies * the minimum or maximum amount of each token the vault is allowed to transfer. * * `batchSwap` can be used to make a single swap, like `swap` does, but doing so requires more gas than the * equivalent `swap` call. * * Emits `Swap` events. */ function batchSwap( SwapKind kind, BatchSwapStep[] memory swaps, IERC20[] memory assets, FundManagement memory funds, int256[] memory limits, uint256 deadline ) external payable returns (int256[] memory); /** * @dev Data for each individual swap executed by `batchSwap`. The asset in and out fields are indexes into the * `assets` array passed to that function, and ETH assets are converted to WETH. * * If `amount` is zero, the multihop mechanism is used to determine the actual amount based on the amount in/out * from the previous swap, depending on the swap kind. * * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be * used to extend swap behavior. */ struct BatchSwapStep { bytes32 poolId; uint256 assetInIndex; uint256 assetOutIndex; uint256 amount; bytes userData; } /** * @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the * `recipient` account. * * If the caller is not `sender`, it must be an authorized relayer for them. * * If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20 * transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender` * must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of * `joinPool`. * * If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of * transferred. This matches the behavior of `exitPool`. * * Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a * revert. */ struct FundManagement { address sender; bool fromInternalBalance; address payable recipient; bool toInternalBalance; } }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.7.6; /// @title Gnosis Protocol v2 Interaction Library /// @author Gnosis Developers library GPv2Interaction { /// @dev Interaction data for performing arbitrary contract interactions. /// Submitted to [`GPv2Settlement.settle`] for code execution. struct Data { address target; uint256 value; bytes callData; } /// @dev Execute an arbitrary contract interaction. /// /// @param interaction Interaction data. function execute(Data calldata interaction) internal { address target = interaction.target; uint256 value = interaction.value; bytes calldata callData = interaction.callData; // NOTE: Use assembly to call the interaction instead of a low level // call for two reasons: // - We don't want to copy the return data, since we discard it for // interactions. // - Solidity will under certain conditions generate code to copy input // calldata twice to memory (the second being a "memcopy loop"). // <https://github.com/gnosis/gp-v2-contracts/pull/417#issuecomment-775091258> // solhint-disable-next-line no-inline-assembly assembly { let freeMemoryPointer := mload(0x40) calldatacopy(freeMemoryPointer, callData.offset, callData.length) if iszero( call( gas(), target, value, freeMemoryPointer, callData.length, 0, 0 ) ) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } } /// @dev Extracts the Solidity ABI selector for the specified interaction. /// /// @param interaction Interaction data. /// @return result The 4 byte function selector of the call encoded in /// this interaction. function selector(Data calldata interaction) internal pure returns (bytes4 result) { bytes calldata callData = interaction.callData; if (callData.length >= 4) { // NOTE: Read the first word of the interaction's calldata. The // value does not need to be shifted since `bytesN` values are left // aligned, and the value does not need to be masked since masking // occurs when the value is accessed and not stored: // <https://docs.soliditylang.org/en/v0.7.6/abi-spec.html#encoding-of-indexed-event-parameters> // <https://docs.soliditylang.org/en/v0.7.6/assembly.html#access-to-external-variables-functions-and-libraries> // solhint-disable-next-line no-inline-assembly assembly { result := calldataload(callData.offset) } } } }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.7.6; import "../interfaces/IERC20.sol"; /// @title Gnosis Protocol v2 Order Library /// @author Gnosis Developers library GPv2Order { /// @dev The complete data for a Gnosis Protocol order. This struct contains /// all order parameters that are signed for submitting to GP. struct Data { IERC20 sellToken; IERC20 buyToken; address receiver; uint256 sellAmount; uint256 buyAmount; uint32 validTo; bytes32 appData; uint256 feeAmount; bytes32 kind; bool partiallyFillable; bytes32 sellTokenBalance; bytes32 buyTokenBalance; } /// @dev The order EIP-712 type hash for the [`GPv2Order.Data`] struct. /// /// This value is pre-computed from the following expression: /// ``` /// keccak256( /// "Order(" + /// "address sellToken," + /// "address buyToken," + /// "address receiver," + /// "uint256 sellAmount," + /// "uint256 buyAmount," + /// "uint32 validTo," + /// "bytes32 appData," + /// "uint256 feeAmount," + /// "string kind," + /// "bool partiallyFillable" + /// "string sellTokenBalance" + /// "string buyTokenBalance" + /// ")" /// ) /// ``` bytes32 internal constant TYPE_HASH = hex"d5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e489"; /// @dev The marker value for a sell order for computing the order struct /// hash. This allows the EIP-712 compatible wallets to display a /// descriptive string for the order kind (instead of 0 or 1). /// /// This value is pre-computed from the following expression: /// ``` /// keccak256("sell") /// ``` bytes32 internal constant KIND_SELL = hex"f3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775"; /// @dev The OrderKind marker value for a buy order for computing the order /// struct hash. /// /// This value is pre-computed from the following expression: /// ``` /// keccak256("buy") /// ``` bytes32 internal constant KIND_BUY = hex"6ed88e868af0a1983e3886d5f3e95a2fafbd6c3450bc229e27342283dc429ccc"; /// @dev The TokenBalance marker value for using direct ERC20 balances for /// computing the order struct hash. /// /// This value is pre-computed from the following expression: /// ``` /// keccak256("erc20") /// ``` bytes32 internal constant BALANCE_ERC20 = hex"5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9"; /// @dev The TokenBalance marker value for using Balancer Vault external /// balances (in order to re-use Vault ERC20 approvals) for computing the /// order struct hash. /// /// This value is pre-computed from the following expression: /// ``` /// keccak256("external") /// ``` bytes32 internal constant BALANCE_EXTERNAL = hex"abee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea0632"; /// @dev The TokenBalance marker value for using Balancer Vault internal /// balances for computing the order struct hash. /// /// This value is pre-computed from the following expression: /// ``` /// keccak256("internal") /// ``` bytes32 internal constant BALANCE_INTERNAL = hex"4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce"; /// @dev Marker address used to indicate that the receiver of the trade /// proceeds should the owner of the order. /// /// This is chosen to be `address(0)` for gas efficiency as it is expected /// to be the most common case. address internal constant RECEIVER_SAME_AS_OWNER = address(0); /// @dev The byte length of an order unique identifier. uint256 internal constant UID_LENGTH = 56; /// @dev Returns the actual receiver for an order. This function checks /// whether or not the [`receiver`] field uses the marker value to indicate /// it is the same as the order owner. /// /// @return receiver The actual receiver of trade proceeds. function actualReceiver(Data memory order, address owner) internal pure returns (address receiver) { if (order.receiver == RECEIVER_SAME_AS_OWNER) { receiver = owner; } else { receiver = order.receiver; } } /// @dev Return the EIP-712 signing hash for the specified order. /// /// @param order The order to compute the EIP-712 signing hash for. /// @param domainSeparator The EIP-712 domain separator to use. /// @return orderDigest The 32 byte EIP-712 struct hash. function hash(Data memory order, bytes32 domainSeparator) internal pure returns (bytes32 orderDigest) { bytes32 structHash; // NOTE: Compute the EIP-712 order struct hash in place. As suggested // in the EIP proposal, noting that the order struct has 10 fields, and // including the type hash `(12 + 1) * 32 = 416` bytes to hash. // <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#rationale-for-encodedata> // solhint-disable-next-line no-inline-assembly assembly { let dataStart := sub(order, 32) let temp := mload(dataStart) mstore(dataStart, TYPE_HASH) structHash := keccak256(dataStart, 416) mstore(dataStart, temp) } // NOTE: Now that we have the struct hash, compute the EIP-712 signing // hash using scratch memory past the free memory pointer. The signing // hash is computed from `"\x19\x01" || domainSeparator || structHash`. // <https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html#layout-in-memory> // <https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md#specification> // solhint-disable-next-line no-inline-assembly assembly { let freeMemoryPointer := mload(0x40) mstore(freeMemoryPointer, "\x19\x01") mstore(add(freeMemoryPointer, 2), domainSeparator) mstore(add(freeMemoryPointer, 34), structHash) orderDigest := keccak256(freeMemoryPointer, 66) } } /// @dev Packs order UID parameters into the specified memory location. The /// result is equivalent to `abi.encodePacked(...)` with the difference that /// it allows re-using the memory for packing the order UID. /// /// This function reverts if the order UID buffer is not the correct size. /// /// @param orderUid The buffer pack the order UID parameters into. /// @param orderDigest The EIP-712 struct digest derived from the order /// parameters. /// @param owner The address of the user who owns this order. /// @param validTo The epoch time at which the order will stop being valid. function packOrderUidParams( bytes memory orderUid, bytes32 orderDigest, address owner, uint32 validTo ) internal pure { require(orderUid.length == UID_LENGTH, "GPv2: uid buffer overflow"); // NOTE: Write the order UID to the allocated memory buffer. The order // parameters are written to memory in **reverse order** as memory // operations write 32-bytes at a time and we want to use a packed // encoding. This means, for example, that after writing the value of // `owner` to bytes `20:52`, writing the `orderDigest` to bytes `0:32` // will **overwrite** bytes `20:32`. This is desirable as addresses are // only 20 bytes and `20:32` should be `0`s: // // | 1111111111222222222233333333334444444444555555 // byte | 01234567890123456789012345678901234567890123456789012345 // -------+--------------------------------------------------------- // field | [.........orderDigest..........][......owner.......][vT] // -------+--------------------------------------------------------- // mstore | [000000000000000000000000000.vT] // | [00000000000.......owner.......] // | [.........orderDigest..........] // // Additionally, since Solidity `bytes memory` are length prefixed, // 32 needs to be added to all the offsets. // // solhint-disable-next-line no-inline-assembly assembly { mstore(add(orderUid, 56), validTo) mstore(add(orderUid, 52), owner) mstore(add(orderUid, 32), orderDigest) } } /// @dev Extracts specific order information from the standardized unique /// order id of the protocol. /// /// @param orderUid The unique identifier used to represent an order in /// the protocol. This uid is the packed concatenation of the order digest, /// the validTo order parameter and the address of the user who created the /// order. It is used by the user to interface with the contract directly, /// and not by calls that are triggered by the solvers. /// @return orderDigest The EIP-712 signing digest derived from the order /// parameters. /// @return owner The address of the user who owns this order. /// @return validTo The epoch time at which the order will stop being valid. function extractOrderUidParams(bytes calldata orderUid) internal pure returns ( bytes32 orderDigest, address owner, uint32 validTo ) { require(orderUid.length == UID_LENGTH, "GPv2: invalid uid"); // Use assembly to efficiently decode packed calldata. // solhint-disable-next-line no-inline-assembly assembly { orderDigest := calldataload(orderUid.offset) owner := shr(96, calldataload(add(orderUid.offset, 32))) validTo := shr(224, calldataload(add(orderUid.offset, 52))) } } }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.7.6; import "../interfaces/IERC20.sol"; /// @title Gnosis Protocol v2 Safe ERC20 Transfer Library /// @author Gnosis Developers /// @dev Gas-efficient version of Openzeppelin's SafeERC20 contract that notably /// does not revert when calling a non-contract. library GPv2SafeERC20 { /// @dev Wrapper around a call to the ERC20 function `transfer` that reverts /// also when the token returns `false`. function safeTransfer( IERC20 token, address to, uint256 value ) internal { bytes4 selector_ = token.transfer.selector; // solhint-disable-next-line no-inline-assembly assembly { let freeMemoryPointer := mload(0x40) mstore(freeMemoryPointer, selector_) mstore( add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff) ) mstore(add(freeMemoryPointer, 36), value) if iszero(call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } require(getLastTansferResult(token), "GPv2: failed transfer"); } /// @dev Wrapper around a call to the ERC20 function `transferFrom` that /// reverts also when the token returns `false`. function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { bytes4 selector_ = token.transferFrom.selector; // solhint-disable-next-line no-inline-assembly assembly { let freeMemoryPointer := mload(0x40) mstore(freeMemoryPointer, selector_) mstore( add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff) ) mstore( add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff) ) mstore(add(freeMemoryPointer, 68), value) if iszero(call(gas(), token, 0, freeMemoryPointer, 100, 0, 0)) { returndatacopy(0, 0, returndatasize()) revert(0, returndatasize()) } } require(getLastTansferResult(token), "GPv2: failed transferFrom"); } /// @dev Verifies that the last return was a successful `transfer*` call. /// This is done by checking that the return data is either empty, or /// is a valid ABI encoded boolean. function getLastTansferResult(IERC20 token) private view returns (bool success) { // NOTE: Inspecting previous return data requires assembly. Note that // we write the return data to memory 0 in the case where the return // data size is 32, this is OK since the first 64 bytes of memory are // reserved by Solidy as a scratch space that can be used within // assembly blocks. // <https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html> // solhint-disable-next-line no-inline-assembly assembly { /// @dev Revert with an ABI encoded Solidity error with a message /// that fits into 32-bytes. /// /// An ABI encoded Solidity error has the following memory layout: /// /// ------------+---------------------------------- /// byte range | value /// ------------+---------------------------------- /// 0x00..0x04 | selector("Error(string)") /// 0x04..0x24 | string offset (always 0x20) /// 0x24..0x44 | string length /// 0x44..0x64 | string value, padded to 32-bytes function revertWithMessage(length, message) { mstore(0x00, "\x08\xc3\x79\xa0") mstore(0x04, 0x20) mstore(0x24, length) mstore(0x44, message) revert(0x00, 0x64) } switch returndatasize() // Non-standard ERC20 transfer without return. case 0 { // NOTE: When the return data size is 0, verify that there // is code at the address. This is done in order to maintain // compatibility with Solidity calling conventions. // <https://docs.soliditylang.org/en/v0.7.6/control-structures.html#external-function-calls> if iszero(extcodesize(token)) { revertWithMessage(20, "GPv2: not a contract") } success := 1 } // Standard ERC20 transfer returning boolean success value. case 32 { returndatacopy(0, 0, returndatasize()) // NOTE: For ABI encoding v1, any non-zero value is accepted // as `true` for a boolean. In order to stay compatible with // OpenZeppelin's `SafeERC20` library which is known to work // with the existing ERC20 implementation we care about, // make sure we return success for any non-zero return value // from the `transfer*` call. success := iszero(iszero(mload(0))) } default { revertWithMessage(31, "GPv2: malformed transfer result") } } } }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.7.6; import "../interfaces/IERC20.sol"; import "../mixins/GPv2Signing.sol"; import "./GPv2Order.sol"; /// @title Gnosis Protocol v2 Trade Library. /// @author Gnosis Developers library GPv2Trade { using GPv2Order for GPv2Order.Data; using GPv2Order for bytes; /// @dev A struct representing a trade to be executed as part a batch /// settlement. struct Data { uint256 sellTokenIndex; uint256 buyTokenIndex; address receiver; uint256 sellAmount; uint256 buyAmount; uint32 validTo; bytes32 appData; uint256 feeAmount; uint256 flags; uint256 executedAmount; bytes signature; } /// @dev Extracts the order data and signing scheme for the specified trade. /// /// @param trade The trade. /// @param tokens The list of tokens included in the settlement. The token /// indices in the trade parameters map to tokens in this array. /// @param order The memory location to extract the order data to. function extractOrder( Data calldata trade, IERC20[] calldata tokens, GPv2Order.Data memory order ) internal pure returns (GPv2Signing.Scheme signingScheme) { order.sellToken = tokens[trade.sellTokenIndex]; order.buyToken = tokens[trade.buyTokenIndex]; order.receiver = trade.receiver; order.sellAmount = trade.sellAmount; order.buyAmount = trade.buyAmount; order.validTo = trade.validTo; order.appData = trade.appData; order.feeAmount = trade.feeAmount; ( order.kind, order.partiallyFillable, order.sellTokenBalance, order.buyTokenBalance, signingScheme ) = extractFlags(trade.flags); } /// @dev Decodes trade flags. /// /// Trade flags are used to tightly encode information on how to decode /// an order. Examples that directly affect the structure of an order are /// the kind of order (either a sell or a buy order) as well as whether the /// order is partially fillable or if it is a "fill-or-kill" order. It also /// encodes the signature scheme used to validate the order. As the most /// likely values are fill-or-kill sell orders by an externally owned /// account, the flags are chosen such that `0x00` represents this kind of /// order. The flags byte uses the following format: /// /// ``` /// bit | 31 ... | 6 | 5 | 4 | 3 | 2 | 1 | 0 | /// ----+----------+---+---+-------+---+---+ /// | reserved | * * | * | * * | * | * | /// | | | | | | | /// | | | | | | +---- order kind bit, 0 for a sell order /// | | | | | | and 1 for a buy order /// | | | | | | /// | | | | | +-------- order fill bit, 0 for fill-or-kill /// | | | | | and 1 for a partially fillable order /// | | | | | /// | | | +---+------------ use internal sell token balance bit: /// | | | 0x: ERC20 token balance /// | | | 10: external Balancer Vault balance /// | | | 11: internal Balancer Vault balance /// | | | /// | | +-------------------- use buy token balance bit /// | | 0: ERC20 token balance /// | | 1: internal Balancer Vault balance /// | | /// +---+------------------------ signature scheme bits: /// 00: EIP-712 /// 01: eth_sign /// 10: EIP-1271 /// 11: pre_sign /// ``` function extractFlags(uint256 flags) internal pure returns ( bytes32 kind, bool partiallyFillable, bytes32 sellTokenBalance, bytes32 buyTokenBalance, GPv2Signing.Scheme signingScheme ) { if (flags & 0x01 == 0) { kind = GPv2Order.KIND_SELL; } else { kind = GPv2Order.KIND_BUY; } partiallyFillable = flags & 0x02 != 0; if (flags & 0x08 == 0) { sellTokenBalance = GPv2Order.BALANCE_ERC20; } else if (flags & 0x04 == 0) { sellTokenBalance = GPv2Order.BALANCE_EXTERNAL; } else { sellTokenBalance = GPv2Order.BALANCE_INTERNAL; } if (flags & 0x10 == 0) { buyTokenBalance = GPv2Order.BALANCE_ERC20; } else { buyTokenBalance = GPv2Order.BALANCE_INTERNAL; } // NOTE: Take advantage of the fact that Solidity will revert if the // following expression does not produce a valid enum value. This means // we check here that the leading reserved bits must be 0. signingScheme = GPv2Signing.Scheme(flags >> 5); } }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.7.6; pragma abicoder v2; import "../interfaces/IERC20.sol"; import "../interfaces/IVault.sol"; import "./GPv2Order.sol"; import "./GPv2SafeERC20.sol"; /// @title Gnosis Protocol v2 Transfers /// @author Gnosis Developers library GPv2Transfer { using GPv2SafeERC20 for IERC20; /// @dev Transfer data. struct Data { address account; IERC20 token; uint256 amount; bytes32 balance; } /// @dev Ether marker address used to indicate an Ether transfer. address internal constant BUY_ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /// @dev Execute the specified transfer from the specified account to a /// recipient. The recipient will either receive internal Vault balances or /// ERC20 token balances depending on whether the account is using internal /// balances or not. /// /// This method is used for transferring fees to the settlement contract /// when settling a single order directly with Balancer. /// /// Note that this method is subtly different from `transferFromAccounts` /// with a single transfer with respect to how it deals with internal /// balances. Specifically, this method will perform an **internal balance /// transfer to the settlement contract instead of a withdrawal to the /// external balance of the settlement contract** for trades that specify /// trading with internal balances. This is done as a gas optimization in /// the single order "fast-path". /// /// @param vault The Balancer vault to use. /// @param transfer The transfer to perform specifying the sender account. /// @param recipient The recipient for the transfer. function fastTransferFromAccount( IVault vault, Data calldata transfer, address recipient ) internal { require( address(transfer.token) != BUY_ETH_ADDRESS, "GPv2: cannot transfer native ETH" ); if (transfer.balance == GPv2Order.BALANCE_ERC20) { transfer.token.safeTransferFrom( transfer.account, recipient, transfer.amount ); } else { IVault.UserBalanceOp[] memory balanceOps = new IVault.UserBalanceOp[](1); IVault.UserBalanceOp memory balanceOp = balanceOps[0]; balanceOp.kind = transfer.balance == GPv2Order.BALANCE_EXTERNAL ? IVault.UserBalanceOpKind.TRANSFER_EXTERNAL : IVault.UserBalanceOpKind.TRANSFER_INTERNAL; balanceOp.asset = transfer.token; balanceOp.amount = transfer.amount; balanceOp.sender = transfer.account; balanceOp.recipient = payable(recipient); vault.manageUserBalance(balanceOps); } } /// @dev Execute the specified transfers from the specified accounts to a /// single recipient. The recipient will receive all transfers as ERC20 /// token balances, regardless of whether or not the accounts are using /// internal Vault balances. /// /// This method is used for accumulating user balances into the settlement /// contract. /// /// @param vault The Balancer vault to use. /// @param transfers The batched transfers to perform specifying the /// sender accounts. /// @param recipient The single recipient for all the transfers. function transferFromAccounts( IVault vault, Data[] calldata transfers, address recipient ) internal { // NOTE: Allocate buffer of Vault balance operations large enough to // hold all GP transfers. This is done to avoid re-allocations (which // are gas inefficient) while still allowing all transfers to be batched // into a single Vault call. IVault.UserBalanceOp[] memory balanceOps = new IVault.UserBalanceOp[](transfers.length); uint256 balanceOpCount = 0; for (uint256 i = 0; i < transfers.length; i++) { Data calldata transfer = transfers[i]; require( address(transfer.token) != BUY_ETH_ADDRESS, "GPv2: cannot transfer native ETH" ); if (transfer.balance == GPv2Order.BALANCE_ERC20) { transfer.token.safeTransferFrom( transfer.account, recipient, transfer.amount ); } else { IVault.UserBalanceOp memory balanceOp = balanceOps[balanceOpCount++]; balanceOp.kind = transfer.balance == GPv2Order.BALANCE_EXTERNAL ? IVault.UserBalanceOpKind.TRANSFER_EXTERNAL : IVault.UserBalanceOpKind.WITHDRAW_INTERNAL; balanceOp.asset = transfer.token; balanceOp.amount = transfer.amount; balanceOp.sender = transfer.account; balanceOp.recipient = payable(recipient); } } if (balanceOpCount > 0) { truncateBalanceOpsArray(balanceOps, balanceOpCount); vault.manageUserBalance(balanceOps); } } /// @dev Execute the specified transfers to their respective accounts. /// /// This method is used for paying out trade proceeds from the settlement /// contract. /// /// @param vault The Balancer vault to use. /// @param transfers The batched transfers to perform. function transferToAccounts(IVault vault, Data[] memory transfers) internal { IVault.UserBalanceOp[] memory balanceOps = new IVault.UserBalanceOp[](transfers.length); uint256 balanceOpCount = 0; for (uint256 i = 0; i < transfers.length; i++) { Data memory transfer = transfers[i]; if (address(transfer.token) == BUY_ETH_ADDRESS) { require( transfer.balance != GPv2Order.BALANCE_INTERNAL, "GPv2: unsupported internal ETH" ); payable(transfer.account).transfer(transfer.amount); } else if (transfer.balance == GPv2Order.BALANCE_ERC20) { transfer.token.safeTransfer(transfer.account, transfer.amount); } else { IVault.UserBalanceOp memory balanceOp = balanceOps[balanceOpCount++]; balanceOp.kind = IVault.UserBalanceOpKind.DEPOSIT_INTERNAL; balanceOp.asset = transfer.token; balanceOp.amount = transfer.amount; balanceOp.sender = address(this); balanceOp.recipient = payable(transfer.account); } } if (balanceOpCount > 0) { truncateBalanceOpsArray(balanceOps, balanceOpCount); vault.manageUserBalance(balanceOps); } } /// @dev Truncate a Vault balance operation array to its actual size. /// /// This method **does not** check whether or not the new length is valid, /// and specifying a size that is larger than the array's actual length is /// undefined behaviour. /// /// @param balanceOps The memory array of balance operations to truncate. /// @param newLength The new length to set. function truncateBalanceOpsArray( IVault.UserBalanceOp[] memory balanceOps, uint256 newLength ) private pure { // NOTE: Truncate the vault transfers array to the specified length. // This is done by setting the array's length which occupies the first // word in memory pointed to by the `balanceOps` memory variable. // <https://docs.soliditylang.org/en/v0.7.6/internals/layout_in_memory.html> // solhint-disable-next-line no-inline-assembly assembly { mstore(balanceOps, newLength) } } }
// SPDX-License-Identifier: MIT // Vendored from OpenZeppelin contracts with minor modifications: // - Modified Solidity version // - Formatted code // - Shortened revert messages // - Removed unused methods // - Convert to `type(*).*` notation // <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/utils/SafeCast.sol> pragma solidity ^0.7.6; /** * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. * * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing * all math on `uint256` and `int256` and then downcasting. */ library SafeCast { /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { require(value >= 0, "SafeCast: not positive"); return uint256(value); } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { require( value <= uint256(type(int256).max), "SafeCast: int256 overflow" ); return int256(value); } }
// SPDX-License-Identifier: MIT // Vendored from OpenZeppelin contracts with minor modifications: // - Modified Solidity version // - Formatted code // - Shortened some revert messages // - Removed unused methods // - Added `ceilDiv` method // <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/math/SafeMath.sol> pragma solidity ^0.7.6; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a, "SafeMath: subtraction overflow"); return a - b; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) return 0; uint256 c = a * b; require(c / a == b, "SafeMath: mul overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers, reverting on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: division by 0"); return a / b; } /** * @dev Returns the ceiling integer division of two unsigned integers, * reverting on division by zero. The result is rounded towards up the * nearest integer, instead of truncating the fractional part. * * Requirements: * * - The divisor cannot be zero. * - The sum of the dividend and divisor cannot overflow. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { require(b > 0, "SafeMath: ceiling division by 0"); return a / b + (a % b == 0 ? 0 : 1); } }
// SPDX-License-Identifier: LGPL-3.0-or-later pragma solidity ^0.7.6; import "../interfaces/GPv2EIP1271.sol"; import "../libraries/GPv2Order.sol"; import "../libraries/GPv2Trade.sol"; /// @title Gnosis Protocol v2 Signing Library. /// @author Gnosis Developers abstract contract GPv2Signing { using GPv2Order for GPv2Order.Data; using GPv2Order for bytes; /// @dev Recovered trade data containing the extracted order and the /// recovered owner address. struct RecoveredOrder { GPv2Order.Data data; bytes uid; address owner; address receiver; } /// @dev Signing scheme used for recovery. enum Scheme {Eip712, EthSign, Eip1271, PreSign} /// @dev The EIP-712 domain type hash used for computing the domain /// separator. bytes32 private constant DOMAIN_TYPE_HASH = keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ); /// @dev The EIP-712 domain name used for computing the domain separator. bytes32 private constant DOMAIN_NAME = keccak256("Gnosis Protocol"); /// @dev The EIP-712 domain version used for computing the domain separator. bytes32 private constant DOMAIN_VERSION = keccak256("v2"); /// @dev Marker value indicating an order is pre-signed. uint256 private constant PRE_SIGNED = uint256(keccak256("GPv2Signing.Scheme.PreSign")); /// @dev The domain separator used for signing orders that gets mixed in /// making signatures for different domains incompatible. This domain /// separator is computed following the EIP-712 standard and has replay /// protection mixed in so that signed orders are only valid for specific /// GPv2 contracts. bytes32 public immutable domainSeparator; /// @dev Storage indicating whether or not an order has been signed by a /// particular address. mapping(bytes => uint256) public preSignature; /// @dev Event that is emitted when an account either pre-signs an order or /// revokes an existing pre-signature. event PreSignature(address indexed owner, bytes orderUid, bool signed); constructor() { // NOTE: Currently, the only way to get the chain ID in solidity is // using assembly. uint256 chainId; // solhint-disable-next-line no-inline-assembly assembly { chainId := chainid() } domainSeparator = keccak256( abi.encode( DOMAIN_TYPE_HASH, DOMAIN_NAME, DOMAIN_VERSION, chainId, address(this) ) ); } /// @dev Sets a presignature for the specified order UID. /// /// @param orderUid The unique identifier of the order to pre-sign. function setPreSignature(bytes calldata orderUid, bool signed) external { (, address owner, ) = orderUid.extractOrderUidParams(); require(owner == msg.sender, "GPv2: cannot presign order"); if (signed) { preSignature[orderUid] = PRE_SIGNED; } else { preSignature[orderUid] = 0; } emit PreSignature(owner, orderUid, signed); } /// @dev Returns an empty recovered order with a pre-allocated buffer for /// packing the unique identifier. /// /// @return recoveredOrder The empty recovered order data. function allocateRecoveredOrder() internal pure returns (RecoveredOrder memory recoveredOrder) { recoveredOrder.uid = new bytes(GPv2Order.UID_LENGTH); } /// @dev Extracts order data and recovers the signer from the specified /// trade. /// /// @param recoveredOrder Memory location used for writing the recovered order data. /// @param tokens The list of tokens included in the settlement. The token /// indices in the trade parameters map to tokens in this array. /// @param trade The trade data to recover the order data from. function recoverOrderFromTrade( RecoveredOrder memory recoveredOrder, IERC20[] calldata tokens, GPv2Trade.Data calldata trade ) internal view { GPv2Order.Data memory order = recoveredOrder.data; Scheme signingScheme = GPv2Trade.extractOrder(trade, tokens, order); (bytes32 orderDigest, address owner) = recoverOrderSigner(order, signingScheme, trade.signature); recoveredOrder.uid.packOrderUidParams( orderDigest, owner, order.validTo ); recoveredOrder.owner = owner; recoveredOrder.receiver = order.actualReceiver(owner); } /// @dev The length of any signature from an externally owned account. uint256 private constant ECDSA_SIGNATURE_LENGTH = 65; /// @dev Recovers an order's signer from the specified order and signature. /// /// @param order The order to recover a signature for. /// @param signingScheme The signing scheme. /// @param signature The signature bytes. /// @return orderDigest The computed order hash. /// @return owner The recovered address from the specified signature. function recoverOrderSigner( GPv2Order.Data memory order, Scheme signingScheme, bytes calldata signature ) internal view returns (bytes32 orderDigest, address owner) { orderDigest = order.hash(domainSeparator); if (signingScheme == Scheme.Eip712) { owner = recoverEip712Signer(orderDigest, signature); } else if (signingScheme == Scheme.EthSign) { owner = recoverEthsignSigner(orderDigest, signature); } else if (signingScheme == Scheme.Eip1271) { owner = recoverEip1271Signer(orderDigest, signature); } else { // signingScheme == Scheme.PreSign owner = recoverPreSigner(orderDigest, signature, order.validTo); } } /// @dev Perform an ECDSA recover for the specified message and calldata /// signature. /// /// The signature is encoded by tighyly packing the following struct: /// ``` /// struct EncodedSignature { /// bytes32 r; /// bytes32 s; /// uint8 v; /// } /// ``` /// /// @param message The signed message. /// @param encodedSignature The encoded signature. function ecdsaRecover(bytes32 message, bytes calldata encodedSignature) internal pure returns (address signer) { require( encodedSignature.length == ECDSA_SIGNATURE_LENGTH, "GPv2: malformed ecdsa signature" ); bytes32 r; bytes32 s; uint8 v; // NOTE: Use assembly to efficiently decode signature data. // solhint-disable-next-line no-inline-assembly assembly { // r = uint256(encodedSignature[0:32]) r := calldataload(encodedSignature.offset) // s = uint256(encodedSignature[32:64]) s := calldataload(add(encodedSignature.offset, 32)) // v = uint8(encodedSignature[64]) v := shr(248, calldataload(add(encodedSignature.offset, 64))) } signer = ecrecover(message, v, r, s); require(signer != address(0), "GPv2: invalid ecdsa signature"); } /// @dev Decodes signature bytes originating from an EIP-712-encoded /// signature. /// /// EIP-712 signs typed data. The specifications are described in the /// related EIP (<https://eips.ethereum.org/EIPS/eip-712>). /// /// EIP-712 signatures are encoded as standard ECDSA signatures as described /// in the corresponding decoding function [`ecdsaRecover`]. /// /// @param orderDigest The EIP-712 signing digest derived from the order /// parameters. /// @param encodedSignature Calldata pointing to tightly packed signature /// bytes. /// @return owner The address of the signer. function recoverEip712Signer( bytes32 orderDigest, bytes calldata encodedSignature ) internal pure returns (address owner) { owner = ecdsaRecover(orderDigest, encodedSignature); } /// @dev Decodes signature bytes originating from the output of the eth_sign /// RPC call. /// /// The specifications are described in the Ethereum documentation /// (<https://eth.wiki/json-rpc/API#eth_sign>). /// /// eth_sign signatures are encoded as standard ECDSA signatures as /// described in the corresponding decoding function /// [`ecdsaRecover`]. /// /// @param orderDigest The EIP-712 signing digest derived from the order /// parameters. /// @param encodedSignature Calldata pointing to tightly packed signature /// bytes. /// @return owner The address of the signer. function recoverEthsignSigner( bytes32 orderDigest, bytes calldata encodedSignature ) internal pure returns (address owner) { // The signed message is encoded as: // `"\x19Ethereum Signed Message:\n" || length || data`, where // the length is a constant (32 bytes) and the data is defined as: // `orderDigest`. bytes32 ethsignDigest = keccak256( abi.encodePacked( "\x19Ethereum Signed Message:\n32", orderDigest ) ); owner = ecdsaRecover(ethsignDigest, encodedSignature); } /// @dev Verifies the input calldata as an EIP-1271 contract signature and /// returns the address of the signer. /// /// The encoded signature tightly packs the following struct: /// /// ``` /// struct EncodedEip1271Signature { /// address owner; /// bytes signature; /// } /// ``` /// /// This function enforces that the encoded data stores enough bytes to /// cover the full length of the decoded signature. /// /// @param encodedSignature The encoded EIP-1271 signature. /// @param orderDigest The EIP-712 signing digest derived from the order /// parameters. /// @return owner The address of the signer. function recoverEip1271Signer( bytes32 orderDigest, bytes calldata encodedSignature ) internal view returns (address owner) { // NOTE: Use assembly to read the verifier address from the encoded // signature bytes. // solhint-disable-next-line no-inline-assembly assembly { // owner = address(encodedSignature[0:20]) owner := shr(96, calldataload(encodedSignature.offset)) } // NOTE: Configure prettier to ignore the following line as it causes // a panic in the Solidity plugin. // prettier-ignore bytes calldata signature = encodedSignature[20:]; require( EIP1271Verifier(owner).isValidSignature(orderDigest, signature) == GPv2EIP1271.MAGICVALUE, "GPv2: invalid eip1271 signature" ); } /// @dev Verifies the order has been pre-signed. The signature is the /// address of the signer of the order. /// /// @param orderDigest The EIP-712 signing digest derived from the order /// parameters. /// @param encodedSignature The pre-sign signature reprenting the order UID. /// @param validTo The order expiry timestamp. /// @return owner The address of the signer. function recoverPreSigner( bytes32 orderDigest, bytes calldata encodedSignature, uint32 validTo ) internal view returns (address owner) { require(encodedSignature.length == 20, "GPv2: malformed presignature"); // NOTE: Use assembly to read the owner address from the encoded // signature bytes. // solhint-disable-next-line no-inline-assembly assembly { // owner = address(encodedSignature[0:20]) owner := shr(96, calldataload(encodedSignature.offset)) } bytes memory orderUid = new bytes(GPv2Order.UID_LENGTH); orderUid.packOrderUidParams(orderDigest, owner, validTo); require( preSignature[orderUid] == PRE_SIGNED, "GPv2: order not presigned" ); } }
// SPDX-License-Identifier: MIT // Vendored from OpenZeppelin contracts with minor modifications: // - Modified Solidity version // - Formatted code // <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/utils/ReentrancyGuard.sol> pragma solidity ^0.7.6; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } }
// SPDX-License-Identifier: LGPL-3.0-only // Vendored from Gnosis utility contracts with minor modifications: // - Modified Solidity version // - Formatted code // - Added linter directives to ignore low level call and assembly warnings // <https://github.com/gnosis/util-contracts/blob/v3.1.0-solc-7/contracts/StorageAccessible.sol> pragma solidity ^0.7.6; /// @title ViewStorageAccessible - Interface on top of StorageAccessible base class to allow simulations from view functions interface ViewStorageAccessible { /** * @dev Same as `simulateDelegatecall` on StorageAccessible. Marked as view so that it can be called from external contracts * that want to run simulations from within view functions. Will revert if the invoked simulation attempts to change state. */ function simulateDelegatecall( address targetContract, bytes memory calldataPayload ) external view returns (bytes memory); /** * @dev Same as `getStorageAt` on StorageAccessible. This method allows reading aribtrary ranges of storage. */ function getStorageAt(uint256 offset, uint256 length) external view returns (bytes memory); } /// @title StorageAccessible - generic base contract that allows callers to access all internal storage. contract StorageAccessible { /** * @dev Reads `length` bytes of storage in the currents contract * @param offset - the offset in the current contract's storage in words to start reading from * @param length - the number of words (32 bytes) of data to read * @return the bytes that were read. */ function getStorageAt(uint256 offset, uint256 length) external view returns (bytes memory) { bytes memory result = new bytes(length * 32); for (uint256 index = 0; index < length; index++) { // solhint-disable-next-line no-inline-assembly assembly { let word := sload(add(offset, index)) mstore(add(add(result, 0x20), mul(index, 0x20)), word) } } return result; } /** * @dev Performs a delegetecall on a targetContract in the context of self. * Internally reverts execution to avoid side effects (making it static). Catches revert and returns encoded result as bytes. * @param targetContract Address of the contract containing the code to execute. * @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments). */ function simulateDelegatecall( address targetContract, bytes memory calldataPayload ) public returns (bytes memory response) { bytes memory innerCall = abi.encodeWithSelector( this.simulateDelegatecallInternal.selector, targetContract, calldataPayload ); // solhint-disable-next-line avoid-low-level-calls (, response) = address(this).call(innerCall); bool innerSuccess = response[response.length - 1] == 0x01; setLength(response, response.length - 1); if (innerSuccess) { return response; } else { revertWith(response); } } /** * @dev Performs a delegetecall on a targetContract in the context of self. * Internally reverts execution to avoid side effects (making it static). Returns encoded result as revert message * concatenated with the success flag of the inner call as a last byte. * @param targetContract Address of the contract containing the code to execute. * @param calldataPayload Calldata that should be sent to the target contract (encoded method name and arguments). */ function simulateDelegatecallInternal( address targetContract, bytes memory calldataPayload ) external returns (bytes memory response) { bool success; // solhint-disable-next-line avoid-low-level-calls (success, response) = targetContract.delegatecall(calldataPayload); revertWith(abi.encodePacked(response, success)); } function revertWith(bytes memory response) internal pure { // solhint-disable-next-line no-inline-assembly assembly { revert(add(response, 0x20), mload(response)) } } function setLength(bytes memory buffer, uint256 length) internal pure { // solhint-disable-next-line no-inline-assembly assembly { mstore(buffer, length) } } }
{ "evmVersion": "istanbul", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 1000000 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
[{"inputs":[{"internalType":"contract GPv2Authentication","name":"authenticator_","type":"address"},{"internalType":"contract IVault","name":"vault_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"Interaction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"bytes","name":"orderUid","type":"bytes"}],"name":"OrderInvalidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"bytes","name":"orderUid","type":"bytes"},{"indexed":false,"internalType":"bool","name":"signed","type":"bool"}],"name":"PreSignature","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"solver","type":"address"}],"name":"Settlement","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"sellToken","type":"address"},{"indexed":false,"internalType":"contract IERC20","name":"buyToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"sellAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"buyAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"orderUid","type":"bytes"}],"name":"Trade","type":"event"},{"inputs":[],"name":"authenticator","outputs":[{"internalType":"contract GPv2Authentication","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"domainSeparator","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"filledAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"orderUids","type":"bytes[]"}],"name":"freeFilledAmountStorage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"orderUids","type":"bytes[]"}],"name":"freePreSignatureStorage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"offset","type":"uint256"},{"internalType":"uint256","name":"length","type":"uint256"}],"name":"getStorageAt","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"orderUid","type":"bytes"}],"name":"invalidateOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"preSignature","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"orderUid","type":"bytes"},{"internalType":"bool","name":"signed","type":"bool"}],"name":"setPreSignature","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"clearingPrices","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"sellTokenIndex","type":"uint256"},{"internalType":"uint256","name":"buyTokenIndex","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"},{"internalType":"uint256","name":"executedAmount","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct GPv2Trade.Data[]","name":"trades","type":"tuple[]"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct GPv2Interaction.Data[][3]","name":"interactions","type":"tuple[][3]"}],"name":"settle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"targetContract","type":"address"},{"internalType":"bytes","name":"calldataPayload","type":"bytes"}],"name":"simulateDelegatecall","outputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"targetContract","type":"address"},{"internalType":"bytes","name":"calldataPayload","type":"bytes"}],"name":"simulateDelegatecallInternal","outputs":[{"internalType":"bytes","name":"response","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"poolId","type":"bytes32"},{"internalType":"uint256","name":"assetInIndex","type":"uint256"},{"internalType":"uint256","name":"assetOutIndex","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"userData","type":"bytes"}],"internalType":"struct IVault.BatchSwapStep[]","name":"swaps","type":"tuple[]"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"components":[{"internalType":"uint256","name":"sellTokenIndex","type":"uint256"},{"internalType":"uint256","name":"buyTokenIndex","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"buyAmount","type":"uint256"},{"internalType":"uint32","name":"validTo","type":"uint32"},{"internalType":"bytes32","name":"appData","type":"bytes32"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint256","name":"flags","type":"uint256"},{"internalType":"uint256","name":"executedAmount","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct GPv2Trade.Data","name":"trade","type":"tuple"}],"name":"swap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract IVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultRelayer","outputs":[{"internalType":"contract GPv2VaultRelayer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6101006040523480156200001257600080fd5b50604051620053eb380380620053eb83398101604081905262000035916200015b565b604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6020808301919091527f6c85c0337eba1661327f94f3bf46c8a7f9311a563f4d5c948362567f5d8ed60c828401527ff9446b8e937d86f0bc87cac73923491692b123ca5f8761908494703758206adf606080840191909152466080808501919091523060a08086019190915285518086038201815260c09586019687905280519401939093209052600180556001600160601b031986821b811690925284901b16905281906200010a906200014d565b62000116919062000199565b604051809103906000f08015801562000133573d6000803e3d6000fd5b5060601b6001600160601b03191660e05250620001c69050565b61129e806200414d83390190565b600080604083850312156200016e578182fd5b82516200017b81620001ad565b60208401519092506200018e81620001ad565b809150509250929050565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114620001c357600080fd5b50565b60805160a05160601c60c05160601c60e05160601c613f2562000228600039806104c55280610d61528061109052806115f0525080610556528061158b52508061039252806106bc528061099d52508061131e52806123df5250613f256000f3fe6080604052600436106100ec5760003560e01c80639b552cc21161008a578063ed9f35ce11610059578063ed9f35ce14610274578063f698da2514610294578063f84436bd146102a9578063fbfa77cf146102c9576100f3565b80639b552cc2146101ff578063a2a7d51b14610214578063d08d33d114610234578063ec6cb13f14610254576100f3565b80632479fb6e116100c65780632479fb6e1461016557806343218e19146101925780635624b25b146101bf578063845a101f146101df576100f3565b806313d79a0b146100f857806315337bc01461011a5780632335c76b1461013a576100f3565b366100f357005b600080fd5b34801561010457600080fd5b5061011861011336600461322e565b6102de565b005b34801561012657600080fd5b50610118610135366004613441565b6105c1565b34801561014657600080fd5b5061014f6106ba565b60405161015c91906136ee565b60405180910390f35b34801561017157600080fd5b506101856101803660046134ca565b6106de565b60405161015c91906137f0565b34801561019e57600080fd5b506101b26101ad3660046131a0565b6106fb565b60405161015c919061380d565b3480156101cb57600080fd5b506101b26101da3660046134fd565b610873565b3480156101eb57600080fd5b506101186101fa36600461338e565b6108e9565b34801561020b57600080fd5b5061014f61108e565b34801561022057600080fd5b5061011861022f3660046131ee565b6110b2565b34801561024057600080fd5b5061018561024f3660046134ca565b6110fb565b34801561026057600080fd5b5061011861026f366004613475565b611118565b34801561028057600080fd5b5061011861028f3660046131ee565b6112d7565b3480156102a057600080fd5b5061018561131c565b3480156102b557600080fd5b506101b26102c43660046131a0565b611340565b3480156102d557600080fd5b5061014f611589565b6002600154141561035057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001556040517f02cc250d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906302cc250d906103c79033906004016136ee565b60206040518083038186803b1580156103df57600080fd5b505afa1580156103f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104179190613425565b610456576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c78565b60405180910390fd5b6104728160005b60200281019061046d9190613d16565b6115ad565b6000806104838989898989896116ea565b6040517f7d10d11f000000000000000000000000000000000000000000000000000000008152919350915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690637d10d11f906104fa90859060040161370f565b600060405180830381600087803b15801561051457600080fd5b505af1158015610528573d6000803e3d6000fd5b5050505061053c8360016003811061045d57fe5b61057c73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001682611851565b61058783600261045d565b60405133907f40338ce1a7c49204f0099533b1e9a7ee0a3d261f84974ab7af36105b8c4e9db490600090a250506001805550505050505050565b60006105cd8383611b2f565b5091505073ffffffffffffffffffffffffffffffffffffffff81163314610620576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613a1b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600284846040516106539291906136c2565b9081526020016040518091039020819055508073ffffffffffffffffffffffffffffffffffffffff167f875b6cb035bbd4ac6500fabc6d1e4ca5bdc58a3e2b424ccb5c24cdbebeb009a984846040516106ad9291906137f9565b60405180910390a2505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b805160208183018101805160028252928201919093012091525481565b606060008373ffffffffffffffffffffffffffffffffffffffff16836040518082805190602001908083835b6020831061076457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610727565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d80600081146107c4576040519150601f19603f3d011682016040523d82523d6000602084013e6107c9565b606091505b50809350819250505061086c82826040516020018083805190602001908083835b6020831061082757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107ea565b6001836020036101000a03801982511681845116808217855250505050505090500182151560f81b815260010192505050604051602081830303815290604052611bbd565b5092915050565b606060008260200267ffffffffffffffff8111801561089157600080fd5b506040519080825280601f01601f1916602001820160405280156108bc576020820181803683370190505b50905060005b838110156108df57848101546020808302840101526001016108c2565b5090505b92915050565b6002600154141561095b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001556040517f02cc250d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016906302cc250d906109d29033906004016136ee565b60206040518083038186803b1580156109ea57600080fd5b505afa1580156109fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a229190613425565b610a58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c78565b6000610a62611bc5565b8051909150610a7382868686611bf2565b60007ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677582610100015114610aa8576001610aab565b60005b9050610ab5612f90565b60408085015173ffffffffffffffffffffffffffffffffffffffff90811683526101408501517f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce9081146020850152606080880151909216928401929092526101608501519091149082015260008667ffffffffffffffff81118015610b3a57600080fd5b50604051908082528060200260200182016040528015610b64578160200160208202803683370190505b50610100850151909150610120870135907ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467751415610c30578460800151811015610bda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c41565b610be78560600151611c90565b82886000013581518110610bf757fe5b602002602001018181525050610c0c81611c90565b60000382886020013581518110610c1f57fe5b602002602001018181525050610cc0565b8460600151811115610c6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b9c565b610c7781611c90565b82886000013581518110610c8757fe5b602002602001018181525050610ca08560800151611c90565b60000382886020013581518110610cb357fe5b6020026020010181815250505b610cc8612f90565b8660400151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508560000151816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508560e0015181604001818152505085610140015181606001818152505060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634817a286878f8f8f8f8b8b8f60a001518b6040518a63ffffffff1660e01b8152600401610dcc99989796959493929190613877565b600060405180830381600087803b158015610de657600080fd5b505af1158015610dfa573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610e4091908101906132ed565b90506000886020015190506000610e6d838c6000013581518110610e6057fe5b6020026020010151611d25565b90506000610e94848d6020013581518110610e8457fe5b6020026020010151600003611d25565b9050600283604051610ea691906136d2565b908152602001604051809103902054600014610eee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613bd3565b7ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467758a61010001511415610f825789606001518214610f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613ac0565b8960600151600284604051610f6d91906136d2565b90815260405190819003602001902055610fe5565b89608001518114610fbf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613af7565b8960800151600284604051610fd491906136d2565b908152604051908190036020019020555b8a6040015173ffffffffffffffffffffffffffffffffffffffff167fa07a543ab8a018198e99ca0184c93fe9050a79400a0a723441f84de1d972cc178b600001518c6020015185858f60e001518960405161104596959493929190613820565b60405180910390a260405133907f40338ce1a7c49204f0099533b1e9a7ee0a3d261f84974ab7af36105b8c4e9db490600090a25050600180555050505050505050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b3033146110eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b65565b6110f760008383611d96565b5050565b805160208183018101805160008252928201919093012091525481565b60006111248484611b2f565b5091505073ffffffffffffffffffffffffffffffffffffffff811633146111ac57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f475076323a2063616e6e6f74207072657369676e206f72646572000000000000604482015290519081900360640190fd5b8115611206577ff59c009283ff87aa78203fc4d9c2df025ee851130fb69cc3e068941f6b5e2d6f60001c60008585604051808383808284378083019250505092505050908152602001604051809103902081905550611232565b600080858560405180838380828437919091019485525050604051928390036020019092209290925550505b8073ffffffffffffffffffffffffffffffffffffffff167f01bf7c8b0ca55deecbea89d7e58295b7ffbf685fd0d96801034ba8c6ffe1c68d858585604051808060200183151581526020018281038252858582818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003965090945050505050a250505050565b303314611310576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b65565b6110f760028383611d96565b7f000000000000000000000000000000000000000000000000000000000000000081565b606060006343218e1960e01b8484604051602401808373ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b838110156113aa578181015183820152602001611392565b50505050905090810190601f1680156113d75780820380516001836020036101000a031916815260200191505b50604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909816979097178752518151919750309688965090945084935091508083835b602083106114a857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161146b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461150a576040519150601f19603f3d011682016040523d82523d6000602084013e61150f565b606091505b5090508092505060008260018451038151811061152857fe5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916600160f81b14905061156b836001855103611e46565b80156115785750506108e3565b61158183611bbd565b505092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60005b818110156116e557368383838181106115c557fe5b90506020028101906115d79190613dde565b905073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001661161d6020830183613184565b73ffffffffffffffffffffffffffffffffffffffff16141561166b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613caf565b61167481611e4a565b6116816020820182613184565b73ffffffffffffffffffffffffffffffffffffffff167fed99827efb37016f2275f98c4bcf71c7551c75d59e9b450f79fa32e60be672c282602001356116c684611ea1565b6040516116d4929190613ce6565b60405180910390a2506001016115b0565b505050565b60608060006116f7611bc5565b90508367ffffffffffffffff8111801561171057600080fd5b5060405190808252806020026020018201604052801561174a57816020015b611737612f90565b81526020019060019003908161172f5790505b5092508367ffffffffffffffff8111801561176457600080fd5b5060405190808252806020026020018201604052801561179e57816020015b61178b612f90565b8152602001906001900390816117835790505b50915060005b8481101561184457368686838181106117b957fe5b90506020028101906117cb9190613e11565b90506117d9838c8c84611bf2565b61183b838a8a84358181106117ea57fe5b905060200201358b8b856020013581811061180157fe5b9050602002013584610120013589878151811061181a57fe5b602002602001015189888151811061182e57fe5b6020026020010151611ecb565b506001016117a4565b5050965096945050505050565b6000815167ffffffffffffffff8111801561186b57600080fd5b506040519080825280602002602001820160405280156118a557816020015b611892612fb7565b81526020019060019003908161188a5790505b5090506000805b8351811015611a935760008482815181106118c357fe5b6020026020010151905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1614156119c7577f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce81606001511415611977576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b2e565b8051604080830151905173ffffffffffffffffffffffffffffffffffffffff9092169181156108fc0291906000818181858888f193505050501580156119c1573d6000803e3d6000fd5b50611a8a565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981606001511415611a2657805160408201516020830151611a219273ffffffffffffffffffffffffffffffffffffffff90911691612216565b611a8a565b6000848480600101955081518110611a3a57fe5b602090810291909101810151600081528382015173ffffffffffffffffffffffffffffffffffffffff90811692820192909252604080850151908201523060608201528351909116608090910152505b506001016118ac565b508015611b2957611aa48282611e46565b6040517f0e8e3e8400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851690630e8e3e8490611af690859060040161375d565b600060405180830381600087803b158015611b1057600080fd5b505af1158015611b24573d6000803e3d6000fd5b505050505b50505050565b6000808060388414611ba257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f475076323a20696e76616c696420756964000000000000000000000000000000604482015290519081900360640190fd5b5050823593602084013560601c936034013560e01c92509050565b805160208201fd5b611bcd612fe7565b6040805160388082526060820190925290602082018180368337505050602082015290565b83516000611c02838686856122ee565b9050600080611c1f8484611c1a610140890189613d7b565b6123d6565b91509150611c4282828660a001518b60200151612485909392919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff81166040890152611c688482612507565b73ffffffffffffffffffffffffffffffffffffffff1660609098019790975250505050505050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115611d2157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f53616665436173743a20696e74323536206f766572666c6f7700000000000000604482015290519081900360640190fd5b5090565b600080821215611d2157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f53616665436173743a206e6f7420706f73697469766500000000000000000000604482015290519081900360640190fd5b60005b81811015611b2957366000848484818110611db057fe5b9050602002810190611dc29190613d7b565b915091506000611dd28383611b2f565b92505050428163ffffffff1610611e15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c0a565b6000878484604051611e289291906136c2565b90815260405190819003602001902055505060019091019050611d99565b9052565b73ffffffffffffffffffffffffffffffffffffffff8135166020820135366000611e776040860186613d7b565b9150915060405181838237600080838387895af1611e99573d6000803e3d6000fd5b505050505050565b60003681611eb26040850185613d7b565b909250905060048110611ec457813592505b5050919050565b8551602087015160a08201514263ffffffff9091161015611f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613a52565b6080820151611f279087612539565b6060830151611f369089612539565b1015611f6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613a89565b6000806000807ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775866101000151141561206f5785610120015115611fdb57889350611fd48660600151611fce868960e0015161253990919063ffffffff16565b906125c9565b9150611fea565b856060015193508560e0015191505b611ffe8a611ff8868e612539565b9061264a565b925061202a8460028760405161201491906136d2565b90815260405190819003602001902054906126e8565b9050856060015181111561206a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613bd3565b612116565b856101200151156120a35788925061209c8660800151611fce858960e0015161253990919063ffffffff16565b91506120b2565b856080015192508560e0015191505b6120c08b611fce858d612539565b93506120d68360028760405161201491906136d2565b90508560800151811115612116576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613bd3565b61212084836126e8565b93508060028660405161213391906136d2565b9081526020016040518091039020819055508b6040015173ffffffffffffffffffffffffffffffffffffffff167fa07a543ab8a018198e99ca0184c93fe9050a79400a0a723441f84de1d972cc17876000015188602001518787878b6040516121a196959493929190613820565b60405180910390a250506040808b015173ffffffffffffffffffffffffffffffffffffffff9081168852855181166020808a0191909152888301949094526101408601516060988901529a8701518b16865282850151909a169185019190915297830197909752610160015191015250505050565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000080825273ffffffffffffffffffffffffffffffffffffffff84166004830152602482018390529060008060448382895af1612279573d6000803e3d6000fd5b506122838461275c565b611b2957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f475076323a206661696c6564207472616e736665720000000000000000000000604482015290519081900360640190fd5b6000838386358181106122fd57fe5b6020908102929092013573ffffffffffffffffffffffffffffffffffffffff168452508490849087013581811061233057fe5b73ffffffffffffffffffffffffffffffffffffffff602091820293909301358316908501525060408087013590911690830152606080860135908301526080808601359083015263ffffffff60a080870135919091169083015260c0808601359083015260e080860135908301526123ac610100860135612826565b61016087019190915261014086019190915290151561012085015261010090930152509392505050565b600080612403867f000000000000000000000000000000000000000000000000000000000000000061297b565b9150600085600381111561241357fe5b141561242b57612424828585612a05565b905061247c565b600185600381111561243957fe5b141561244a57612424828585612a1a565b600285600381111561245857fe5b141561246957612424828585612a82565b6124798285858960a00151612c20565b90505b94509492505050565b60388451146124f557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f475076323a2075696420627566666572206f766572666c6f7700000000000000604482015290519081900360640190fd5b60388401526034830152602090910152565b604082015160009073ffffffffffffffffffffffffffffffffffffffff166125305750806108e3565b50506040015190565b600082612548575060006108e3565b8282028284828161255557fe5b04146125c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f536166654d6174683a206d756c206f766572666c6f7700000000000000000000604482015290519081900360640190fd5b9392505050565b600080821161263957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f536166654d6174683a206469766973696f6e2062792030000000000000000000604482015290519081900360640190fd5b81838161264257fe5b049392505050565b60008082116126ba57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f536166654d6174683a206365696c696e67206469766973696f6e206279203000604482015290519081900360640190fd5b8183816126c357fe5b06156126d05760016126d3565b60005b60ff168284816126df57fe5b04019392505050565b6000828201838110156125c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600061279a565b7f08c379a0000000000000000000000000000000000000000000000000000000006000526020600452806024528160445260646000fd5b3d80156127d95760208114612813576127d47f475076323a206d616c666f726d6564207472616e7366657220726573756c7400601f612763565b612820565b823b61280a5761280a7f475076323a206e6f74206120636f6e74726163740000000000000000000000006014612763565b60019150612820565b3d6000803e600051151591505b50919050565b6000808080806001861661285c577ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467759450612880565b7f6ed88e868af0a1983e3886d5f3e95a2fafbd6c3450bc229e27342283dc429ccc94505b6002861615159350600886166128b8577f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9925061290c565b600486166128e8577fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea0632925061290c565b7f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce92505b6010861661293c577f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc99150612960565b7f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce91505b600586901c600381111561297057fe5b905091939590929450565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090910180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6000612a12848484612de5565b949350505050565b6000808460405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c01828152602001915050604051602081830303815290604052805190602001209050612a79818585612de5565b95945050505050565b813560601c366000612a978460148188613e68565b604080517f1626ba7e00000000000000000000000000000000000000000000000000000000808252600482018b81526024830193845260448301859052949650929450919273ffffffffffffffffffffffffffffffffffffffff871692631626ba7e928b928892889290606401848480828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201965060209550909350505081840390508186803b158015612b5d57600080fd5b505afa158015612b71573d6000803e3d6000fd5b505050506040513d6020811015612b8757600080fd5b50517fffffffff000000000000000000000000000000000000000000000000000000001614612c1757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f475076323a20696e76616c69642065697031323731207369676e617475726500604482015290519081900360640190fd5b50509392505050565b600060148314612c9157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f475076323a206d616c666f726d6564207072657369676e617475726500000000604482015290519081900360640190fd5b506040805160388082526060828101909352853590921c9160009190602082018180368337019050509050612cc881878486612485565b7ff59c009283ff87aa78203fc4d9c2df025ee851130fb69cc3e068941f6b5e2d6f60001c6000826040518082805190602001908083835b60208310612d3c57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101612cff565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390205414612ddc57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f475076323a206f72646572206e6f74207072657369676e656400000000000000604482015290519081900360640190fd5b50949350505050565b600060418214612e5657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f475076323a206d616c666f726d6564206563647361207369676e617475726500604482015290519081900360640190fd5b604080516000815260208181018084528790528286013560f81c82840181905286356060840181905282880135608085018190529451909493919260019260a0808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015612ed9573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015194505073ffffffffffffffffffffffffffffffffffffffff8416612f8657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f475076323a20696e76616c6964206563647361207369676e6174757265000000604482015290519081900360640190fd5b5050509392505050565b60408051608081018252600080825260208201819052918101829052606081019190915290565b6040805160a081019091528060008152600060208201819052604082018190526060820181905260809091015290565b6040518060800160405280612ffa613014565b815260606020820181905260006040830181905291015290565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b60008083601f840112613089578182fd5b50813567ffffffffffffffff8111156130a0578182fd5b60208301915083602080830285010111156130ba57600080fd5b9250929050565b60008083601f8401126130d2578182fd5b50813567ffffffffffffffff8111156130e9578182fd5b6020830191508360208285010111156130ba57600080fd5b600082601f830112613111578081fd5b813567ffffffffffffffff81111561312557fe5b61315660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613e44565b81815284602083860101111561316a578283fd5b816020850160208301379081016020019190915292915050565b600060208284031215613195578081fd5b81356125c281613ebc565b600080604083850312156131b2578081fd5b82356131bd81613ebc565b9150602083013567ffffffffffffffff8111156131d8578182fd5b6131e485828601613101565b9150509250929050565b60008060208385031215613200578182fd5b823567ffffffffffffffff811115613216578283fd5b61322285828601613078565b90969095509350505050565b60008060008060008060006080888a031215613248578283fd5b873567ffffffffffffffff8082111561325f578485fd5b61326b8b838c01613078565b909950975060208a0135915080821115613283578485fd5b61328f8b838c01613078565b909750955060408a01359150808211156132a7578485fd5b6132b38b838c01613078565b909550935060608a01359150808211156132cb578283fd5b508801606081018a10156132dd578182fd5b8091505092959891949750929550565b600060208083850312156132ff578182fd5b825167ffffffffffffffff80821115613316578384fd5b818501915085601f830112613329578384fd5b81518181111561333557fe5b8381029150613345848301613e44565b8181528481019084860184860187018a101561335f578788fd5b8795505b83861015613381578051835260019590950194918601918601613363565b5098975050505050505050565b6000806000806000606086880312156133a5578081fd5b853567ffffffffffffffff808211156133bc578283fd5b6133c889838a01613078565b909750955060208801359150808211156133e0578283fd5b6133ec89838a01613078565b90955093506040880135915080821115613404578283fd5b5086016101608189031215613417578182fd5b809150509295509295909350565b600060208284031215613436578081fd5b81516125c281613ee1565b60008060208385031215613453578182fd5b823567ffffffffffffffff811115613469578283fd5b613222858286016130c1565b600080600060408486031215613489578081fd5b833567ffffffffffffffff81111561349f578182fd5b6134ab868287016130c1565b90945092505060208401356134bf81613ee1565b809150509250925092565b6000602082840312156134db578081fd5b813567ffffffffffffffff8111156134f1578182fd5b612a1284828501613101565b6000806040838503121561350f578182fd5b50508035926020909101359150565b60008284526020808501945082825b8581101561356857813561354081613ebc565b73ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161352d565b509495945050505050565b6000815180845260208085019450808401835b8381101561356857815187529582019590820190600101613586565b600082845282826020860137806020848601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011685010190509392505050565b60008151808452613602816020860160208601613e90565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8082511683528060208301511660208401525060408101516040830152606081015160608301525050565b73ffffffffffffffffffffffffffffffffffffffff808251168352602082015115156020840152806040830151166040840152506060810151151560608301525050565b63ffffffff169052565b6000828483379101908152919050565b600082516136e4818460208701613e90565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6020808252825182820181905260009190848201906040850190845b818110156137515761373e838551613634565b928401926080929092019160010161372b565b50909695505050505050565b602080825282518282018190526000919060409081850190868401855b828110156137e357815180516004811061379057fe5b85528087015173ffffffffffffffffffffffffffffffffffffffff908116888701528682015187870152606080830151821690870152608091820151169085015260a0909301929085019060010161377a565b5091979650505050505050565b90815260200190565b600060208252612a126020830184866135a2565b6000602082526125c260208301846135ea565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015284606083015283608083015260c060a083015261386b60c08301846135ea565b98975050505050505050565b60006101a0820160028c1061388857fe5b8b835260206101a081850152818b83526101c0850190506101c0828d0286010192508c845b8d8110156139b6577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe408786030183527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff618f36030182351261390c578586fd5b8e823501803586528481013585870152604081013560408701526060810135606087015260808101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1823603018112613964578788fd5b8101803567ffffffffffffffff81111561397c578889fd5b80360383131561398a578889fd5b60a060808901526139a160a08901828985016135a2565b975050509284019250908301906001016138ad565b5050505082810360408401526139cd81898b61351e565b90506139dc6060840188613674565b82810360e08401526139ee8187613573565b9150506139ff6101008301856136b8565b613a0d610120830184613634565b9a9950505050505050505050565b6020808252601f908201527f475076323a2063616c6c657220646f6573206e6f74206f776e206f7264657200604082015260600190565b60208082526013908201527f475076323a206f72646572206578706972656400000000000000000000000000604082015260600190565b6020808252601f908201527f475076323a206c696d6974207072696365206e6f742072657370656374656400604082015260600190565b6020808252601f908201527f475076323a2073656c6c20616d6f756e74206e6f742072657370656374656400604082015260600190565b6020808252601e908201527f475076323a2062757920616d6f756e74206e6f74207265737065637465640000604082015260600190565b6020808252601e908201527f475076323a20756e737570706f7274656420696e7465726e616c204554480000604082015260600190565b60208082526018908201527f475076323a206e6f7420616e20696e746572616374696f6e0000000000000000604082015260600190565b60208082526014908201527f475076323a206c696d697420746f6f2068696768000000000000000000000000604082015260600190565b60208082526012908201527f475076323a206f726465722066696c6c65640000000000000000000000000000604082015260600190565b60208082526017908201527f475076323a206f72646572207374696c6c2076616c6964000000000000000000604082015260600190565b60208082526013908201527f475076323a206c696d697420746f6f206c6f7700000000000000000000000000604082015260600190565b60208082526012908201527f475076323a206e6f74206120736f6c7665720000000000000000000000000000604082015260600190565b6020808252601b908201527f475076323a20666f7262696464656e20696e746572616374696f6e0000000000604082015260600190565b9182527fffffffff0000000000000000000000000000000000000000000000000000000016602082015260400190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613d4a578283fd5b83018035915067ffffffffffffffff821115613d64578283fd5b60209081019250810236038213156130ba57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613daf578283fd5b83018035915067ffffffffffffffff821115613dc9578283fd5b6020019150368190038213156130ba57600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa18336030181126136e4578182fd5b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea18336030181126136e4578182fd5b60405181810167ffffffffffffffff81118282101715613e6057fe5b604052919050565b60008085851115613e77578182fd5b83861115613e83578182fd5b5050820193919092039150565b60005b83811015613eab578181015183820152602001613e93565b83811115611b295750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114613ede57600080fd5b50565b8015158114613ede57600080fdfea2646970667358221220de5e493c48a3b42da03a5db89085177b8d8ccec6e9bf6e8e48b3809343624c8f64736f6c6343000706003360c060405234801561001057600080fd5b5060405161129e38038061129e83398101604081905261002f9161004b565b33606090811b6080521b6001600160601b03191660a052610079565b60006020828403121561005c578081fd5b81516001600160a01b0381168114610072578182fd5b9392505050565b60805160601c60a05160601c6111ee6100b060003980610130528061020152806102bd5250806093528061024c52506111ee6000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80634817a2861461003b5780637d10d11f14610064575b600080fd5b61004e610049366004610cd9565b610079565b60405161005b9190610eb3565b60405180910390f35b610077610072366004610c69565b610234565b005b60603373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146100f3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ea906110e5565b60405180910390fd5b6040517f945bcec900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063945bcec990610171908c908c908c908c908c908c908c90600401610f59565b600060405180830381600087803b15801561018b57600080fd5b505af115801561019f573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526101e59190810190610bd9565b905061022873ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001683336102e9565b98975050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146102a3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ea906110e5565b6102e573ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016838333610551565b5050565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee61030e6040840160208501610bb6565b73ffffffffffffffffffffffffffffffffffffffff16141561035c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ea9061111c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9826060013514156103d0576103cb6103986020840184610bb6565b82604085018035906103ad9060208801610bb6565b73ffffffffffffffffffffffffffffffffffffffff16929190610816565b61054c565b604080516001808252818301909252600091816020015b6103ef6109cb565b8152602001906001900390816103e757905050905060008160008151811061041357fe5b602002602001015190507fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea063284606001351461044f576002610452565b60035b8190600381111561045f57fe5b9081600381111561046c57fe5b90525061047f6040850160208601610bb6565b73ffffffffffffffffffffffffffffffffffffffff16602080830191909152604080860135908301526104b490850185610bb6565b73ffffffffffffffffffffffffffffffffffffffff908116606083015283811660808301526040517f0e8e3e8400000000000000000000000000000000000000000000000000000000815290861690630e8e3e8490610517908590600401610ec6565b600060405180830381600087803b15801561053157600080fd5b505af1158015610545573d6000803e3d6000fd5b5050505050505b505050565b60008267ffffffffffffffff8111801561056a57600080fd5b506040519080825280602002602001820160405280156105a457816020015b6105916109cb565b8152602001906001900390816105895790505b5090506000805b8481101561077857368686838181106105c057fe5b60800291909101915073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee90506105f06040830160208401610bb6565b73ffffffffffffffffffffffffffffffffffffffff16141561063e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100ea9061111c565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9816060013514156106945761068f61067a6020830183610bb6565b86604084018035906103ad9060208701610bb6565b61076f565b60008484806001019550815181106106a857fe5b602002602001015190507fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea06328260600135146106e45760016106e7565b60035b819060038111156106f457fe5b9081600381111561070157fe5b9052506107146040830160208401610bb6565b73ffffffffffffffffffffffffffffffffffffffff166020808301919091526040808401359083015261074990830183610bb6565b73ffffffffffffffffffffffffffffffffffffffff908116606083015286166080909101525b506001016105ab565b50801561080e5761078982826108fd565b6040517f0e8e3e8400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871690630e8e3e84906107db908590600401610ec6565b600060405180830381600087803b1580156107f557600080fd5b505af1158015610809573d6000803e3d6000fd5b505050505b505050505050565b6040517f23b872dd0000000000000000000000000000000000000000000000000000000080825273ffffffffffffffffffffffffffffffffffffffff8581166004840152841660248301526044820183905290600080606483828a5af1610881573d6000803e3d6000fd5b5061088b85610901565b6108f657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f475076323a206661696c6564207472616e7366657246726f6d00000000000000604482015290519081900360640190fd5b5050505050565b9052565b600061093f565b7f08c379a0000000000000000000000000000000000000000000000000000000006000526020600452806024528160445260646000fd5b3d801561097e57602081146109b8576109797f475076323a206d616c666f726d6564207472616e7366657220726573756c7400601f610908565b6109c5565b823b6109af576109af7f475076323a206e6f74206120636f6e74726163740000000000000000000000006014610908565b600191506109c5565b3d6000803e600051151591505b50919050565b6040805160a081019091528060008152600060208201819052604082018190526060820181905260809091015290565b600082601f830112610a0b578081fd5b81356020610a20610a1b83611175565b611151565b8281528181019085830183850287018401881015610a3c578586fd5b855b85811015610a63578135610a5181611193565b84529284019290840190600101610a3e565b5090979650505050505050565b600082601f830112610a80578081fd5b81356020610a90610a1b83611175565b8281528181019085830183850287018401881015610aac578586fd5b855b85811015610a6357813584529284019290840190600101610aae565b60008083601f840112610adb578182fd5b50813567ffffffffffffffff811115610af2578182fd5b6020830191508360208083028501011115610b0c57600080fd5b9250929050565b80358015158114610b2357600080fd5b919050565b6000608082840312156109c5578081fd5b600060808284031215610b4a578081fd5b6040516080810181811067ffffffffffffffff82111715610b6757fe5b6040529050808235610b7881611193565b8152610b8660208401610b13565b60208201526040830135610b9981611193565b6040820152610baa60608401610b13565b60608201525092915050565b600060208284031215610bc7578081fd5b8135610bd281611193565b9392505050565b60006020808385031215610beb578182fd5b825167ffffffffffffffff811115610c01578283fd5b8301601f81018513610c11578283fd5b8051610c1f610a1b82611175565b8181528381019083850185840285018601891015610c3b578687fd5b8694505b83851015610c5d578051835260019490940193918501918501610c3f565b50979650505050505050565b60008060208385031215610c7b578081fd5b823567ffffffffffffffff80821115610c92578283fd5b818501915085601f830112610ca5578283fd5b813581811115610cb3578384fd5b866020608083028501011115610cc7578384fd5b60209290920196919550909350505050565b6000806000806000806000806101a0898b031215610cf5578384fd5b883560028110610d03578485fd5b9750602089013567ffffffffffffffff80821115610d1f578586fd5b610d2b8c838d01610aca565b909950975060408b0135915080821115610d43578586fd5b610d4f8c838d016109fb565b9650610d5e8c60608d01610b39565b955060e08b0135915080821115610d73578485fd5b50610d808b828c01610a70565b9350506101008901359150610d998a6101208b01610b28565b90509295985092959890939650565b6000815180845260208085019450808401835b83811015610ded57815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101610dbb565b509495945050505050565b6000815180845260208085019450808401835b83811015610ded57815187529582019590820190600101610e0b565b600082845282826020860137806020848601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011685010190509392505050565b73ffffffffffffffffffffffffffffffffffffffff808251168352602082015115156020840152806040830151166040840152506060810151151560608301525050565b600060208252610bd26020830184610df8565b602080825282518282018190526000919060409081850190868401855b82811015610f4c578151805160048110610ef957fe5b85528087015173ffffffffffffffffffffffffffffffffffffffff908116888701528682015187870152606080830151821690870152608091820151169085015260a09093019290850190600101610ee3565b5091979650505050505050565b600061012080830160028b10610f6b57fe5b8a8452602080850192909252889052610140808401918981028501909101908a845b8b811015611098577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec087850301855281357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff618e3603018112610fed578687fd5b8d01803585528381013584860152604080820135908601526060808201359086015260a0608080830135368490037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe101811261104757898afd5b8301803567ffffffffffffffff81111561105f578a8bfd5b80360385131561106d578a8bfd5b83838a0152611081848a01828a8501610e27565b998801999850505093850193505050600101610f8d565b50505083810360408501526110ad8189610da8565b9150506110bd6060840187610e6f565b82810360e08401526110cf8186610df8565b9150508261010083015298975050505050505050565b60208082526011908201527f475076323a206e6f742063726561746f72000000000000000000000000000000604082015260600190565b6020808252818101527f475076323a2063616e6e6f74207472616e73666572206e617469766520455448604082015260600190565b60405181810167ffffffffffffffff8111828210171561116d57fe5b604052919050565b600067ffffffffffffffff82111561118957fe5b5060209081020190565b73ffffffffffffffffffffffffffffffffffffffff811681146111b557600080fd5b5056fea2646970667358221220364a6941bea69620b7dc3a957d0ab4cbf3bfc459c7ad3924d220620aca9202fc64736f6c634300070600330000000000000000000000002c4c28ddbdac9c5e7055b4c863b72ea0149d8afe000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8
Deployed Bytecode
0x6080604052600436106100ec5760003560e01c80639b552cc21161008a578063ed9f35ce11610059578063ed9f35ce14610274578063f698da2514610294578063f84436bd146102a9578063fbfa77cf146102c9576100f3565b80639b552cc2146101ff578063a2a7d51b14610214578063d08d33d114610234578063ec6cb13f14610254576100f3565b80632479fb6e116100c65780632479fb6e1461016557806343218e19146101925780635624b25b146101bf578063845a101f146101df576100f3565b806313d79a0b146100f857806315337bc01461011a5780632335c76b1461013a576100f3565b366100f357005b600080fd5b34801561010457600080fd5b5061011861011336600461322e565b6102de565b005b34801561012657600080fd5b50610118610135366004613441565b6105c1565b34801561014657600080fd5b5061014f6106ba565b60405161015c91906136ee565b60405180910390f35b34801561017157600080fd5b506101856101803660046134ca565b6106de565b60405161015c91906137f0565b34801561019e57600080fd5b506101b26101ad3660046131a0565b6106fb565b60405161015c919061380d565b3480156101cb57600080fd5b506101b26101da3660046134fd565b610873565b3480156101eb57600080fd5b506101186101fa36600461338e565b6108e9565b34801561020b57600080fd5b5061014f61108e565b34801561022057600080fd5b5061011861022f3660046131ee565b6110b2565b34801561024057600080fd5b5061018561024f3660046134ca565b6110fb565b34801561026057600080fd5b5061011861026f366004613475565b611118565b34801561028057600080fd5b5061011861028f3660046131ee565b6112d7565b3480156102a057600080fd5b5061018561131c565b3480156102b557600080fd5b506101b26102c43660046131a0565b611340565b3480156102d557600080fd5b5061014f611589565b6002600154141561035057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001556040517f02cc250d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002c4c28ddbdac9c5e7055b4c863b72ea0149d8afe16906302cc250d906103c79033906004016136ee565b60206040518083038186803b1580156103df57600080fd5b505afa1580156103f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104179190613425565b610456576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c78565b60405180910390fd5b6104728160005b60200281019061046d9190613d16565b6115ad565b6000806104838989898989896116ea565b6040517f7d10d11f000000000000000000000000000000000000000000000000000000008152919350915073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c92e8bdf79f0507f65a392b0ab4667716bfe01101690637d10d11f906104fa90859060040161370f565b600060405180830381600087803b15801561051457600080fd5b505af1158015610528573d6000803e3d6000fd5b5050505061053c8360016003811061045d57fe5b61057c73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c81682611851565b61058783600261045d565b60405133907f40338ce1a7c49204f0099533b1e9a7ee0a3d261f84974ab7af36105b8c4e9db490600090a250506001805550505050505050565b60006105cd8383611b2f565b5091505073ffffffffffffffffffffffffffffffffffffffff81163314610620576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613a1b565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600284846040516106539291906136c2565b9081526020016040518091039020819055508073ffffffffffffffffffffffffffffffffffffffff167f875b6cb035bbd4ac6500fabc6d1e4ca5bdc58a3e2b424ccb5c24cdbebeb009a984846040516106ad9291906137f9565b60405180910390a2505050565b7f0000000000000000000000002c4c28ddbdac9c5e7055b4c863b72ea0149d8afe81565b805160208183018101805160028252928201919093012091525481565b606060008373ffffffffffffffffffffffffffffffffffffffff16836040518082805190602001908083835b6020831061076457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610727565b6001836020036101000a038019825116818451168082178552505050505050905001915050600060405180830381855af49150503d80600081146107c4576040519150601f19603f3d011682016040523d82523d6000602084013e6107c9565b606091505b50809350819250505061086c82826040516020018083805190602001908083835b6020831061082757805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107ea565b6001836020036101000a03801982511681845116808217855250505050505090500182151560f81b815260010192505050604051602081830303815290604052611bbd565b5092915050565b606060008260200267ffffffffffffffff8111801561089157600080fd5b506040519080825280601f01601f1916602001820160405280156108bc576020820181803683370190505b50905060005b838110156108df57848101546020808302840101526001016108c2565b5090505b92915050565b6002600154141561095b57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015290519081900360640190fd5b60026001556040517f02cc250d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002c4c28ddbdac9c5e7055b4c863b72ea0149d8afe16906302cc250d906109d29033906004016136ee565b60206040518083038186803b1580156109ea57600080fd5b505afa1580156109fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a229190613425565b610a58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c78565b6000610a62611bc5565b8051909150610a7382868686611bf2565b60007ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee34677582610100015114610aa8576001610aab565b60005b9050610ab5612f90565b60408085015173ffffffffffffffffffffffffffffffffffffffff90811683526101408501517f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce9081146020850152606080880151909216928401929092526101608501519091149082015260008667ffffffffffffffff81118015610b3a57600080fd5b50604051908082528060200260200182016040528015610b64578160200160208202803683370190505b50610100850151909150610120870135907ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467751415610c30578460800151811015610bda576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c41565b610be78560600151611c90565b82886000013581518110610bf757fe5b602002602001018181525050610c0c81611c90565b60000382886020013581518110610c1f57fe5b602002602001018181525050610cc0565b8460600151811115610c6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b9c565b610c7781611c90565b82886000013581518110610c8757fe5b602002602001018181525050610ca08560800151611c90565b60000382886020013581518110610cb357fe5b6020026020010181815250505b610cc8612f90565b8660400151816000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508560000151816020019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff16815250508560e0015181604001818152505085610140015181606001818152505060007f000000000000000000000000c92e8bdf79f0507f65a392b0ab4667716bfe011073ffffffffffffffffffffffffffffffffffffffff16634817a286878f8f8f8f8b8b8f60a001518b6040518a63ffffffff1660e01b8152600401610dcc99989796959493929190613877565b600060405180830381600087803b158015610de657600080fd5b505af1158015610dfa573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610e4091908101906132ed565b90506000886020015190506000610e6d838c6000013581518110610e6057fe5b6020026020010151611d25565b90506000610e94848d6020013581518110610e8457fe5b6020026020010151600003611d25565b9050600283604051610ea691906136d2565b908152602001604051809103902054600014610eee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613bd3565b7ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467758a61010001511415610f825789606001518214610f58576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613ac0565b8960600151600284604051610f6d91906136d2565b90815260405190819003602001902055610fe5565b89608001518114610fbf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613af7565b8960800151600284604051610fd491906136d2565b908152604051908190036020019020555b8a6040015173ffffffffffffffffffffffffffffffffffffffff167fa07a543ab8a018198e99ca0184c93fe9050a79400a0a723441f84de1d972cc178b600001518c6020015185858f60e001518960405161104596959493929190613820565b60405180910390a260405133907f40338ce1a7c49204f0099533b1e9a7ee0a3d261f84974ab7af36105b8c4e9db490600090a25050600180555050505050505050505050505050565b7f000000000000000000000000c92e8bdf79f0507f65a392b0ab4667716bfe011081565b3033146110eb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b65565b6110f760008383611d96565b5050565b805160208183018101805160008252928201919093012091525481565b60006111248484611b2f565b5091505073ffffffffffffffffffffffffffffffffffffffff811633146111ac57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f475076323a2063616e6e6f74207072657369676e206f72646572000000000000604482015290519081900360640190fd5b8115611206577ff59c009283ff87aa78203fc4d9c2df025ee851130fb69cc3e068941f6b5e2d6f60001c60008585604051808383808284378083019250505092505050908152602001604051809103902081905550611232565b600080858560405180838380828437919091019485525050604051928390036020019092209290925550505b8073ffffffffffffffffffffffffffffffffffffffff167f01bf7c8b0ca55deecbea89d7e58295b7ffbf685fd0d96801034ba8c6ffe1c68d858585604051808060200183151581526020018281038252858582818152602001925080828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201829003965090945050505050a250505050565b303314611310576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b65565b6110f760028383611d96565b7fdaee378bd0eb30ddf479272accf91761e697bc00e067a268f95f1d2732ed230b81565b606060006343218e1960e01b8484604051602401808373ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b838110156113aa578181015183820152602001611392565b50505050905090810190601f1680156113d75780820380516001836020036101000a031916815260200191505b50604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909816979097178752518151919750309688965090945084935091508083835b602083106114a857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161146b565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811461150a576040519150601f19603f3d011682016040523d82523d6000602084013e61150f565b606091505b5090508092505060008260018451038151811061152857fe5b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916600160f81b14905061156b836001855103611e46565b80156115785750506108e3565b61158183611bbd565b505092915050565b7f000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c881565b60005b818110156116e557368383838181106115c557fe5b90506020028101906115d79190613dde565b905073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000c92e8bdf79f0507f65a392b0ab4667716bfe01101661161d6020830183613184565b73ffffffffffffffffffffffffffffffffffffffff16141561166b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613caf565b61167481611e4a565b6116816020820182613184565b73ffffffffffffffffffffffffffffffffffffffff167fed99827efb37016f2275f98c4bcf71c7551c75d59e9b450f79fa32e60be672c282602001356116c684611ea1565b6040516116d4929190613ce6565b60405180910390a2506001016115b0565b505050565b60608060006116f7611bc5565b90508367ffffffffffffffff8111801561171057600080fd5b5060405190808252806020026020018201604052801561174a57816020015b611737612f90565b81526020019060019003908161172f5790505b5092508367ffffffffffffffff8111801561176457600080fd5b5060405190808252806020026020018201604052801561179e57816020015b61178b612f90565b8152602001906001900390816117835790505b50915060005b8481101561184457368686838181106117b957fe5b90506020028101906117cb9190613e11565b90506117d9838c8c84611bf2565b61183b838a8a84358181106117ea57fe5b905060200201358b8b856020013581811061180157fe5b9050602002013584610120013589878151811061181a57fe5b602002602001015189888151811061182e57fe5b6020026020010151611ecb565b506001016117a4565b5050965096945050505050565b6000815167ffffffffffffffff8111801561186b57600080fd5b506040519080825280602002602001820160405280156118a557816020015b611892612fb7565b81526020019060019003908161188a5790505b5090506000805b8351811015611a935760008482815181106118c357fe5b6020026020010151905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff16816020015173ffffffffffffffffffffffffffffffffffffffff1614156119c7577f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce81606001511415611977576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613b2e565b8051604080830151905173ffffffffffffffffffffffffffffffffffffffff9092169181156108fc0291906000818181858888f193505050501580156119c1573d6000803e3d6000fd5b50611a8a565b7f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc981606001511415611a2657805160408201516020830151611a219273ffffffffffffffffffffffffffffffffffffffff90911691612216565b611a8a565b6000848480600101955081518110611a3a57fe5b602090810291909101810151600081528382015173ffffffffffffffffffffffffffffffffffffffff90811692820192909252604080850151908201523060608201528351909116608090910152505b506001016118ac565b508015611b2957611aa48282611e46565b6040517f0e8e3e8400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851690630e8e3e8490611af690859060040161375d565b600060405180830381600087803b158015611b1057600080fd5b505af1158015611b24573d6000803e3d6000fd5b505050505b50505050565b6000808060388414611ba257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f475076323a20696e76616c696420756964000000000000000000000000000000604482015290519081900360640190fd5b5050823593602084013560601c936034013560e01c92509050565b805160208201fd5b611bcd612fe7565b6040805160388082526060820190925290602082018180368337505050602082015290565b83516000611c02838686856122ee565b9050600080611c1f8484611c1a610140890189613d7b565b6123d6565b91509150611c4282828660a001518b60200151612485909392919063ffffffff16565b73ffffffffffffffffffffffffffffffffffffffff81166040890152611c688482612507565b73ffffffffffffffffffffffffffffffffffffffff1660609098019790975250505050505050565b60007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821115611d2157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f53616665436173743a20696e74323536206f766572666c6f7700000000000000604482015290519081900360640190fd5b5090565b600080821215611d2157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f53616665436173743a206e6f7420706f73697469766500000000000000000000604482015290519081900360640190fd5b60005b81811015611b2957366000848484818110611db057fe5b9050602002810190611dc29190613d7b565b915091506000611dd28383611b2f565b92505050428163ffffffff1610611e15576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613c0a565b6000878484604051611e289291906136c2565b90815260405190819003602001902055505060019091019050611d99565b9052565b73ffffffffffffffffffffffffffffffffffffffff8135166020820135366000611e776040860186613d7b565b9150915060405181838237600080838387895af1611e99573d6000803e3d6000fd5b505050505050565b60003681611eb26040850185613d7b565b909250905060048110611ec457813592505b5050919050565b8551602087015160a08201514263ffffffff9091161015611f18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613a52565b6080820151611f279087612539565b6060830151611f369089612539565b1015611f6e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613a89565b6000806000807ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee346775866101000151141561206f5785610120015115611fdb57889350611fd48660600151611fce868960e0015161253990919063ffffffff16565b906125c9565b9150611fea565b856060015193508560e0015191505b611ffe8a611ff8868e612539565b9061264a565b925061202a8460028760405161201491906136d2565b90815260405190819003602001902054906126e8565b9050856060015181111561206a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613bd3565b612116565b856101200151156120a35788925061209c8660800151611fce858960e0015161253990919063ffffffff16565b91506120b2565b856080015192508560e0015191505b6120c08b611fce858d612539565b93506120d68360028760405161201491906136d2565b90508560800151811115612116576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161044d90613bd3565b61212084836126e8565b93508060028660405161213391906136d2565b9081526020016040518091039020819055508b6040015173ffffffffffffffffffffffffffffffffffffffff167fa07a543ab8a018198e99ca0184c93fe9050a79400a0a723441f84de1d972cc17876000015188602001518787878b6040516121a196959493929190613820565b60405180910390a250506040808b015173ffffffffffffffffffffffffffffffffffffffff9081168852855181166020808a0191909152888301949094526101408601516060988901529a8701518b16865282850151909a169185019190915297830197909752610160015191015250505050565b6040517fa9059cbb0000000000000000000000000000000000000000000000000000000080825273ffffffffffffffffffffffffffffffffffffffff84166004830152602482018390529060008060448382895af1612279573d6000803e3d6000fd5b506122838461275c565b611b2957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f475076323a206661696c6564207472616e736665720000000000000000000000604482015290519081900360640190fd5b6000838386358181106122fd57fe5b6020908102929092013573ffffffffffffffffffffffffffffffffffffffff168452508490849087013581811061233057fe5b73ffffffffffffffffffffffffffffffffffffffff602091820293909301358316908501525060408087013590911690830152606080860135908301526080808601359083015263ffffffff60a080870135919091169083015260c0808601359083015260e080860135908301526123ac610100860135612826565b61016087019190915261014086019190915290151561012085015261010090930152509392505050565b600080612403867fdaee378bd0eb30ddf479272accf91761e697bc00e067a268f95f1d2732ed230b61297b565b9150600085600381111561241357fe5b141561242b57612424828585612a05565b905061247c565b600185600381111561243957fe5b141561244a57612424828585612a1a565b600285600381111561245857fe5b141561246957612424828585612a82565b6124798285858960a00151612c20565b90505b94509492505050565b60388451146124f557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f475076323a2075696420627566666572206f766572666c6f7700000000000000604482015290519081900360640190fd5b60388401526034830152602090910152565b604082015160009073ffffffffffffffffffffffffffffffffffffffff166125305750806108e3565b50506040015190565b600082612548575060006108e3565b8282028284828161255557fe5b04146125c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f536166654d6174683a206d756c206f766572666c6f7700000000000000000000604482015290519081900360640190fd5b9392505050565b600080821161263957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f536166654d6174683a206469766973696f6e2062792030000000000000000000604482015290519081900360640190fd5b81838161264257fe5b049392505050565b60008082116126ba57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f536166654d6174683a206365696c696e67206469766973696f6e206279203000604482015290519081900360640190fd5b8183816126c357fe5b06156126d05760016126d3565b60005b60ff168284816126df57fe5b04019392505050565b6000828201838110156125c257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b600061279a565b7f08c379a0000000000000000000000000000000000000000000000000000000006000526020600452806024528160445260646000fd5b3d80156127d95760208114612813576127d47f475076323a206d616c666f726d6564207472616e7366657220726573756c7400601f612763565b612820565b823b61280a5761280a7f475076323a206e6f74206120636f6e74726163740000000000000000000000006014612763565b60019150612820565b3d6000803e600051151591505b50919050565b6000808080806001861661285c577ff3b277728b3fee749481eb3e0b3b48980dbbab78658fc419025cb16eee3467759450612880565b7f6ed88e868af0a1983e3886d5f3e95a2fafbd6c3450bc229e27342283dc429ccc94505b6002861615159350600886166128b8577f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc9925061290c565b600486166128e8577fabee3b73373acd583a130924aad6dc38cfdc44ba0555ba94ce2ff63980ea0632925061290c565b7f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce92505b6010861661293c577f5a28e9363bb942b639270062aa6bb295f434bcdfc42c97267bf003f272060dc99150612960565b7f4ac99ace14ee0a5ef932dc609df0943ab7ac16b7583634612f8dc35a4289a6ce91505b600586901c600381111561297057fe5b905091939590929450565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090910180517fd5a25ba2e97094ad7d83dc28a6572da797d6b3e7fc6663bd93efb789fc17e48982526101a0822091526040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b6000612a12848484612de5565b949350505050565b6000808460405160200180807f19457468657265756d205369676e6564204d6573736167653a0a333200000000815250601c01828152602001915050604051602081830303815290604052805190602001209050612a79818585612de5565b95945050505050565b813560601c366000612a978460148188613e68565b604080517f1626ba7e00000000000000000000000000000000000000000000000000000000808252600482018b81526024830193845260448301859052949650929450919273ffffffffffffffffffffffffffffffffffffffff871692631626ba7e928b928892889290606401848480828437600083820152604051601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016909201965060209550909350505081840390508186803b158015612b5d57600080fd5b505afa158015612b71573d6000803e3d6000fd5b505050506040513d6020811015612b8757600080fd5b50517fffffffff000000000000000000000000000000000000000000000000000000001614612c1757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f475076323a20696e76616c69642065697031323731207369676e617475726500604482015290519081900360640190fd5b50509392505050565b600060148314612c9157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f475076323a206d616c666f726d6564207072657369676e617475726500000000604482015290519081900360640190fd5b506040805160388082526060828101909352853590921c9160009190602082018180368337019050509050612cc881878486612485565b7ff59c009283ff87aa78203fc4d9c2df025ee851130fb69cc3e068941f6b5e2d6f60001c6000826040518082805190602001908083835b60208310612d3c57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101612cff565b6001836020036101000a03801982511681845116808217855250505050505090500191505090815260200160405180910390205414612ddc57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f475076323a206f72646572206e6f74207072657369676e656400000000000000604482015290519081900360640190fd5b50949350505050565b600060418214612e5657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f475076323a206d616c666f726d6564206563647361207369676e617475726500604482015290519081900360640190fd5b604080516000815260208181018084528790528286013560f81c82840181905286356060840181905282880135608085018190529451909493919260019260a0808201937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081019281900390910190855afa158015612ed9573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015194505073ffffffffffffffffffffffffffffffffffffffff8416612f8657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f475076323a20696e76616c6964206563647361207369676e6174757265000000604482015290519081900360640190fd5b5050509392505050565b60408051608081018252600080825260208201819052918101829052606081019190915290565b6040805160a081019091528060008152600060208201819052604082018190526060820181905260809091015290565b6040518060800160405280612ffa613014565b815260606020820181905260006040830181905291015290565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081018290526101208101829052610140810182905261016081019190915290565b60008083601f840112613089578182fd5b50813567ffffffffffffffff8111156130a0578182fd5b60208301915083602080830285010111156130ba57600080fd5b9250929050565b60008083601f8401126130d2578182fd5b50813567ffffffffffffffff8111156130e9578182fd5b6020830191508360208285010111156130ba57600080fd5b600082601f830112613111578081fd5b813567ffffffffffffffff81111561312557fe5b61315660207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613e44565b81815284602083860101111561316a578283fd5b816020850160208301379081016020019190915292915050565b600060208284031215613195578081fd5b81356125c281613ebc565b600080604083850312156131b2578081fd5b82356131bd81613ebc565b9150602083013567ffffffffffffffff8111156131d8578182fd5b6131e485828601613101565b9150509250929050565b60008060208385031215613200578182fd5b823567ffffffffffffffff811115613216578283fd5b61322285828601613078565b90969095509350505050565b60008060008060008060006080888a031215613248578283fd5b873567ffffffffffffffff8082111561325f578485fd5b61326b8b838c01613078565b909950975060208a0135915080821115613283578485fd5b61328f8b838c01613078565b909750955060408a01359150808211156132a7578485fd5b6132b38b838c01613078565b909550935060608a01359150808211156132cb578283fd5b508801606081018a10156132dd578182fd5b8091505092959891949750929550565b600060208083850312156132ff578182fd5b825167ffffffffffffffff80821115613316578384fd5b818501915085601f830112613329578384fd5b81518181111561333557fe5b8381029150613345848301613e44565b8181528481019084860184860187018a101561335f578788fd5b8795505b83861015613381578051835260019590950194918601918601613363565b5098975050505050505050565b6000806000806000606086880312156133a5578081fd5b853567ffffffffffffffff808211156133bc578283fd5b6133c889838a01613078565b909750955060208801359150808211156133e0578283fd5b6133ec89838a01613078565b90955093506040880135915080821115613404578283fd5b5086016101608189031215613417578182fd5b809150509295509295909350565b600060208284031215613436578081fd5b81516125c281613ee1565b60008060208385031215613453578182fd5b823567ffffffffffffffff811115613469578283fd5b613222858286016130c1565b600080600060408486031215613489578081fd5b833567ffffffffffffffff81111561349f578182fd5b6134ab868287016130c1565b90945092505060208401356134bf81613ee1565b809150509250925092565b6000602082840312156134db578081fd5b813567ffffffffffffffff8111156134f1578182fd5b612a1284828501613101565b6000806040838503121561350f578182fd5b50508035926020909101359150565b60008284526020808501945082825b8581101561356857813561354081613ebc565b73ffffffffffffffffffffffffffffffffffffffff168752958201959082019060010161352d565b509495945050505050565b6000815180845260208085019450808401835b8381101561356857815187529582019590820190600101613586565b600082845282826020860137806020848601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f85011685010190509392505050565b60008151808452613602816020860160208601613e90565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8082511683528060208301511660208401525060408101516040830152606081015160608301525050565b73ffffffffffffffffffffffffffffffffffffffff808251168352602082015115156020840152806040830151166040840152506060810151151560608301525050565b63ffffffff169052565b6000828483379101908152919050565b600082516136e4818460208701613e90565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b6020808252825182820181905260009190848201906040850190845b818110156137515761373e838551613634565b928401926080929092019160010161372b565b50909695505050505050565b602080825282518282018190526000919060409081850190868401855b828110156137e357815180516004811061379057fe5b85528087015173ffffffffffffffffffffffffffffffffffffffff908116888701528682015187870152606080830151821690870152608091820151169085015260a0909301929085019060010161377a565b5091979650505050505050565b90815260200190565b600060208252612a126020830184866135a2565b6000602082526125c260208301846135ea565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015284606083015283608083015260c060a083015261386b60c08301846135ea565b98975050505050505050565b60006101a0820160028c1061388857fe5b8b835260206101a081850152818b83526101c0850190506101c0828d0286010192508c845b8d8110156139b6577ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe408786030183527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff618f36030182351261390c578586fd5b8e823501803586528481013585870152604081013560408701526060810135606087015260808101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1823603018112613964578788fd5b8101803567ffffffffffffffff81111561397c578889fd5b80360383131561398a578889fd5b60a060808901526139a160a08901828985016135a2565b975050509284019250908301906001016138ad565b5050505082810360408401526139cd81898b61351e565b90506139dc6060840188613674565b82810360e08401526139ee8187613573565b9150506139ff6101008301856136b8565b613a0d610120830184613634565b9a9950505050505050505050565b6020808252601f908201527f475076323a2063616c6c657220646f6573206e6f74206f776e206f7264657200604082015260600190565b60208082526013908201527f475076323a206f72646572206578706972656400000000000000000000000000604082015260600190565b6020808252601f908201527f475076323a206c696d6974207072696365206e6f742072657370656374656400604082015260600190565b6020808252601f908201527f475076323a2073656c6c20616d6f756e74206e6f742072657370656374656400604082015260600190565b6020808252601e908201527f475076323a2062757920616d6f756e74206e6f74207265737065637465640000604082015260600190565b6020808252601e908201527f475076323a20756e737570706f7274656420696e7465726e616c204554480000604082015260600190565b60208082526018908201527f475076323a206e6f7420616e20696e746572616374696f6e0000000000000000604082015260600190565b60208082526014908201527f475076323a206c696d697420746f6f2068696768000000000000000000000000604082015260600190565b60208082526012908201527f475076323a206f726465722066696c6c65640000000000000000000000000000604082015260600190565b60208082526017908201527f475076323a206f72646572207374696c6c2076616c6964000000000000000000604082015260600190565b60208082526013908201527f475076323a206c696d697420746f6f206c6f7700000000000000000000000000604082015260600190565b60208082526012908201527f475076323a206e6f74206120736f6c7665720000000000000000000000000000604082015260600190565b6020808252601b908201527f475076323a20666f7262696464656e20696e746572616374696f6e0000000000604082015260600190565b9182527fffffffff0000000000000000000000000000000000000000000000000000000016602082015260400190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613d4a578283fd5b83018035915067ffffffffffffffff821115613d64578283fd5b60209081019250810236038213156130ba57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613daf578283fd5b83018035915067ffffffffffffffff821115613dc9578283fd5b6020019150368190038213156130ba57600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa18336030181126136e4578182fd5b600082357ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffea18336030181126136e4578182fd5b60405181810167ffffffffffffffff81118282101715613e6057fe5b604052919050565b60008085851115613e77578182fd5b83861115613e83578182fd5b5050820193919092039150565b60005b83811015613eab578181015183820152602001613e93565b83811115611b295750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114613ede57600080fd5b50565b8015158114613ede57600080fdfea2646970667358221220de5e493c48a3b42da03a5db89085177b8d8ccec6e9bf6e8e48b3809343624c8f64736f6c63430007060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002c4c28ddbdac9c5e7055b4c863b72ea0149d8afe000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8
-----Decoded View---------------
Arg [0] : authenticator_ (address): 0x2c4c28DDBdAc9C5E7055b4C863b72eA0149D8aFE
Arg [1] : vault_ (address): 0xBA12222222228d8Ba445958a75a0704d566BF2C8
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000002c4c28ddbdac9c5e7055b4c863b72ea0149d8afe
Arg [1] : 000000000000000000000000ba12222222228d8ba445958a75a0704d566bf2c8
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.