More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 78,933 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Fulfill | 31206947 | 901 days ago | IN | 0 POL | 0.00870719 | ||||
Fulfill | 31130819 | 903 days ago | IN | 0 POL | 0.00105999 | ||||
Fulfill | 31018696 | 906 days ago | IN | 0 POL | 0.00092814 | ||||
Fulfill | 30942186 | 908 days ago | IN | 0 POL | 0.00112929 | ||||
Fulfill | 30940265 | 908 days ago | IN | 0 POL | 0.00126825 | ||||
Fulfill | 30859967 | 910 days ago | IN | 0 POL | 0.00139339 | ||||
Fulfill | 30581875 | 917 days ago | IN | 0 POL | 0.00093804 | ||||
Fulfill | 30566075 | 918 days ago | IN | 0 POL | 0.0010172 | ||||
Fulfill | 25578834 | 1046 days ago | IN | 0 POL | 0.00084827 | ||||
Fulfill | 25578714 | 1046 days ago | IN | 0 POL | 0.00084827 | ||||
Prepare | 20755252 | 1172 days ago | IN | 0 POL | 0.00009355 | ||||
Prepare | 20755252 | 1172 days ago | IN | 0 POL | 0.00004677 | ||||
Cancel | 20490544 | 1179 days ago | IN | 0 POL | 0.00213186 | ||||
Cancel | 20152690 | 1189 days ago | IN | 0 POL | 0.00232032 | ||||
Remove Liquidity | 20148624 | 1189 days ago | IN | 0 POL | 0.00134139 | ||||
Remove Liquidity | 20148060 | 1189 days ago | IN | 0 POL | 0.00180378 | ||||
Remove Liquidity | 20147976 | 1189 days ago | IN | 0 POL | 0.00120252 | ||||
Remove Liquidity | 20147292 | 1189 days ago | IN | 0 POL | 0.00120252 | ||||
Remove Liquidity | 20147100 | 1189 days ago | IN | 0 POL | 0.00120252 | ||||
Prepare | 20018138 | 1192 days ago | IN | 0 POL | 0.00018173 | ||||
Prepare | 20018138 | 1192 days ago | IN | 0 POL | 0.00004677 | ||||
Prepare | 20013495 | 1192 days ago | IN | 0 POL | 0.00070168 | ||||
Prepare | 20013494 | 1192 days ago | IN | 0 POL | 0.00004677 | ||||
Prepare | 20013479 | 1192 days ago | IN | 0 POL | 0.00004676 | ||||
Prepare | 20013024 | 1192 days ago | IN | 0 POL | 0.00022758 |
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
18421338 | 1236 days ago | Contract Creation | 0 POL |
Loading...
Loading
Contract Name:
TransactionManager
Compiler Version
v0.8.4+commit.c7e474f2
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.4; import "./interfaces/IFulfillInterpreter.sol"; import "./interfaces/ITransactionManager.sol"; import "./interpreters/FulfillInterpreter.sol"; import "./ProposedOwnable.sol"; import "./lib/LibAsset.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; /** * * @title TransactionManager * @author Connext <[email protected]> * @notice This contract holds the logic to facilitate crosschain transactions. * Transactions go through three phases in the happy case: * * 1. Route Auction (offchain): User broadcasts to our network * signalling their desired route. Routers respond with sealed bids * containing commitments to fulfilling the transaction within a * certain time and price range. * * 2. Prepare: Once the auction is completed, the transaction can be * prepared. The user submits a transaction to `TransactionManager` * contract on sender-side chain containing router's signed bid. This * transaction locks up the users funds on the sending chain. Upon * detecting an event containing their signed bid from the chain, * router submits the same transaction to `TransactionManager` on the * receiver-side chain, and locks up a corresponding amount of * liquidity. The amount locked on the receiving chain is `sending * amount - auction fee` so the router is incentivized to complete the * transaction. * * 3. Fulfill: Upon detecting the `TransactionPrepared` event on the * receiver-side chain, the user signs a message and sends it to a * relayer, who will earn a fee for submission. The relayer (which may * be the router) then submits the message to the `TransactionManager` * to complete their transaction on receiver-side chain and claim the * funds locked by the router. A relayer is used here to allow users * to submit transactions with arbitrary calldata on the receiving * chain without needing gas to do so. The router then submits the * same signed message and completes transaction on sender-side, * unlocking the original `amount`. * * If a transaction is not fulfilled within a fixed timeout, it * reverts and can be reclaimed by the party that called `prepare` on * each chain (initiator). Additionally, transactions can be cancelled * unilaterally by the person owed funds on that chain (router for * sending chain, user for receiving chain) prior to expiry. */ contract TransactionManager is ReentrancyGuard, ProposedOwnable, ITransactionManager { /** * @dev Mapping of router to balance specific to asset */ mapping(address => mapping(address => uint256)) public routerBalances; /** * @dev Mapping of allowed router addresses. Must be added to both * sending and receiving chains when forwarding a transfer. */ mapping(address => bool) public approvedRouters; /** * @dev Mapping of allowed assetIds on same chain as contract */ mapping(address => bool) public approvedAssets; /** * @dev Mapping of hash of `InvariantTransactionData` to the hash * of the `VariantTransactionData` */ mapping(bytes32 => bytes32) public variantTransactionData; /** * @dev The stored chain id of the contract, may be passed in to avoid any * evm issues */ uint256 private immutable chainId; /** * @dev Minimum timeout (will be the lowest on the receiving chain) */ uint256 public constant MIN_TIMEOUT = 1 days; // 24 hours /** * @dev Maximum timeout (will be the highest on the sending chain) */ uint256 public constant MAX_TIMEOUT = 30 days; // 720 hours /** * @dev The external contract that will execute crosschain * calldata */ IFulfillInterpreter public immutable interpreter; constructor(uint256 _chainId) { chainId = _chainId; interpreter = new FulfillInterpreter(address(this)); } /** * @notice Gets the chainId for this contract. If not specified during init * will use the block.chainId */ function getChainId() public view override returns (uint256 _chainId) { // Hold in memory to reduce sload calls uint256 chain = chainId; if (chain == 0) { // If not provided, pull from block assembly { _chainId := chainid() } } else { // Use provided override _chainId = chain; } } /** * @notice Allows us to get the chainId that this contract has stored */ function getStoredChainId() external view override returns (uint256) { return chainId; } /** * @notice Used to add routers that can transact crosschain * @param router Router address to add */ function addRouter(address router) external override onlyOwner { // Sanity check: not empty require(router != address(0), "#AR:001"); // Sanity check: needs approval require(approvedRouters[router] == false, "#AR:032"); // Update mapping approvedRouters[router] = true; // Emit event emit RouterAdded(router, msg.sender); } /** * @notice Used to remove routers that can transact crosschain * @param router Router address to remove */ function removeRouter(address router) external override onlyOwner { // Sanity check: not empty require(router != address(0), "#RR:001"); // Sanity check: needs removal require(approvedRouters[router] == true, "#RR:033"); // Update mapping approvedRouters[router] = false; // Emit event emit RouterRemoved(router, msg.sender); } /** * @notice Used to add assets on same chain as contract that can * be transferred. * @param assetId AssetId to add */ function addAssetId(address assetId) external override onlyOwner { // Sanity check: needs approval require(approvedAssets[assetId] == false, "#AA:032"); // Update mapping approvedAssets[assetId] = true; // Emit event emit AssetAdded(assetId, msg.sender); } /** * @notice Used to remove assets on same chain as contract that can * be transferred. * @param assetId AssetId to remove */ function removeAssetId(address assetId) external override onlyOwner { // Sanity check: already approval require(approvedAssets[assetId] == true, "#RA:033"); // Update mapping approvedAssets[assetId] = false; // Emit event emit AssetRemoved(assetId, msg.sender); } /** * @notice This is used by anyone to increase a router's available * liquidity for a given asset. * @param amount The amount of liquidity to add for the router * @param assetId The address (or `address(0)` if native asset) of the * asset you're adding liquidity for * @param router The router you are adding liquidity on behalf of */ function addLiquidityFor(uint256 amount, address assetId, address router) external payable override nonReentrant { _addLiquidityForRouter(amount, assetId, router); } /** * @notice This is used by any router to increase their available * liquidity for a given asset. * @param amount The amount of liquidity to add for the router * @param assetId The address (or `address(0)` if native asset) of the * asset you're adding liquidity for */ function addLiquidity(uint256 amount, address assetId) external payable override nonReentrant { _addLiquidityForRouter(amount, assetId, msg.sender); } /** * @notice This is used by any router to decrease their available * liquidity for a given asset. * @param amount The amount of liquidity to remove for the router * @param assetId The address (or `address(0)` if native asset) of the * asset you're removing liquidity for * @param recipient The address that will receive the liquidity being removed */ function removeLiquidity( uint256 amount, address assetId, address payable recipient ) external override nonReentrant { // Sanity check: recipient is sensible require(recipient != address(0), "#RL:007"); // Sanity check: nonzero amounts require(amount > 0, "#RL:002"); uint256 routerBalance = routerBalances[msg.sender][assetId]; // Sanity check: amount can be deducted for the router require(routerBalance >= amount, "#RL:008"); // Update router balances unchecked { routerBalances[msg.sender][assetId] = routerBalance - amount; } // Transfer from contract to specified recipient LibAsset.transferAsset(assetId, recipient, amount); // Emit event emit LiquidityRemoved(msg.sender, assetId, amount, recipient); } /** * @notice This function creates a crosschain transaction. When called on * the sending chain, the user is expected to lock up funds. When * called on the receiving chain, the router deducts the transfer * amount from the available liquidity. The majority of the * information about a given transfer does not change between chains, * with three notable exceptions: `amount`, `expiry`, and * `preparedBlock`. The `amount` and `expiry` are decremented * between sending and receiving chains to provide an incentive for * the router to complete the transaction and time for the router to * fulfill the transaction on the sending chain after the unlocking * signature is revealed, respectively. * @param invariantData The data for a crosschain transaction that will * not change between sending and receiving chains. * The hash of this data is used as the key to store * the inforamtion that does change between chains * (amount,expiry,preparedBlock) for verification * @param amount The amount of the transaction on this chain * @param expiry The block.timestamp when the transaction will no longer be * fulfillable and is freely cancellable on this chain * @param encryptedCallData The calldata to be executed when the tx is * fulfilled. Used in the function to allow the user * to reconstruct the tx from events. Hash is stored * onchain to prevent shenanigans. * @param encodedBid The encoded bid that was accepted by the user for this * crosschain transfer. It is supplied as a param to the * function but is only used in event emission * @param bidSignature The signature of the bidder on the encoded bid for * this transaction. Only used within the function for * event emission. The validity of the bid and * bidSignature are enforced offchain */ function prepare( InvariantTransactionData calldata invariantData, uint256 amount, uint256 expiry, bytes calldata encryptedCallData, bytes calldata encodedBid, bytes calldata bidSignature ) external payable override nonReentrant returns (TransactionData memory) { // Sanity check: user is sensible require(invariantData.user != address(0), "#P:009"); // Sanity check: router is sensible require(invariantData.router != address(0), "#P:001"); // Router is approved *on both chains* require(isRouterOwnershipRenounced() || approvedRouters[invariantData.router], "#P:003"); // Sanity check: sendingChainFallback is sensible require(invariantData.sendingChainFallback != address(0), "#P:010"); // Sanity check: valid fallback require(invariantData.receivingAddress != address(0), "#P:026"); // Make sure the chains are different require(invariantData.sendingChainId != invariantData.receivingChainId, "#P:011"); // Make sure the chains are relevant uint256 _chainId = getChainId(); require(invariantData.sendingChainId == _chainId || invariantData.receivingChainId == _chainId, "#P:012"); { // Expiry scope // Make sure the expiry is greater than min uint256 buffer = expiry - block.timestamp; require(buffer >= MIN_TIMEOUT, "#P:013"); // Make sure the expiry is lower than max require(buffer <= MAX_TIMEOUT, "#P:014"); } // Make sure the hash is not a duplicate bytes32 digest = keccak256(abi.encode(invariantData)); require(variantTransactionData[digest] == bytes32(0), "#P:015"); // NOTE: the `encodedBid` and `bidSignature` are simply passed through // to the contract emitted event to ensure the availability of // this information. Their validity is asserted offchain, and // is out of scope of this contract. They are used as inputs so // in the event of a router or user crash, they may recover the // correct bid information without requiring an offchain store. // First determine if this is sender side or receiver side if (invariantData.sendingChainId == _chainId) { // Sanity check: amount is sensible // Only check on sending chain to enforce router fees. Transactions could // be 0-valued on receiving chain if it is just a value-less call to some // `IFulfillHelper` require(amount > 0, "#P:002"); // Assets are approved // NOTE: Cannot check this on receiving chain because of differing // chain contexts require(isAssetOwnershipRenounced() || approvedAssets[invariantData.sendingAssetId], "#P:004"); // This is sender side prepare. The user is beginning the process of // submitting an onchain tx after accepting some bid. They should // lock their funds in the contract for the router to claim after // they have revealed their signature on the receiving chain via // submitting a corresponding `fulfill` tx // Validate correct amounts on msg and transfer from user to // contract amount = transferAssetToContract(invariantData.sendingAssetId, amount); // Store the transaction variants. This happens after transferring to // account for fee on transfer tokens variantTransactionData[digest] = hashVariantTransactionData(amount, expiry, block.number); } else { // This is receiver side prepare. The router has proposed a bid on the // transfer which the user has accepted. They can now lock up their // own liquidity on th receiving chain, which the user can unlock by // calling `fulfill`. When creating the `amount` and `expiry` on the // receiving chain, the router should have decremented both. The // expiry should be decremented to ensure the router has time to // complete the sender-side transaction after the user completes the // receiver-side transactoin. The amount should be decremented to act as // a fee to incentivize the router to complete the transaction properly. // Check that the callTo is a contract // NOTE: This cannot happen on the sending chain (different chain // contexts), so a user could mistakenly create a transfer that must be // cancelled if this is incorrect require(invariantData.callTo == address(0) || Address.isContract(invariantData.callTo), "#P:031"); // Check that the asset is approved // NOTE: This cannot happen on both chains because of differing chain // contexts. May be possible for user to create transaction that is not // prepare-able on the receiver chain. require(isAssetOwnershipRenounced() || approvedAssets[invariantData.receivingAssetId], "#P:004"); // Check that the caller is the router require(msg.sender == invariantData.router, "#P:016"); // Check that the router isnt accidentally locking funds in the contract require(msg.value == 0, "#P:017"); // Check that router has liquidity uint256 balance = routerBalances[invariantData.router][invariantData.receivingAssetId]; require(balance >= amount, "#P:018"); // Store the transaction variants variantTransactionData[digest] = hashVariantTransactionData(amount, expiry, block.number); // Decrement the router liquidity // using unchecked because underflow protected against with require unchecked { routerBalances[invariantData.router][invariantData.receivingAssetId] = balance - amount; } } // Emit event TransactionData memory txData = TransactionData({ receivingChainTxManagerAddress: invariantData.receivingChainTxManagerAddress, user: invariantData.user, router: invariantData.router, sendingAssetId: invariantData.sendingAssetId, receivingAssetId: invariantData.receivingAssetId, sendingChainFallback: invariantData.sendingChainFallback, callTo: invariantData.callTo, receivingAddress: invariantData.receivingAddress, callDataHash: invariantData.callDataHash, transactionId: invariantData.transactionId, sendingChainId: invariantData.sendingChainId, receivingChainId: invariantData.receivingChainId, amount: amount, expiry: expiry, preparedBlockNumber: block.number }); emit TransactionPrepared(txData.user, txData.router, txData.transactionId, txData, msg.sender, encryptedCallData, encodedBid, bidSignature); return txData; } /** * @notice This function completes a crosschain transaction. When called on * the receiving chain, the user reveals their signature on the * transactionId and is sent the amount corresponding to the number * of shares the router locked when calling `prepare`. The router * then uses this signature to unlock the corresponding funds on the * receiving chain, which are then added back to their available * liquidity. The user includes a relayer fee since it is not * assumed they will have gas on the receiving chain. This function * *must* be called before the transaction expiry has elapsed. * @param txData All of the data (invariant and variant) for a crosschain * transaction. The variant data provided is checked against * what was stored when the `prepare` function was called. * @param relayerFee The fee that should go to the relayer when they are * calling the function on the receiving chain for the user * @param signature The users signature on the transaction id + fee that * can be used by the router to unlock the transaction on * the sending chain * @param callData The calldata to be sent to and executed by the * `FulfillHelper` */ function fulfill( TransactionData calldata txData, uint256 relayerFee, bytes calldata signature, // signature on fee + digest bytes calldata callData ) external override nonReentrant returns (TransactionData memory) { // Get the hash of the invariant tx data. This hash is the same // between sending and receiving chains. The variant data is stored // in the contract when `prepare` is called within the mapping. { // scope: validation and effects bytes32 digest = hashInvariantTransactionData(txData); // Make sure that the variant data matches what was stored require(variantTransactionData[digest] == hashVariantTransactionData(txData.amount, txData.expiry, txData.preparedBlockNumber), "#F:019"); // Make sure the expiry has not elapsed require(txData.expiry >= block.timestamp, "#F:020"); // Make sure the transaction wasn't already completed require(txData.preparedBlockNumber > 0, "#F:021"); // Validate the user has signed require(recoverFulfillSignature(txData.transactionId, relayerFee, txData.receivingChainId, txData.receivingChainTxManagerAddress, signature) == txData.user, "#F:022"); // Sanity check: fee <= amount. Allow `=` in case of only wanting to execute // 0-value crosschain tx, so only providing the fee amount require(relayerFee <= txData.amount, "#F:023"); // Check provided callData matches stored hash require(keccak256(callData) == txData.callDataHash, "#F:024"); // To prevent `fulfill` / `cancel` from being called multiple times, the // preparedBlockNumber is set to 0 before being hashed. The value of the // mapping is explicitly *not* zeroed out so users who come online without // a store can tell the difference between a transaction that has not been // prepared, and a transaction that was already completed on the receiver // chain. variantTransactionData[digest] = hashVariantTransactionData(txData.amount, txData.expiry, 0); } // Declare these variables for the event emission. Are only assigned // IFF there is an external call on the receiving chain bool success; bytes memory returnData; if (txData.sendingChainId == getChainId()) { // The router is completing the transaction, they should get the // amount that the user deposited credited to their liquidity // reserves. // Make sure that the user is not accidentally fulfilling the transaction // on the sending chain require(msg.sender == txData.router, "#F:016"); // Complete tx to router for original sending amount routerBalances[txData.router][txData.sendingAssetId] += txData.amount; } else { (success, returnData) = _receivingChainFulfill(txData, relayerFee, callData); } // Emit event emit TransactionFulfilled( txData.user, txData.router, txData.transactionId, txData, relayerFee, signature, callData, success, returnData, msg.sender ); return txData; } /** * @notice Any crosschain transaction can be cancelled after it has been * created to prevent indefinite lock up of funds. After the * transaction has expired, anyone can cancel it. Before the * expiry, only the recipient of the funds on the given chain is * able to cancel. On the sending chain, this means only the router * is able to cancel before the expiry, while only the user can * prematurely cancel on the receiving chain. * @param txData All of the data (invariant and variant) for a crosschain * transaction. The variant data provided is checked against * what was stored when the `prepare` function was called. * @param signature The user's signature that allows a transaction to be * cancelled by a relayer */ function cancel(TransactionData calldata txData, bytes calldata signature) external override nonReentrant returns (TransactionData memory) { // Make sure params match against stored data // Also checks that there is an active transfer here // Also checks that sender or receiver chainID is this chainId (bc we checked it previously) // Get the hash of the invariant tx data. This hash is the same // between sending and receiving chains. The variant data is stored // in the contract when `prepare` is called within the mapping. bytes32 digest = hashInvariantTransactionData(txData); // Verify the variant data is correct require(variantTransactionData[digest] == hashVariantTransactionData(txData.amount, txData.expiry, txData.preparedBlockNumber), "#C:019"); // Make sure the transaction wasn't already completed require(txData.preparedBlockNumber > 0, "#C:021"); // To prevent `fulfill` / `cancel` from being called multiple times, the // preparedBlockNumber is set to 0 before being hashed. The value of the // mapping is explicitly *not* zeroed out so users who come online without // a store can tell the difference between a transaction that has not been // prepared, and a transaction that was already completed on the receiver // chain. variantTransactionData[digest] = hashVariantTransactionData(txData.amount, txData.expiry, 0); // Get chainId for gas uint256 _chainId = getChainId(); // Return the appropriate locked funds if (txData.sendingChainId == _chainId) { // Sender side, funds must be returned to the user if (txData.expiry >= block.timestamp) { // Timeout has not expired and tx may only be cancelled by router // NOTE: no need to validate the signature here, since you are requiring // the router must be the sender when the cancellation is during the // fulfill-able window require(msg.sender == txData.router, "#C:025"); } // Return users locked funds // NOTE: no need to check if amount > 0 because cant be prepared on // sending chain with 0 value LibAsset.transferAsset(txData.sendingAssetId, payable(txData.sendingChainFallback), txData.amount); } else { // Receiver side, router liquidity is returned if (txData.expiry >= block.timestamp) { // Timeout has not expired and tx may only be cancelled by user // Validate signature require(msg.sender == txData.user || recoverCancelSignature(txData.transactionId, _chainId, address(this), signature) == txData.user, "#C:022"); // NOTE: there is no incentive here for relayers to submit this on // behalf of the user (i.e. fee not respected) because the user has not // locked funds on this contract. However, if the user reveals their // cancel signature to the router, they are incentivized to submit it // to unlock their own funds } // Return liquidity to router routerBalances[txData.router][txData.receivingAssetId] += txData.amount; } // Emit event emit TransactionCancelled(txData.user, txData.router, txData.transactionId, txData, msg.sender); // Return return txData; } ////////////////////////// /// Private functions /// ////////////////////////// /** * @notice Contains the logic to verify + increment a given routers liquidity * @param amount The amount of liquidity to add for the router * @param assetId The address (or `address(0)` if native asset) of the * asset you're adding liquidity for * @param router The router you are adding liquidity on behalf of */ function _addLiquidityForRouter( uint256 amount, address assetId, address router ) internal { // Sanity check: router is sensible require(router != address(0), "#AL:001"); // Sanity check: nonzero amounts require(amount > 0, "#AL:002"); // Router is approved require(isRouterOwnershipRenounced() || approvedRouters[router], "#AL:003"); // Asset is approved require(isAssetOwnershipRenounced() || approvedAssets[assetId], "#AL:004"); // Transfer funds to contract amount = transferAssetToContract(assetId, amount); // Update the router balances. Happens after pulling funds to account for // the fee on transfer tokens routerBalances[router][assetId] += amount; // Emit event emit LiquidityAdded(router, assetId, amount, msg.sender); } /** * @notice Handles transferring funds from msg.sender to the * transaction manager contract. Used in prepare, addLiquidity * @param assetId The address to transfer * @param specifiedAmount The specified amount to transfer. May not be the * actual amount transferred (i.e. fee on transfer * tokens) */ function transferAssetToContract(address assetId, uint256 specifiedAmount) internal returns (uint256) { uint256 trueAmount = specifiedAmount; // Validate correct amounts are transferred if (LibAsset.isNativeAsset(assetId)) { require(msg.value == specifiedAmount, "#TA:005"); } else { uint256 starting = LibAsset.getOwnBalance(assetId); require(msg.value == 0, "#TA:006"); LibAsset.transferFromERC20(assetId, msg.sender, address(this), specifiedAmount); // Calculate the *actual* amount that was sent here trueAmount = LibAsset.getOwnBalance(assetId) - starting; } return trueAmount; } /// @notice Recovers the signer from the signature provided by the user /// @param transactionId Transaction identifier of tx being recovered /// @param signature The signature you are recovering the signer from function recoverCancelSignature( bytes32 transactionId, uint256 receivingChainId, address receivingChainTxManagerAddress, bytes calldata signature ) internal pure returns (address) { // Create the signed payload SignedCancelData memory payload = SignedCancelData({ transactionId: transactionId, functionIdentifier: "cancel", receivingChainId: receivingChainId, receivingChainTxManagerAddress: receivingChainTxManagerAddress }); // Recover return recoverSignature(abi.encode(payload), signature); } /** * @notice Recovers the signer from the signature provided by the user * @param transactionId Transaction identifier of tx being recovered * @param relayerFee The fee paid to the relayer for submitting the * tx on behalf of the user. * @param signature The signature you are recovering the signer from */ function recoverFulfillSignature( bytes32 transactionId, uint256 relayerFee, uint256 receivingChainId, address receivingChainTxManagerAddress, bytes calldata signature ) internal pure returns (address) { // Create the signed payload SignedFulfillData memory payload = SignedFulfillData({ transactionId: transactionId, relayerFee: relayerFee, functionIdentifier: "fulfill", receivingChainId: receivingChainId, receivingChainTxManagerAddress: receivingChainTxManagerAddress }); // Recover return recoverSignature(abi.encode(payload), signature); } /** * @notice Holds the logic to recover the signer from an encoded payload. * Will hash and convert to an eth signed message. * @param encodedPayload The payload that was signed * @param signature The signature you are recovering the signer from */ function recoverSignature(bytes memory encodedPayload, bytes calldata signature) internal pure returns (address) { // Recover return ECDSA.recover( ECDSA.toEthSignedMessageHash(keccak256(encodedPayload)), signature ); } /** * @notice Returns the hash of only the invariant portions of a given * crosschain transaction * @param txData TransactionData to hash */ function hashInvariantTransactionData(TransactionData calldata txData) internal pure returns (bytes32) { InvariantTransactionData memory invariant = InvariantTransactionData({ receivingChainTxManagerAddress: txData.receivingChainTxManagerAddress, user: txData.user, router: txData.router, sendingAssetId: txData.sendingAssetId, receivingAssetId: txData.receivingAssetId, sendingChainFallback: txData.sendingChainFallback, callTo: txData.callTo, receivingAddress: txData.receivingAddress, sendingChainId: txData.sendingChainId, receivingChainId: txData.receivingChainId, callDataHash: txData.callDataHash, transactionId: txData.transactionId }); return keccak256(abi.encode(invariant)); } /** * @notice Returns the hash of only the variant portions of a given * crosschain transaction * @param amount amount to hash * @param expiry expiry to hash * @param preparedBlockNumber preparedBlockNumber to hash * @return Hash of the variant data * */ function hashVariantTransactionData(uint256 amount, uint256 expiry, uint256 preparedBlockNumber) internal pure returns (bytes32) { VariantTransactionData memory variant = VariantTransactionData({ amount: amount, expiry: expiry, preparedBlockNumber: preparedBlockNumber }); return keccak256(abi.encode(variant)); } /** * @notice Handles the receiving-chain fulfillment. This function should * pay the relayer and either send funds to the specified address * or execute the calldata. Will return a tuple of boolean,bytes * indicating the success and return data of the external call. * @dev Separated from fulfill function to avoid stack too deep errors * * @param txData The TransactionData that needs to be fulfilled * @param relayerFee The fee to be paid to the relayer for submission * @param callData The data to be executed on the receiving chain * * @return Tuple representing (success, returnData) of the external call */ function _receivingChainFulfill( TransactionData calldata txData, uint256 relayerFee, bytes calldata callData ) internal returns (bool, bytes memory) { // The user is completing the transaction, they should get the // amount that the router deposited less fees for relayer. // Get the amount to send uint256 toSend; unchecked { toSend = txData.amount - relayerFee; } // Send the relayer the fee if (relayerFee > 0) { LibAsset.transferAsset(txData.receivingAssetId, payable(msg.sender), relayerFee); } // Handle receiver chain external calls if needed if (txData.callTo == address(0)) { // No external calls, send directly to receiving address if (toSend > 0) { LibAsset.transferAsset(txData.receivingAssetId, payable(txData.receivingAddress), toSend); } return (false, new bytes(0)); } else { // Handle external calls with a fallback to the receiving // address in case the call fails so the funds dont remain // locked. bool isNativeAsset = LibAsset.isNativeAsset(txData.receivingAssetId); // First, transfer the funds to the helper if needed if (!isNativeAsset && toSend > 0) { LibAsset.transferERC20(txData.receivingAssetId, address(interpreter), toSend); } // Next, call `execute` on the helper. Helpers should internally // track funds to make sure no one user is able to take all funds // for tx, and handle the case of reversions return interpreter.execute{ value: isNativeAsset ? toSend : 0}( txData.transactionId, payable(txData.callTo), txData.receivingAssetId, payable(txData.receivingAddress), toSend, callData ); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _setOwner(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _setOwner(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _setOwner(newOwner); } function _setOwner(address newOwner) private { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @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: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; assembly { size := extcodesize(account) } return size > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) private pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { // Check the signature length // - case 65: r,s,v signature (standard) // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._ if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return recover(hash, v, r, s); } else if (signature.length == 64) { bytes32 r; bytes32 vs; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. assembly { r := mload(add(signature, 0x20)) vs := mload(add(signature, 0x40)) } return recover(hash, r, vs); } else { revert("ECDSA: invalid signature length"); } } /** * @dev Overload of {ECDSA-recover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.2._ */ function recover( bytes32 hash, bytes32 r, bytes32 vs ) internal pure returns (address) { bytes32 s; uint8 v; assembly { s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) v := add(shr(255, vs), 27) } return recover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, `r` and `s` signature fields separately. */ function recover( bytes32 hash, uint8 v, bytes32 r, bytes32 s ) internal pure returns (address) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. require( uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value" ); require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value"); // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); require(signer != address(0), "ECDSA: invalid signature"); return signer; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) { // 32 is the length in bytes of hash, // enforced by the type signature above return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.4; /** * @title ProposedOwnable * @notice Contract module which provides a basic access control mechanism, * where there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed via a two step process: * 1. Call `proposeOwner` * 2. Wait out the delay period * 3. Call `acceptOwner` * * @dev This module is used through inheritance. It will make available the * modifier `onlyOwner`, which can be applied to your functions to restrict * their use to the owner. * * @dev The majority of this code was taken from the openzeppelin Ownable * contract * */ abstract contract ProposedOwnable { address private _owner; address private _proposed; uint256 private _proposedOwnershipTimestamp; bool private _routerOwnershipRenounced; uint256 private _routerOwnershipTimestamp; bool private _assetOwnershipRenounced; uint256 private _assetOwnershipTimestamp; uint256 private constant _delay = 7 days; event RouterOwnershipRenunciationProposed(uint256 timestamp); event RouterOwnershipRenounced(bool renounced); event AssetOwnershipRenunciationProposed(uint256 timestamp); event AssetOwnershipRenounced(bool renounced); event OwnershipProposed(address indexed proposedOwner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @notice Initializes the contract setting the deployer as the initial * owner. */ constructor() { _setOwner(msg.sender); } /** * @notice Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @notice Returns the address of the proposed owner. */ function proposed() public view virtual returns (address) { return _proposed; } /** * @notice Returns the address of the proposed owner. */ function proposedTimestamp() public view virtual returns (uint256) { return _proposedOwnershipTimestamp; } /** * @notice Returns the timestamp when router ownership was last proposed to be renounced */ function routerOwnershipTimestamp() public view virtual returns (uint256) { return _routerOwnershipTimestamp; } /** * @notice Returns the timestamp when asset ownership was last proposed to be renounced */ function assetOwnershipTimestamp() public view virtual returns (uint256) { return _assetOwnershipTimestamp; } /** * @notice Returns the delay period before a new owner can be accepted. */ function delay() public view virtual returns (uint256) { return _delay; } /** * @notice Throws if called by any account other than the owner. */ modifier onlyOwner() { require(_owner == msg.sender, "#OO:029"); _; } /** * @notice Throws if called by any account other than the proposed owner. */ modifier onlyProposed() { require(_proposed == msg.sender, "#OP:035"); _; } /** * @notice Indicates if the ownership of the router whitelist has * been renounced */ function isRouterOwnershipRenounced() public view returns (bool) { return _owner == address(0) || _routerOwnershipRenounced; } /** * @notice Indicates if the ownership of the router whitelist has * been renounced */ function proposeRouterOwnershipRenunciation() public virtual onlyOwner { // Use contract as source of truth // Will fail if all ownership is renounced by modifier require(!_routerOwnershipRenounced, "#PROR:038"); // Begin delay, emit event _setRouterOwnershipTimestamp(); } /** * @notice Indicates if the ownership of the asset whitelist has * been renounced */ function renounceRouterOwnership() public virtual onlyOwner { // Contract as sournce of truth // Will fail if all ownership is renounced by modifier require(!_routerOwnershipRenounced, "#RRO:038"); // Ensure there has been a proposal cycle started require(_routerOwnershipTimestamp > 0, "#RRO:037"); // Delay has elapsed require((block.timestamp - _routerOwnershipTimestamp) > _delay, "#RRO:030"); // Set renounced, emit event, reset timestamp to 0 _setRouterOwnership(true); } /** * @notice Indicates if the ownership of the asset whitelist has * been renounced */ function isAssetOwnershipRenounced() public view returns (bool) { return _owner == address(0) || _assetOwnershipRenounced; } /** * @notice Indicates if the ownership of the asset whitelist has * been renounced */ function proposeAssetOwnershipRenunciation() public virtual onlyOwner { // Contract as sournce of truth // Will fail if all ownership is renounced by modifier require(!_assetOwnershipRenounced, "#PAOR:038"); // Start cycle, emit event _setAssetOwnershipTimestamp(); } /** * @notice Indicates if the ownership of the asset whitelist has * been renounced */ function renounceAssetOwnership() public virtual onlyOwner { // Contract as sournce of truth // Will fail if all ownership is renounced by modifier require(!_assetOwnershipRenounced, "#RAO:038"); // Ensure there has been a proposal cycle started require(_assetOwnershipTimestamp > 0, "#RAO:037"); // Ensure delay has elapsed require((block.timestamp - _assetOwnershipTimestamp) > _delay, "#RAO:030"); // Set ownership, reset timestamp, emit event _setAssetOwnership(true); } /** * @notice Indicates if the ownership has been renounced() by * checking if current owner is address(0) */ function renounced() public view returns (bool) { return _owner == address(0); } /** * @notice Sets the timestamp for an owner to be proposed, and sets the * newly proposed owner as step 1 in a 2-step process */ function proposeNewOwner(address newlyProposed) public virtual onlyOwner { // Contract as source of truth require(_proposed != newlyProposed || newlyProposed == address(0), "#PNO:036"); // Sanity check: reasonable proposal require(_owner != newlyProposed, "#PNO:038"); _setProposed(newlyProposed); } /** * @notice Renounces ownership of the contract after a delay */ function renounceOwnership() public virtual onlyOwner { // Ensure there has been a proposal cycle started require(_proposedOwnershipTimestamp > 0, "#RO:037"); // Ensure delay has elapsed require((block.timestamp - _proposedOwnershipTimestamp) > _delay, "#RO:030"); // Require proposed is set to 0 require(_proposed == address(0), "#RO:036"); // Emit event, set new owner, reset timestamp _setOwner(_proposed); } /** * @notice Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function acceptProposedOwner() public virtual onlyProposed { // Contract as source of truth require(_owner != _proposed, "#APO:038"); // NOTE: no need to check if _proposedOwnershipTimestamp > 0 because // the only time this would happen is if the _proposed was never // set (will fail from modifier) or if the owner == _proposed (checked // above) // Ensure delay has elapsed require((block.timestamp - _proposedOwnershipTimestamp) > _delay, "#APO:030"); // Emit event, set new owner, reset timestamp _setOwner(_proposed); } ////// INTERNAL ////// function _setRouterOwnershipTimestamp() private { _routerOwnershipTimestamp = block.timestamp; emit RouterOwnershipRenunciationProposed(_routerOwnershipTimestamp); } function _setRouterOwnership(bool value) private { _routerOwnershipRenounced = value; _routerOwnershipTimestamp = 0; emit RouterOwnershipRenounced(value); } function _setAssetOwnershipTimestamp() private { _assetOwnershipTimestamp = block.timestamp; emit AssetOwnershipRenunciationProposed(_assetOwnershipTimestamp); } function _setAssetOwnership(bool value) private { _assetOwnershipRenounced = value; _assetOwnershipTimestamp = 0; emit AssetOwnershipRenounced(value); } function _setOwner(address newOwner) private { address oldOwner = _owner; _owner = newOwner; _proposedOwnershipTimestamp = 0; emit OwnershipTransferred(oldOwner, newOwner); } function _setProposed(address newlyProposed) private { _proposedOwnershipTimestamp = block.timestamp; _proposed = newlyProposed; emit OwnershipProposed(_proposed); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.4; interface IFulfillInterpreter { event Executed( bytes32 indexed transactionId, address payable callTo, address assetId, address payable fallbackAddress, uint256 amount, bytes callData, bytes returnData, bool success ); function getTransactionManager() external returns (address); function execute( bytes32 transactionId, address payable callTo, address assetId, address payable fallbackAddress, uint256 amount, bytes calldata callData ) external payable returns (bool success, bytes memory returnData); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.4; interface ITransactionManager { // Structs // Holds all data that is constant between sending and // receiving chains. The hash of this is what gets signed // to ensure the signature can be used on both chains. struct InvariantTransactionData { address receivingChainTxManagerAddress; address user; address router; address sendingAssetId; address receivingAssetId; address sendingChainFallback; // funds sent here on cancel address receivingAddress; address callTo; uint256 sendingChainId; uint256 receivingChainId; bytes32 callDataHash; // hashed to prevent free option bytes32 transactionId; } // Holds all data that varies between sending and receiving // chains. The hash of this is stored onchain to ensure the // information passed in is valid. struct VariantTransactionData { uint256 amount; uint256 expiry; uint256 preparedBlockNumber; } // All Transaction data, constant and variable struct TransactionData { address receivingChainTxManagerAddress; address user; address router; address sendingAssetId; address receivingAssetId; address sendingChainFallback; address receivingAddress; address callTo; bytes32 callDataHash; bytes32 transactionId; uint256 sendingChainId; uint256 receivingChainId; uint256 amount; uint256 expiry; uint256 preparedBlockNumber; // Needed for removal of active blocks on fulfill/cancel } // The structure of the signed data for fulfill struct SignedFulfillData { bytes32 transactionId; uint256 relayerFee; string functionIdentifier; // "fulfill" or "cancel" uint256 receivingChainId; // For domain separation address receivingChainTxManagerAddress; // For domain separation } // The structure of the signed data for cancellation struct SignedCancelData { bytes32 transactionId; string functionIdentifier; uint256 receivingChainId; address receivingChainTxManagerAddress; // For domain separation } // Adding/removing asset events event RouterAdded(address indexed addedRouter, address indexed caller); event RouterRemoved(address indexed removedRouter, address indexed caller); // Adding/removing router events event AssetAdded(address indexed addedAssetId, address indexed caller); event AssetRemoved(address indexed removedAssetId, address indexed caller); // Liquidity events event LiquidityAdded(address indexed router, address indexed assetId, uint256 amount, address caller); event LiquidityRemoved(address indexed router, address indexed assetId, uint256 amount, address recipient); // Transaction events event TransactionPrepared( address indexed user, address indexed router, bytes32 indexed transactionId, TransactionData txData, address caller, bytes encryptedCallData, bytes encodedBid, bytes bidSignature ); event TransactionFulfilled( address indexed user, address indexed router, bytes32 indexed transactionId, TransactionData txData, uint256 relayerFee, bytes signature, bytes callData, bool success, bytes returnData, address caller ); event TransactionCancelled( address indexed user, address indexed router, bytes32 indexed transactionId, TransactionData txData, address caller ); // Getters function getChainId() external view returns (uint256); function getStoredChainId() external view returns (uint256); // Owner only methods function addRouter(address router) external; function removeRouter(address router) external; function addAssetId(address assetId) external; function removeAssetId(address assetId) external; // Router only methods function addLiquidityFor(uint256 amount, address assetId, address router) external payable; function addLiquidity(uint256 amount, address assetId) external payable; function removeLiquidity( uint256 amount, address assetId, address payable recipient ) external; // Methods for crosschain transfers // called in the following order (in happy case) // 1. prepare by user on sending chain // 2. prepare by router on receiving chain // 3. fulfill by user on receiving chain // 4. fulfill by router on sending chain function prepare( InvariantTransactionData calldata txData, uint256 amount, uint256 expiry, bytes calldata encryptedCallData, bytes calldata encodedBid, bytes calldata bidSignature ) external payable returns (TransactionData memory); function fulfill( TransactionData calldata txData, uint256 relayerFee, bytes calldata signature, bytes calldata callData ) external returns (TransactionData memory); function cancel(TransactionData calldata txData, bytes calldata signature) external returns (TransactionData memory); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.4; import "../interfaces/IFulfillInterpreter.sol"; import "../lib/LibAsset.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; /** * @title FulfillInterpreter * @author Connext <[email protected]> * @notice This library contains an `execute` function that is callabale by * an associated TransactionManager contract. This is used to execute * arbitrary calldata on a receiving chain. */ contract FulfillInterpreter is ReentrancyGuard, IFulfillInterpreter { address private immutable _transactionManager; constructor(address transactionManager) { _transactionManager = transactionManager; } /** * @notice Errors if the sender is not the transaction manager */ modifier onlyTransactionManager { require(msg.sender == _transactionManager, "#OTM:027"); _; } /** * @notice Returns the transaction manager address (only address that can * call the `execute` function) * @return The address of the associated transaction manager */ function getTransactionManager() override external view returns (address) { return _transactionManager; } /** * @notice Executes some arbitrary call data on a given address. The * call data executes can be payable, and will have `amount` sent * along with the function (or approved to the contract). If the * call fails, rather than reverting, funds are sent directly to * some provided fallbaack address * @param transactionId Unique identifier of transaction id that necessitated * calldata execution * @param callTo The address to execute the calldata on * @param assetId The assetId of the funds to approve to the contract or * send along with the call * @param fallbackAddress The address to send funds to if the `call` fails * @param amount The amount to approve or send with the call * @param callData The data to execute */ function execute( bytes32 transactionId, address payable callTo, address assetId, address payable fallbackAddress, uint256 amount, bytes calldata callData ) override external payable onlyTransactionManager returns (bool, bytes memory) { // If it is not ether, approve the callTo // We approve here rather than transfer since many external contracts // simply require an approval, and it is unclear if they can handle // funds transferred directly to them (i.e. Uniswap) bool isNative = LibAsset.isNativeAsset(assetId); if (!isNative) { LibAsset.increaseERC20Allowance(assetId, callTo, amount); } // Check if the callTo is a contract bool success; bytes memory returnData; if (Address.isContract(callTo)) { // Try to execute the callData // the low level call will return `false` if its execution reverts (success, returnData) = callTo.call{value: isNative ? amount : 0}(callData); } // Handle failure cases if (!success) { // If it fails, transfer to fallback LibAsset.transferAsset(assetId, fallbackAddress, amount); // Decrease allowance if (!isNative) { LibAsset.decreaseERC20Allowance(assetId, callTo, amount); } } // Emit event emit Executed( transactionId, callTo, assetId, fallbackAddress, amount, callData, returnData, success ); return (success, returnData); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.4; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title LibAsset * @author Connext <[email protected]> * @notice This library contains helpers for dealing with onchain transfers * of assets, including accounting for the native asset `assetId` * conventions and any noncompliant ERC20 transfers */ library LibAsset { /** * @dev All native assets use the empty address for their asset id * by convention */ address constant NATIVE_ASSETID = address(0); /** * @notice Determines whether the given assetId is the native asset * @param assetId The asset identifier to evaluate * @return Boolean indicating if the asset is the native asset */ function isNativeAsset(address assetId) internal pure returns (bool) { return assetId == NATIVE_ASSETID; } /** * @notice Gets the balance of the inheriting contract for the given asset * @param assetId The asset identifier to get the balance of * @return Balance held by contracts using this library */ function getOwnBalance(address assetId) internal view returns (uint256) { return isNativeAsset(assetId) ? address(this).balance : IERC20(assetId).balanceOf(address(this)); } /** * @notice Transfers ether from the inheriting contract to a given * recipient * @param recipient Address to send ether to * @param amount Amount to send to given recipient */ function transferNativeAsset(address payable recipient, uint256 amount) internal { (bool success,) = recipient.call{value: amount}(""); require(success, "#TNA:028"); } /** * @notice Transfers tokens from the inheriting contract to a given * recipient * @param assetId Token address to transfer * @param recipient Address to send ether to * @param amount Amount to send to given recipient */ function transferERC20( address assetId, address recipient, uint256 amount ) internal { SafeERC20.safeTransfer(IERC20(assetId), recipient, amount); } /** * @notice Transfers tokens from a sender to a given recipient * @param assetId Token address to transfer * @param from Address of sender/owner * @param to Address of recipient/spender * @param amount Amount to transfer from owner to spender */ function transferFromERC20( address assetId, address from, address to, uint256 amount ) internal { SafeERC20.safeTransferFrom(IERC20(assetId), from, to, amount); } /** * @notice Increases the allowance of a token to a spender * @param assetId Token address of asset to increase allowance of * @param spender Account whos allowance is increased * @param amount Amount to increase allowance by */ function increaseERC20Allowance( address assetId, address spender, uint256 amount ) internal { require(!isNativeAsset(assetId), "#IA:034"); SafeERC20.safeIncreaseAllowance(IERC20(assetId), spender, amount); } /** * @notice Decreases the allowance of a token to a spender * @param assetId Token address of asset to decrease allowance of * @param spender Account whos allowance is decreased * @param amount Amount to decrease allowance by */ function decreaseERC20Allowance( address assetId, address spender, uint256 amount ) internal { require(!isNativeAsset(assetId), "#DA:034"); SafeERC20.safeDecreaseAllowance(IERC20(assetId), spender, amount); } /** * @notice Wrapper function to transfer a given asset (native or erc20) to * some recipient. Should handle all non-compliant return value * tokens as well by using the SafeERC20 contract by open zeppelin. * @param assetId Asset id for transfer (address(0) for native asset, * token address for erc20s) * @param recipient Address to send asset to * @param amount Amount to send to given recipient */ function transferAsset( address assetId, address payable recipient, uint256 amount ) internal { isNativeAsset(assetId) ? transferNativeAsset(recipient, amount) : transferERC20(assetId, recipient, amount); } }
{ "evmVersion": "istanbul", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 200 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addedAssetId","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"}],"name":"AssetAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"renounced","type":"bool"}],"name":"AssetOwnershipRenounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"AssetOwnershipRenunciationProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"removedAssetId","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"}],"name":"AssetRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"router","type":"address"},{"indexed":true,"internalType":"address","name":"assetId","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"LiquidityAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"router","type":"address"},{"indexed":true,"internalType":"address","name":"assetId","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"}],"name":"LiquidityRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"proposedOwner","type":"address"}],"name":"OwnershipProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addedRouter","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"}],"name":"RouterAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"renounced","type":"bool"}],"name":"RouterOwnershipRenounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"RouterOwnershipRenunciationProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"removedRouter","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"}],"name":"RouterRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"router","type":"address"},{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"sendingAssetId","type":"address"},{"internalType":"address","name":"receivingAssetId","type":"address"},{"internalType":"address","name":"sendingChainFallback","type":"address"},{"internalType":"address","name":"receivingAddress","type":"address"},{"internalType":"address","name":"callTo","type":"address"},{"internalType":"bytes32","name":"callDataHash","type":"bytes32"},{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"uint256","name":"sendingChainId","type":"uint256"},{"internalType":"uint256","name":"receivingChainId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"preparedBlockNumber","type":"uint256"}],"indexed":false,"internalType":"struct ITransactionManager.TransactionData","name":"txData","type":"tuple"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"TransactionCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"router","type":"address"},{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"sendingAssetId","type":"address"},{"internalType":"address","name":"receivingAssetId","type":"address"},{"internalType":"address","name":"sendingChainFallback","type":"address"},{"internalType":"address","name":"receivingAddress","type":"address"},{"internalType":"address","name":"callTo","type":"address"},{"internalType":"bytes32","name":"callDataHash","type":"bytes32"},{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"uint256","name":"sendingChainId","type":"uint256"},{"internalType":"uint256","name":"receivingChainId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"preparedBlockNumber","type":"uint256"}],"indexed":false,"internalType":"struct ITransactionManager.TransactionData","name":"txData","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"relayerFee","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"signature","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"callData","type":"bytes"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"bytes","name":"returnData","type":"bytes"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"TransactionFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"router","type":"address"},{"indexed":true,"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"sendingAssetId","type":"address"},{"internalType":"address","name":"receivingAssetId","type":"address"},{"internalType":"address","name":"sendingChainFallback","type":"address"},{"internalType":"address","name":"receivingAddress","type":"address"},{"internalType":"address","name":"callTo","type":"address"},{"internalType":"bytes32","name":"callDataHash","type":"bytes32"},{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"uint256","name":"sendingChainId","type":"uint256"},{"internalType":"uint256","name":"receivingChainId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"preparedBlockNumber","type":"uint256"}],"indexed":false,"internalType":"struct ITransactionManager.TransactionData","name":"txData","type":"tuple"},{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"bytes","name":"encryptedCallData","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"encodedBid","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"bidSignature","type":"bytes"}],"name":"TransactionPrepared","type":"event"},{"inputs":[],"name":"MAX_TIMEOUT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_TIMEOUT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptProposedOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"assetId","type":"address"}],"name":"addAssetId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"assetId","type":"address"}],"name":"addLiquidity","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"assetId","type":"address"},{"internalType":"address","name":"router","type":"address"}],"name":"addLiquidityFor","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"router","type":"address"}],"name":"addRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approvedAssets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"approvedRouters","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetOwnershipTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"sendingAssetId","type":"address"},{"internalType":"address","name":"receivingAssetId","type":"address"},{"internalType":"address","name":"sendingChainFallback","type":"address"},{"internalType":"address","name":"receivingAddress","type":"address"},{"internalType":"address","name":"callTo","type":"address"},{"internalType":"bytes32","name":"callDataHash","type":"bytes32"},{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"uint256","name":"sendingChainId","type":"uint256"},{"internalType":"uint256","name":"receivingChainId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"preparedBlockNumber","type":"uint256"}],"internalType":"struct ITransactionManager.TransactionData","name":"txData","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"cancel","outputs":[{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"sendingAssetId","type":"address"},{"internalType":"address","name":"receivingAssetId","type":"address"},{"internalType":"address","name":"sendingChainFallback","type":"address"},{"internalType":"address","name":"receivingAddress","type":"address"},{"internalType":"address","name":"callTo","type":"address"},{"internalType":"bytes32","name":"callDataHash","type":"bytes32"},{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"uint256","name":"sendingChainId","type":"uint256"},{"internalType":"uint256","name":"receivingChainId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"preparedBlockNumber","type":"uint256"}],"internalType":"struct ITransactionManager.TransactionData","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"sendingAssetId","type":"address"},{"internalType":"address","name":"receivingAssetId","type":"address"},{"internalType":"address","name":"sendingChainFallback","type":"address"},{"internalType":"address","name":"receivingAddress","type":"address"},{"internalType":"address","name":"callTo","type":"address"},{"internalType":"bytes32","name":"callDataHash","type":"bytes32"},{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"uint256","name":"sendingChainId","type":"uint256"},{"internalType":"uint256","name":"receivingChainId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"preparedBlockNumber","type":"uint256"}],"internalType":"struct ITransactionManager.TransactionData","name":"txData","type":"tuple"},{"internalType":"uint256","name":"relayerFee","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"fulfill","outputs":[{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"sendingAssetId","type":"address"},{"internalType":"address","name":"receivingAssetId","type":"address"},{"internalType":"address","name":"sendingChainFallback","type":"address"},{"internalType":"address","name":"receivingAddress","type":"address"},{"internalType":"address","name":"callTo","type":"address"},{"internalType":"bytes32","name":"callDataHash","type":"bytes32"},{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"uint256","name":"sendingChainId","type":"uint256"},{"internalType":"uint256","name":"receivingChainId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"preparedBlockNumber","type":"uint256"}],"internalType":"struct ITransactionManager.TransactionData","name":"","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getChainId","outputs":[{"internalType":"uint256","name":"_chainId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStoredChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"interpreter","outputs":[{"internalType":"contract IFulfillInterpreter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isAssetOwnershipRenounced","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isRouterOwnershipRenounced","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"sendingAssetId","type":"address"},{"internalType":"address","name":"receivingAssetId","type":"address"},{"internalType":"address","name":"sendingChainFallback","type":"address"},{"internalType":"address","name":"receivingAddress","type":"address"},{"internalType":"address","name":"callTo","type":"address"},{"internalType":"uint256","name":"sendingChainId","type":"uint256"},{"internalType":"uint256","name":"receivingChainId","type":"uint256"},{"internalType":"bytes32","name":"callDataHash","type":"bytes32"},{"internalType":"bytes32","name":"transactionId","type":"bytes32"}],"internalType":"struct ITransactionManager.InvariantTransactionData","name":"invariantData","type":"tuple"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"bytes","name":"encryptedCallData","type":"bytes"},{"internalType":"bytes","name":"encodedBid","type":"bytes"},{"internalType":"bytes","name":"bidSignature","type":"bytes"}],"name":"prepare","outputs":[{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"sendingAssetId","type":"address"},{"internalType":"address","name":"receivingAssetId","type":"address"},{"internalType":"address","name":"sendingChainFallback","type":"address"},{"internalType":"address","name":"receivingAddress","type":"address"},{"internalType":"address","name":"callTo","type":"address"},{"internalType":"bytes32","name":"callDataHash","type":"bytes32"},{"internalType":"bytes32","name":"transactionId","type":"bytes32"},{"internalType":"uint256","name":"sendingChainId","type":"uint256"},{"internalType":"uint256","name":"receivingChainId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint256","name":"preparedBlockNumber","type":"uint256"}],"internalType":"struct ITransactionManager.TransactionData","name":"","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"proposeAssetOwnershipRenunciation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newlyProposed","type":"address"}],"name":"proposeNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proposeRouterOwnershipRenunciation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proposed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposedTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"assetId","type":"address"}],"name":"removeAssetId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"assetId","type":"address"},{"internalType":"address payable","name":"recipient","type":"address"}],"name":"removeLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"router","type":"address"}],"name":"removeRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceAssetOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceRouterOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounced","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"routerBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"routerOwnershipTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"variantTransactionData","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c06040523480156200001157600080fd5b5060405162004c3038038062004c30833981016040819052620000349162000105565b600160005562000044336200009e565b608081905260405130906200005990620000f7565b6001600160a01b039091168152602001604051809103906000f08015801562000086573d6000803e3d6000fd5b5060601b6001600160601b03191660a052506200011e565b600180546001600160a01b038381166001600160a01b0319831681179093556000600381905560405191909216929183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610b2d806200410383390190565b60006020828403121562000117578081fd5b5051919050565b60805160a05160601c613fa76200015c600039600081816102ee01528181612758015261277f01526000818161026401526107890152613fa76000f3fe6080604052600436106102045760003560e01c8063715018a611610118578063c5b350df116100a0578063de38eb3a1161006f578063de38eb3a146105db578063e070da09146105f2578063e47602f714610605578063e8be0dfc1461061a578063f31abcc41461062f57600080fd5b8063c5b350df14610576578063c95f9d0e1461058b578063d1851c921461059e578063d232c220146105bc57600080fd5b806397eb0088116100e757806397eb0088146104dc578063b1d2618d1461050c578063b1f8100d1461052c578063c0c17baf1461054c578063c1a049591461056157600080fd5b8063715018a6146104745780637bac72b5146104895780638741eac5146104a95780638da5cb5b146104be57600080fd5b806341258b5c1161019b57806363405b931161016a57806363405b93146103e957806367df6017146104095780636a41633a146104295780636a42b8f81461043e5780636ae0b1541461045457600080fd5b806341258b5c1461033d578063445b1e4b14610375578063543ad1df146103a55780635e679856146103bc57600080fd5b806334e9393c116101d757806334e9393c146102a75780633855b467146102c75780633a35cf17146102dc5780633cf52ffb1461032857600080fd5b80632004ef451461020957806324ca984e1461023357806332a130c9146102555780633408e47014610292575b600080fd5b34801561021557600080fd5b5061021e61064f565b60405190151581526020015b60405180910390f35b34801561023f57600080fd5b5061025361024e366004613314565b610671565b005b34801561026157600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405190815260200161022a565b34801561029e57600080fd5b50610284610785565b3480156102b357600080fd5b506102536102c2366004613314565b6107b9565b3480156102d357600080fd5b50610253610884565b3480156102e857600080fd5b506103107f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161022a565b34801561033457600080fd5b50600354610284565b34801561034957600080fd5b50610284610358366004613330565b600860209081526000928352604080842090915290825290205481565b34801561038157600080fd5b5061021e610390366004613314565b60096020526000908152604090205460ff1681565b3480156103b157600080fd5b506102846201518081565b3480156103c857600080fd5b506102846103d736600461343e565b600b6020526000908152604090205481565b6103fc6103f7366004613456565b61097f565b60405161022a9190613e2d565b34801561041557600080fd5b506103fc61042436600461351e565b611278565b34801561043557600080fd5b50600754610284565b34801561044a57600080fd5b5062093a80610284565b34801561046057600080fd5b5061025361046f366004613314565b6115d4565b34801561048057600080fd5b506102536116e0565b34801561049557600080fd5b506103fc6104a4366004613572565b6117e7565b3480156104b557600080fd5b50610253611bd3565b3480156104ca57600080fd5b506001546001600160a01b0316610310565b3480156104e857600080fd5b5061021e6104f7366004613314565b600a6020526000908152604090205460ff1681565b34801561051857600080fd5b50610253610527366004613314565b611c44565b34801561053857600080fd5b50610253610547366004613314565b611d10565b34801561055857600080fd5b50610253611dea565b34801561056d57600080fd5b50600554610284565b34801561058257600080fd5b50610253611ee3565b610253610599366004613708565b611fbd565b3480156105aa57600080fd5b506002546001600160a01b0316610310565b3480156105c857600080fd5b506001546001600160a01b03161561021e565b3480156105e757600080fd5b5061028462278d0081565b61025361060036600461372c565b611ff9565b34801561061157600080fd5b50610253612036565b34801561062657600080fd5b5061021e6120a7565b34801561063b57600080fd5b5061025361064a36600461372c565b6120c7565b6001546000906001600160a01b0316158061066c575060045460ff165b905090565b6001546001600160a01b031633146106a45760405162461bcd60e51b815260040161069b90613a86565b60405180910390fd5b6001600160a01b0381166106e45760405162461bcd60e51b81526020600482015260076024820152662341523a30303160c81b604482015260640161069b565b6001600160a01b03811660009081526009602052604090205460ff16156107375760405162461bcd60e51b815260206004820152600760248201526611a0a91d18199960c91b604482015260640161069b565b6001600160a01b038116600081815260096020526040808220805460ff19166001179055513392917fbc68405e644da2aaf25623ce2199da82c6dfd2e1de102b400eba6a091704d4f491a350565b60007f0000000000000000000000000000000000000000000000000000000000000000806107b4574691505090565b919050565b6001546001600160a01b031633146107e35760405162461bcd60e51b815260040161069b90613a86565b6001600160a01b0381166000908152600a602052604090205460ff16156108365760405162461bcd60e51b815260206004820152600760248201526611a0a09d18199960c91b604482015260640161069b565b6001600160a01b0381166000818152600a6020526040808220805460ff19166001179055513392917f0bb5715f0f217c2fe9a0c877ea87d474380c641102f3440ee2a4c8b9d979091891a350565b6001546001600160a01b031633146108ae5760405162461bcd60e51b815260040161069b90613a86565b60065460ff16156108ec5760405162461bcd60e51b8152602060048201526008602482015267046a4829e746066760c31b604482015260640161069b565b6000600754116109295760405162461bcd60e51b81526020600482015260086024820152672352414f3a30333760c01b604482015260640161069b565b62093a806007544261093b9190613eed565b116109735760405162461bcd60e51b815260206004820152600860248201526702352414f3a3033360c41b604482015260640161069b565b61097d600161224c565b565b61098761321e565b600260005414156109aa5760405162461bcd60e51b815260040161069b90613aa7565b600260009081556109c160408c0160208d01613314565b6001600160a01b03161415610a015760405162461bcd60e51b815260206004820152600660248201526523503a30303960d01b604482015260640161069b565b6000610a1360608c0160408d01613314565b6001600160a01b03161415610a535760405162461bcd60e51b815260206004820152600660248201526523503a30303160d01b604482015260640161069b565b610a5b61064f565b80610a93575060096000610a7560608d0160408e01613314565b6001600160a01b0316815260208101919091526040016000205460ff165b610ac85760405162461bcd60e51b815260206004820152600660248201526523503a30303360d01b604482015260640161069b565b6000610ada60c08c0160a08d01613314565b6001600160a01b03161415610b1a5760405162461bcd60e51b8152602060048201526006602482015265023503a3031360d41b604482015260640161069b565b6000610b2c60e08c0160c08d01613314565b6001600160a01b03161415610b6c5760405162461bcd60e51b815260206004820152600660248201526511a81d18191b60d11b604482015260640161069b565b8961012001358a61010001351415610baf5760405162461bcd60e51b815260206004820152600660248201526523503a30313160d01b604482015260640161069b565b6000610bb9610785565b9050808b61010001351480610bd25750808b6101200135145b610c075760405162461bcd60e51b815260206004820152600660248201526511a81d18189960d11b604482015260640161069b565b6000610c13428b613eed565b905062015180811015610c515760405162461bcd60e51b815260206004820152600660248201526523503a30313360d01b604482015260640161069b565b62278d00811115610c8d5760405162461bcd60e51b815260206004820152600660248201526508d40e8c0c4d60d21b604482015260640161069b565b5060008b604051602001610ca19190613ade565b60408051601f1981840301815291815281516020928301206000818152600b90935291205490915015610cff5760405162461bcd60e51b815260206004820152600660248201526523503a30313560d01b604482015260640161069b565b818c61010001351415610df75760008b11610d455760405162461bcd60e51b815260206004820152600660248201526511a81d18181960d11b604482015260640161069b565b610d4d6120a7565b80610d885750600a60008d6060016020810190610d6a9190613314565b6001600160a01b0316815260208101919091526040016000205460ff165b610dbd5760405162461bcd60e51b815260206004820152600660248201526508d40e8c0c0d60d21b604482015260640161069b565b610dd6610dd060808e0160608f01613314565b8c612299565b9a50610de38b8b4361235a565b6000828152600b60205260409020556110a8565b6000610e0a6101008e0160e08f01613314565b6001600160a01b03161480610e345750610e34610e2e6101008e0160e08f01613314565b3b151590565b610e695760405162461bcd60e51b815260206004820152600660248201526523503a30333160d01b604482015260640161069b565b610e716120a7565b80610eac5750600a60008d6080016020810190610e8e9190613314565b6001600160a01b0316815260208101919091526040016000205460ff165b610ee15760405162461bcd60e51b815260206004820152600660248201526508d40e8c0c0d60d21b604482015260640161069b565b610ef160608d0160408e01613314565b6001600160a01b0316336001600160a01b031614610f3a5760405162461bcd60e51b815260206004820152600660248201526511a81d18189b60d11b604482015260640161069b565b3415610f715760405162461bcd60e51b815260206004820152600660248201526523503a30313760d01b604482015260640161069b565b6000600860008e6040016020810190610f8a9190613314565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008e6080016020810190610fbf9190613314565b6001600160a01b03166001600160a01b031681526020019081526020016000205490508b81101561101b5760405162461bcd60e51b8152602060048201526006602482015265046a0746062760d31b604482015260640161069b565b6110268c8c4361235a565b600b6000848152602001908152602001600020819055508b8103600860008f60400160208101906110579190613314565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008f608001602081019061108c9190613314565b6001600160a01b03168152602081019190915260400160002055505b6000604051806101e001604052808e60000160208101906110c99190613314565b6001600160a01b031681526020018e60200160208101906110ea9190613314565b6001600160a01b031681526020018e604001602081019061110b9190613314565b6001600160a01b031681526020018e606001602081019061112c9190613314565b6001600160a01b031681526020018e608001602081019061114d9190613314565b6001600160a01b031681526020018e60a001602081019061116e9190613314565b6001600160a01b031681526020018e60c001602081019061118f9190613314565b6001600160a01b031681526020018e60e00160208101906111b09190613314565b6001600160a01b031681526020018e610140013581526020018e610160013581526020018e610100013581526020018e610120013581526020018d81526020018c815260200143815250905080610120015181604001516001600160a01b031682602001516001600160a01b03167fab398cccfbdc6ce7daf9d26bc84174d4d49bde657c28c1cc456b4eb7c0aa720a84338f8f8f8f8f8f60405161125b989796959493929190613e3c565b60405180910390a460016000559c9b505050505050505050505050565b61128061321e565b600260005414156112a35760405162461bcd60e51b815260040161069b90613aa7565b600260009081556112b3856123a8565b90506112cf856101800135866101a00135876101c0013561235a565b6000828152600b6020526040902054146113145760405162461bcd60e51b815260206004820152600660248201526523433a30313960d01b604482015260640161069b565b6000856101c00135116113525760405162461bcd60e51b815260206004820152600660248201526523433a30323160d01b604482015260640161069b565b611368856101800135866101a00135600061235a565b6000828152600b6020526040812091909155611382610785565b90508086610140013514156114295742866101a00135106113f6576113ad6060870160408801613314565b6001600160a01b0316336001600160a01b0316146113f65760405162461bcd60e51b815260206004820152600660248201526523433a30323560d01b604482015260640161069b565b6114246114096080880160608901613314565b61141960c0890160a08a01613314565b886101800135612506565b611545565b42866101a00135106114ca576114456040870160208801613314565b6001600160a01b0316336001600160a01b03161480611495575061146f6040870160208801613314565b6001600160a01b031661148a8761012001358330898961252f565b6001600160a01b0316145b6114ca5760405162461bcd60e51b815260206004820152600660248201526511a19d18191960d11b604482015260640161069b565b610180860135600860006114e460608a0160408b01613314565b6001600160a01b03168152602081019190915260400160009081209061151060a08a0160808b01613314565b6001600160a01b03166001600160a01b03168152602001908152602001600020600082825461153f9190613ed5565b90915550505b61012086013561155b6060880160408901613314565b6001600160a01b03166115746040890160208a01613314565b6001600160a01b03167f9ff4e119c7d03c442b1656c62e4fb6c3cd6490a27ab86e7ff2ce50dd3b73a4c189336040516115ae929190613d87565b60405180910390a46115c5368790038701876135fe565b60016000559695505050505050565b6001546001600160a01b031633146115fe5760405162461bcd60e51b815260040161069b90613a86565b6001600160a01b03811661163e5760405162461bcd60e51b81526020600482015260076024820152662352523a30303160c81b604482015260640161069b565b6001600160a01b03811660009081526009602052604090205460ff1615156001146116955760405162461bcd60e51b81526020600482015260076024820152662352523a30333360c81b604482015260640161069b565b6001600160a01b038116600081815260096020526040808220805460ff19169055513392917fbee3e974bb6a6f44f20096ede047c191eef60322e65e4ee4bd3392230a8716d591a350565b6001546001600160a01b0316331461170a5760405162461bcd60e51b815260040161069b90613a86565b6000600354116117465760405162461bcd60e51b815260206004820152600760248201526623524f3a30333760c81b604482015260640161069b565b62093a80600354426117589190613eed565b1161178f5760405162461bcd60e51b8152602060048201526007602482015266023524f3a3033360cc1b604482015260640161069b565b6002546001600160a01b0316156117d25760405162461bcd60e51b815260206004820152600760248201526611a9279d18199b60c91b604482015260640161069b565b60025461097d906001600160a01b03166125b1565b6117ef61321e565b600260005414156118125760405162461bcd60e51b815260040161069b90613aa7565b60026000908155611822886123a8565b905061183e886101800135896101a001358a6101c0013561235a565b6000828152600b6020526040902054146118835760405162461bcd60e51b815260206004820152600660248201526523463a30313960d01b604482015260640161069b565b42886101a0013510156118c15760405162461bcd60e51b8152602060048201526006602482015265023463a3032360d41b604482015260640161069b565b6000886101c00135116118ff5760405162461bcd60e51b815260206004820152600660248201526523463a30323160d01b604482015260640161069b565b61190f6040890160208a01613314565b6001600160a01b031661193c6101208a0135896101608c013561193560208e018e613314565b8b8b61260a565b6001600160a01b03161461197b5760405162461bcd60e51b815260206004820152600660248201526511a31d18191960d11b604482015260640161069b565b8761018001358711156119b95760405162461bcd60e51b815260206004820152600660248201526523463a30323360d01b604482015260640161069b565b87610100013584846040516119cf9291906139f8565b604051809103902014611a0d5760405162461bcd60e51b815260206004820152600660248201526508d18e8c0c8d60d21b604482015260640161069b565b611a23886101800135896101a00135600061235a565b6000918252600b60205260408220556060611a3c610785565b8961014001351415611b2157611a5860608a0160408b01613314565b6001600160a01b0316336001600160a01b031614611aa15760405162461bcd60e51b815260206004820152600660248201526511a31d18189b60d11b604482015260640161069b565b61018089013560086000611abb60608d0160408e01613314565b6001600160a01b031681526020810191909152604001600090812090611ae760808d0160608e01613314565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254611b169190613ed5565b90915550611b339050565b611b2d89898787612674565b90925090505b610120890135611b4960608b0160408c01613314565b6001600160a01b0316611b6260408c0160208d01613314565b6001600160a01b03167f61bafb0ebbe27dfee40c81c31c114db452f16caed88c1f653c14d8645f1d78c78c8c8c8c8c8c8b8b33604051611baa99989796959493929190613daf565b60405180910390a4611bc1368a90038a018a6135fe565b60016000559998505050505050505050565b6001546001600160a01b03163314611bfd5760405162461bcd60e51b815260040161069b90613a86565b60065460ff1615611c3c5760405162461bcd60e51b8152602060048201526009602482015268046a0829ea4746066760bb1b604482015260640161069b565b61097d61287f565b6001546001600160a01b03163314611c6e5760405162461bcd60e51b815260040161069b90613a86565b6001600160a01b0381166000908152600a602052604090205460ff161515600114611cc55760405162461bcd60e51b81526020600482015260076024820152662352413a30333360c81b604482015260640161069b565b6001600160a01b0381166000818152600a6020526040808220805460ff19169055513392917f0fa1e4606af435f32f05b3804033d2933e691fab32ee74d2db6fa82d2741f1ea91a350565b6001546001600160a01b03163314611d3a5760405162461bcd60e51b815260040161069b90613a86565b6002546001600160a01b038281169116141580611d5e57506001600160a01b038116155b611d955760405162461bcd60e51b815260206004820152600860248201526711a827279d18199b60c11b604482015260640161069b565b6001546001600160a01b0382811691161415611dde5760405162461bcd60e51b8152602060048201526008602482015267046a09c9e746066760c31b604482015260640161069b565b611de7816128bb565b50565b6001546001600160a01b03163314611e145760405162461bcd60e51b815260040161069b90613a86565b60045460ff1615611e525760405162461bcd60e51b8152602060048201526008602482015267046a4a49e746066760c31b604482015260640161069b565b600060055411611e8f5760405162461bcd60e51b81526020600482015260086024820152672352524f3a30333760c01b604482015260640161069b565b62093a8060055442611ea19190613eed565b11611ed95760405162461bcd60e51b815260206004820152600860248201526702352524f3a3033360c41b604482015260640161069b565b61097d6001612909565b6002546001600160a01b03163314611f275760405162461bcd60e51b8152602060048201526007602482015266234f503a30333560c81b604482015260640161069b565b6002546001546001600160a01b0390811691161415611f735760405162461bcd60e51b815260206004820152600860248201526704682a09e746066760c31b604482015260640161069b565b62093a8060035442611f859190613eed565b116117d25760405162461bcd60e51b815260206004820152600860248201526702341504f3a3033360c41b604482015260640161069b565b60026000541415611fe05760405162461bcd60e51b815260040161069b90613aa7565b6002600055611ff082823361294f565b50506001600055565b6002600054141561201c5760405162461bcd60e51b815260040161069b90613aa7565b600260005561202c83838361294f565b5050600160005550565b6001546001600160a01b031633146120605760405162461bcd60e51b815260040161069b90613a86565b60045460ff161561209f5760405162461bcd60e51b8152602060048201526009602482015268046a0a49ea4746066760bb1b604482015260640161069b565b61097d612b23565b6001546000906001600160a01b0316158061066c57505060065460ff1690565b600260005414156120ea5760405162461bcd60e51b815260040161069b90613aa7565b60026000556001600160a01b03811661212f5760405162461bcd60e51b815260206004820152600760248201526623524c3a30303760c81b604482015260640161069b565b600083116121695760405162461bcd60e51b815260206004820152600760248201526611a9261d18181960c91b604482015260640161069b565b3360009081526008602090815260408083206001600160a01b0386168452909152902054838110156121c75760405162461bcd60e51b8152602060048201526007602482015266046a498746060760cb1b604482015260640161069b565b3360009081526008602090815260408083206001600160a01b0387168452909152902084820390556121fa838386612506565b604080518581526001600160a01b03848116602083015285169133917f7da12116be8cb7af4b2d9e9b4a2ca2c3a3243ddd6fd3a94411902367b8eed568910160405180910390a3505060016000555050565b6006805460ff191682151590811790915560006007556040519081527f868d89ead22a5d10f456845ac0014901d9af7203e71cf0892d70d9dc262c2fb9906020015b60405180910390a150565b6000816001600160a01b0384166122e8578234146122e35760405162461bcd60e51b81526020600482015260076024820152662354413a30303560c81b604482015260640161069b565b612351565b60006122f385612b59565b9050341561232d5760405162461bcd60e51b815260206004820152600760248201526611aa209d18181b60c91b604482015260640161069b565b61233985333087612bed565b8061234386612b59565b61234d9190613eed565b9150505b90505b92915050565b604080516060808201835285825260208083018681529284018581528451808301899052935184860152518383015283518084039092018252608090920190925281519101205b9392505050565b6040805161018081019091526000908190806123c76020860186613314565b6001600160a01b031681526020018460200160208101906123e89190613314565b6001600160a01b031681526020016124066060860160408701613314565b6001600160a01b031681526020016124246080860160608701613314565b6001600160a01b0316815260200161244260a0860160808701613314565b6001600160a01b0316815260200161246060c0860160a08701613314565b6001600160a01b0316815260200161247e60e0860160c08701613314565b6001600160a01b0316815260200161249d610100860160e08701613314565b6001600160a01b031681526020018461014001358152602001846101600135815260200184610100013581526020018461012001358152509050806040516020016124e89190613bd9565b60405160208183030381529060405280519060200120915050919050565b6001600160a01b0383161561252557612520838383612bff565b505050565b6125208282612c0a565b60008060405180608001604052808881526020016040518060400160405280600681526020016518d85b98d95b60d21b8152508152602001878152602001866001600160a01b031681525090506125a6816040516020016125909190613cdb565b6040516020818303038152906040528585612c98565b979650505050505050565b600180546001600160a01b038381166001600160a01b0319831681179093556000600381905560405191909216929183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040805160a0810182528781526020808201889052825180840184526007815266199d5b199a5b1b60ca1b8183015282840152606082018790526001600160a01b038616608083015291516000926126689161259091849101613d2c565b98975050505050505050565b6000606061018086013585900385156126a1576126a161269a60a0890160808a01613314565b3388612506565b60006126b4610100890160e08a01613314565b6001600160a01b0316141561270c5780156126f2576126f26126dc60a0890160808a01613314565b6126ec60e08a0160c08b01613314565b83612506565b604080516000808252602082019092529250925050612876565b600061272e61272160a08a0160808b01613314565b6001600160a01b03161590565b90508015801561273e5750600082115b1561277d5761277d61275660a08a0160808b01613314565b7f000000000000000000000000000000000000000000000000000000000000000084612bff565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cf9a3604826127b85760006127ba565b835b6101208b01356127d16101008d0160e08e01613314565b6127e160a08e0160808f01613314565b8d60c00160208101906127f49190613314565b888d8d6040518963ffffffff1660e01b81526004016128199796959493929190613a24565b6000604051808303818588803b15801561283257600080fd5b505af1158015612846573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f1916820160405261286f9190810190613382565b9350935050505b94509492505050565b4260078190556040519081527fa78fdca214e4619ef34a695316d423f5b0d8274bc919d29733bf8f92ec8cbb7a906020015b60405180910390a1565b42600355600280546001600160a01b0319166001600160a01b0383169081179091556040517f6ab4d119f23076e8ad491bc65ce85f017fb0591dce08755ba8591059cc51737a90600090a250565b6004805460ff191682151590811790915560006005556040519081527f243ebbb2f905234bbf0556bb38e1f7c23b09ffd2e441a16e58b844eb2ab7a3979060200161228e565b6001600160a01b03811661298f5760405162461bcd60e51b815260206004820152600760248201526623414c3a30303160c81b604482015260640161069b565b600083116129c95760405162461bcd60e51b815260206004820152600760248201526611a0a61d18181960c91b604482015260640161069b565b6129d161064f565b806129f457506001600160a01b03811660009081526009602052604090205460ff165b612a2a5760405162461bcd60e51b815260206004820152600760248201526623414c3a30303360c81b604482015260640161069b565b612a326120a7565b80612a5557506001600160a01b0382166000908152600a602052604090205460ff165b612a8b5760405162461bcd60e51b815260206004820152600760248201526608d0530e8c0c0d60ca1b604482015260640161069b565b612a958284612299565b6001600160a01b038083166000908152600860209081526040808320938716835292905290812080549295508592909190612ad1908490613ed5565b9091555050604080518481523360208201526001600160a01b0380851692908416917f4bd28ccd068c4853d24d35f727ef2a3fea11ce55e8d93461e45f785818e1e139910160405180910390a3505050565b4260058190556040519081527fa52048c5f468d21a62e4644ac4db19bcaa1a20f0cf37d163ba49c7217d35feb8906020016128b1565b60006001600160a01b03821615612be6576040516370a0823160e01b81523060048201526001600160a01b038316906370a082319060240160206040518083038186803b158015612ba957600080fd5b505afa158015612bbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612be191906136f0565b612354565b4792915050565b612bf984848484612d3f565b50505050565b612520838383612daa565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612c57576040519150601f19603f3d011682016040523d82523d6000602084013e612c5c565b606091505b50509050806125205760405162461bcd60e51b8152602060048201526008602482015267046a89c82746064760c31b604482015260640161069b565b6000612d37612cfb85805190602001206040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612dda92505050565b949350505050565b6040516001600160a01b0380851660248301528316604482015260648101829052612bf99085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612e7e565b6040516001600160a01b03831660248201526044810182905261252090849063a9059cbb60e01b90606401612d73565b6000815160411415612e0e5760208201516040830151606084015160001a612e0486828585612f50565b9350505050612354565b815160401415612e365760208201516040830151612e2d8583836130f9565b92505050612354565b60405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161069b565b6000612ed3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166131239092919063ffffffff16565b8051909150156125205780806020019051810190612ef19190613368565b6125205760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161069b565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0821115612fcd5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161069b565b8360ff16601b1480612fe257508360ff16601c145b6130395760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161069b565b6040805160008082526020820180845288905260ff871692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa15801561308d573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166130f05760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161069b565b95945050505050565b60006001600160ff1b03821660ff83901c601b0161311986828785612f50565b9695505050505050565b6060612d37848460008585843b61317c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161069b565b600080866001600160a01b031685876040516131989190613a08565b60006040518083038185875af1925050503d80600081146131d5576040519150601f19603f3d011682016040523d82523d6000602084013e6131da565b606091505b50915091506125a6828286606083156131f45750816123a1565b8251156132045782518084602001fd5b8160405162461bcd60e51b815260040161069b9190613a73565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081019190915290565b80356107b481613f5c565b805180151581146107b457600080fd5b60008083601f8401126132c6578182fd5b50813567ffffffffffffffff8111156132dd578182fd5b6020830191508360208285010111156132f557600080fd5b9250929050565b60006101e0828403121561330e578081fd5b50919050565b600060208284031215613325578081fd5b813561235181613f5c565b60008060408385031215613342578081fd5b823561334d81613f5c565b9150602083013561335d81613f5c565b809150509250929050565b600060208284031215613379578081fd5b6123a1826132a5565b60008060408385031215613394578182fd5b61339d836132a5565b9150602083015167ffffffffffffffff808211156133b9578283fd5b818501915085601f8301126133cc578283fd5b8151818111156133de576133de613f46565b604051601f8201601f19908116603f0116810190838211818310171561340657613406613f46565b8160405282815288602084870101111561341e578586fd5b61342f836020830160208801613f04565b80955050505050509250929050565b60006020828403121561344f578081fd5b5035919050565b6000806000806000806000806000898b03610220811215613475578586fd5b61018080821215613484578687fd5b8b9a508a01359850506101a089013596506101c089013567ffffffffffffffff808211156134b0578687fd5b6134bc8d838e016132b5565b90985096506101e08c01359150808211156134d5578586fd5b6134e18d838e016132b5565b90965094506102008c01359150808211156134fa578384fd5b506135078c828d016132b5565b915080935050809150509295985092959850929598565b60008060006102008486031215613533578283fd5b61353d85856132fc565b92506101e084013567ffffffffffffffff811115613559578283fd5b613565868287016132b5565b9497909650939450505050565b600080600080600080610240878903121561358b578182fd5b61359588886132fc565b95506101e0870135945061020087013567ffffffffffffffff808211156135ba578384fd5b6135c68a838b016132b5565b90965094506102208901359150808211156135df578384fd5b506135ec89828a016132b5565b979a9699509497509295939492505050565b60006101e08284031215613610578081fd5b613618613eab565b6136218361329a565b815261362f6020840161329a565b60208201526136406040840161329a565b60408201526136516060840161329a565b60608201526136626080840161329a565b608082015261367360a0840161329a565b60a082015261368460c0840161329a565b60c082015261369560e0840161329a565b60e0820152610100838101359082015261012080840135908201526101408084013590820152610160808401359082015261018080840135908201526101a080840135908201526101c0928301359281019290925250919050565b600060208284031215613701578081fd5b5051919050565b6000806040838503121561371a578182fd5b82359150602083013561335d81613f5c565b600080600060608486031215613740578081fd5b83359250602084013561375281613f5c565b9150604084013561376281613f5c565b809150509250925092565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526137ae816020860160208601613f04565b601f01601f19169290920160200192915050565b6137dc826137cf8361329a565b6001600160a01b03169052565b6137e86020820161329a565b6001600160a01b031660208301526138026040820161329a565b6001600160a01b0316604083015261381c6060820161329a565b6001600160a01b031660608301526138366080820161329a565b6001600160a01b0316608083015261385060a0820161329a565b6001600160a01b031660a083015261386a60c0820161329a565b6001600160a01b031660c083015261388460e0820161329a565b6001600160a01b031660e0830152610100818101359083015261012080820135908301526101408082013590830152610160808201359083015261018080820135908301526101a080820135908301526101c090810135910152565b80516001600160a01b03168252602081015161390760208401826001600160a01b03169052565b50604081015161392260408401826001600160a01b03169052565b50606081015161393d60608401826001600160a01b03169052565b50608081015161395860808401826001600160a01b03169052565b5060a081015161397360a08401826001600160a01b03169052565b5060c081015161398e60c08401826001600160a01b03169052565b5060e08101516139a960e08401826001600160a01b03169052565b50610100818101519083015261012080820151908301526101408082015190830152610160808201519083015261018080820151908301526101a080820151908301526101c090810151910152565b8183823760009101908152919050565b60008251613a1a818460208701613f04565b9190910192915050565b8781526001600160a01b0387811660208301528681166040830152851660608201526080810184905260c060a08201819052600090613a66908301848661376d565b9998505050505050505050565b6020815260006123a16020830184613796565b602080825260079082015266234f4f3a30323960c81b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6101808101613af0826137cf8561329a565b613afc6020840161329a565b6001600160a01b03166020830152613b166040840161329a565b6001600160a01b03166040830152613b306060840161329a565b6001600160a01b03166060830152613b4a6080840161329a565b6001600160a01b03166080830152613b6460a0840161329a565b6001600160a01b031660a0830152613b7e60c0840161329a565b6001600160a01b031660c0830152613b9860e0840161329a565b6001600160a01b031660e083015261010083810135908301526101208084013590830152610140808401359083015261016092830135929091019190915290565b81516001600160a01b0316815261018081016020830151613c0560208401826001600160a01b03169052565b506040830151613c2060408401826001600160a01b03169052565b506060830151613c3b60608401826001600160a01b03169052565b506080830151613c5660808401826001600160a01b03169052565b5060a0830151613c7160a08401826001600160a01b03169052565b5060c0830151613c8c60c08401826001600160a01b03169052565b5060e0830151613ca760e08401826001600160a01b03169052565b5061010083810151908301526101208084015190830152610140808401519083015261016092830151929091019190915290565b60208152815160208201526000602083015160806040840152613d0160a0840182613796565b6040850151606085810191909152909401516001600160a01b03166080909301929092525090919050565b6020815281516020820152602082015160408201526000604083015160a06060840152613d5c60c0840182613796565b6060850151608085810191909152909401516001600160a01b031660a0909301929092525090919050565b6102008101613d9682856137c2565b6001600160a01b03929092166101e09190910152919050565b60006102a0613dbe838d6137c2565b8a6101e084015280610200840152613dd98184018a8c61376d565b9050828103610220840152613def81888a61376d565b9050851515610240840152828103610260840152613e0d8186613796565b91505060018060a01b0383166102808301529a9950505050505050505050565b6101e0810161235482846138e0565b6000610260613e4b838c6138e0565b6001600160a01b038a166101e08401526102008301819052613e70818401898b61376d565b9050828103610220840152613e8681878961376d565b9050828103610240840152613e9c81858761376d565b9b9a5050505050505050505050565b6040516101e0810167ffffffffffffffff81118282101715613ecf57613ecf613f46565b60405290565b60008219821115613ee857613ee8613f30565b500190565b600082821015613eff57613eff613f30565b500390565b60005b83811015613f1f578181015183820152602001613f07565b83811115612bf95750506000910152565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114611de757600080fdfea264697066735822122038664d80b725d76538324127327ffb672ddf1977b3b07b22156be702f9a8cce964736f6c6343000804003360a060405234801561001057600080fd5b50604051610b2d380380610b2d83398101604081905261002f91610049565b600160005560601b6001600160601b031916608052610077565b60006020828403121561005a578081fd5b81516001600160a01b0381168114610070578182fd5b9392505050565b60805160601c610a9361009a600039600081816048015260a70152610a936000f3fe6080604052600436106100295760003560e01c806396f32fb81461002e578063cf9a360414610077575b600080fd5b34801561003a57600080fd5b506040516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526020015b60405180910390f35b61008a610085366004610822565b610098565b60405161006e9291906109c7565b60006060336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101045760405162461bcd60e51b8152602060048201526008602482015267234f544d3a30323760c01b60448201526064015b60405180910390fd5b6001600160a01b038716158061011f5761011f888a88610212565b600060608a3b1561019b578a6001600160a01b031683610140576000610142565b885b888860405161015292919061091f565b60006040518083038185875af1925050503d806000811461018f576040519150601f19603f3d011682016040523d82523d6000602084013e610194565b606091505b5090925090505b816101bb576101ab8a8a8a610262565b826101bb576101bb8a8c8a610286565b8b7fbf49bd2de448d90a19e0510ab1030fead50ebfc64a4f112ca42535ae79fbab798c8c8c8c8c8c888a6040516101f998979695949392919061094b565b60405180910390a2909b909a5098505050505050505050565b6001600160a01b0383166102525760405162461bcd60e51b815260206004820152600760248201526608d2504e8c0ccd60ca1b60448201526064016100fb565b61025d8383836102d1565b505050565b6001600160a01b0383161561027c5761025d8383836103cb565b61025d82826103d6565b6001600160a01b0383166102c65760405162461bcd60e51b815260206004820152600760248201526608d1104e8c0ccd60ca1b60448201526064016100fb565b61025d838383610464565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e9060440160206040518083038186803b15801561031d57600080fd5b505afa158015610331573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061035591906108db565b61035f91906109f5565b6040516001600160a01b0385166024820152604481018290529091506103c590859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152610586565b50505050565b61025d838383610658565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114610423576040519150601f19603f3d011682016040523d82523d6000602084013e610428565b606091505b505090508061025d5760405162461bcd60e51b8152602060048201526008602482015267046a89c82746064760c31b60448201526064016100fb565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e9060440160206040518083038186803b1580156104af57600080fd5b505afa1580156104c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e791906108db565b90508181101561054b5760405162461bcd60e51b815260206004820152602960248201527f5361666545524332303a2064656372656173656420616c6c6f77616e63652062604482015268656c6f77207a65726f60b81b60648201526084016100fb565b6040516001600160a01b0384166024820152828203604482018190529061057f90869063095ea7b360e01b9060640161038e565b5050505050565b60006105db826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166106889092919063ffffffff16565b80519091501561025d57808060200190518101906105f99190610802565b61025d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016100fb565b6040516001600160a01b03831660248201526044810182905261025d90849063a9059cbb60e01b9060640161038e565b606061069784846000856106a1565b90505b9392505050565b6060824710156107025760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016100fb565b843b6107505760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016100fb565b600080866001600160a01b0316858760405161076c919061092f565b60006040518083038185875af1925050503d80600081146107a9576040519150601f19603f3d011682016040523d82523d6000602084013e6107ae565b606091505b50915091506107be8282866107c9565b979650505050505050565b606083156107d857508161069a565b8251156107e85782518084602001fd5b8160405162461bcd60e51b81526004016100fb91906109e2565b600060208284031215610813578081fd5b8151801515811461069a578182fd5b600080600080600080600060c0888a03121561083c578283fd5b87359650602088013561084e81610a45565b9550604088013561085e81610a45565b9450606088013561086e81610a45565b93506080880135925060a088013567ffffffffffffffff80821115610891578384fd5b818a0191508a601f8301126108a4578384fd5b8135818111156108b2578485fd5b8b60208285010111156108c3578485fd5b60208301945080935050505092959891949750929550565b6000602082840312156108ec578081fd5b5051919050565b6000815180845261090b816020860160208601610a19565b601f01601f19169290920160200192915050565b8183823760009101908152919050565b60008251610941818460208701610a19565b9190910192915050565b6001600160a01b0389811682528881166020830152871660408201526060810186905260e0608082018190528101849052600061010085878285013781818785010152601f19601f8701168301818482030160a08501526109ae828201876108f3565b9250505082151560c08301529998505050505050505050565b821515815260406020820152600061069760408301846108f3565b60208152600061069a60208301846108f3565b60008219821115610a1457634e487b7160e01b81526011600452602481fd5b500190565b60005b83811015610a34578181015183820152602001610a1c565b838111156103c55750506000910152565b6001600160a01b0381168114610a5a57600080fd5b5056fea264697066735822122054fb00728b764b8a8ec83285f0d93b770ffecaa2795a78606c7db0bb4704565164736f6c634300080400330000000000000000000000000000000000000000000000000000000000000089
Deployed Bytecode
0x6080604052600436106102045760003560e01c8063715018a611610118578063c5b350df116100a0578063de38eb3a1161006f578063de38eb3a146105db578063e070da09146105f2578063e47602f714610605578063e8be0dfc1461061a578063f31abcc41461062f57600080fd5b8063c5b350df14610576578063c95f9d0e1461058b578063d1851c921461059e578063d232c220146105bc57600080fd5b806397eb0088116100e757806397eb0088146104dc578063b1d2618d1461050c578063b1f8100d1461052c578063c0c17baf1461054c578063c1a049591461056157600080fd5b8063715018a6146104745780637bac72b5146104895780638741eac5146104a95780638da5cb5b146104be57600080fd5b806341258b5c1161019b57806363405b931161016a57806363405b93146103e957806367df6017146104095780636a41633a146104295780636a42b8f81461043e5780636ae0b1541461045457600080fd5b806341258b5c1461033d578063445b1e4b14610375578063543ad1df146103a55780635e679856146103bc57600080fd5b806334e9393c116101d757806334e9393c146102a75780633855b467146102c75780633a35cf17146102dc5780633cf52ffb1461032857600080fd5b80632004ef451461020957806324ca984e1461023357806332a130c9146102555780633408e47014610292575b600080fd5b34801561021557600080fd5b5061021e61064f565b60405190151581526020015b60405180910390f35b34801561023f57600080fd5b5061025361024e366004613314565b610671565b005b34801561026157600080fd5b507f00000000000000000000000000000000000000000000000000000000000000895b60405190815260200161022a565b34801561029e57600080fd5b50610284610785565b3480156102b357600080fd5b506102536102c2366004613314565b6107b9565b3480156102d357600080fd5b50610253610884565b3480156102e857600080fd5b506103107f0000000000000000000000005b9e4d0dd21f4e071729a9eb522a2366abed149a81565b6040516001600160a01b03909116815260200161022a565b34801561033457600080fd5b50600354610284565b34801561034957600080fd5b50610284610358366004613330565b600860209081526000928352604080842090915290825290205481565b34801561038157600080fd5b5061021e610390366004613314565b60096020526000908152604090205460ff1681565b3480156103b157600080fd5b506102846201518081565b3480156103c857600080fd5b506102846103d736600461343e565b600b6020526000908152604090205481565b6103fc6103f7366004613456565b61097f565b60405161022a9190613e2d565b34801561041557600080fd5b506103fc61042436600461351e565b611278565b34801561043557600080fd5b50600754610284565b34801561044a57600080fd5b5062093a80610284565b34801561046057600080fd5b5061025361046f366004613314565b6115d4565b34801561048057600080fd5b506102536116e0565b34801561049557600080fd5b506103fc6104a4366004613572565b6117e7565b3480156104b557600080fd5b50610253611bd3565b3480156104ca57600080fd5b506001546001600160a01b0316610310565b3480156104e857600080fd5b5061021e6104f7366004613314565b600a6020526000908152604090205460ff1681565b34801561051857600080fd5b50610253610527366004613314565b611c44565b34801561053857600080fd5b50610253610547366004613314565b611d10565b34801561055857600080fd5b50610253611dea565b34801561056d57600080fd5b50600554610284565b34801561058257600080fd5b50610253611ee3565b610253610599366004613708565b611fbd565b3480156105aa57600080fd5b506002546001600160a01b0316610310565b3480156105c857600080fd5b506001546001600160a01b03161561021e565b3480156105e757600080fd5b5061028462278d0081565b61025361060036600461372c565b611ff9565b34801561061157600080fd5b50610253612036565b34801561062657600080fd5b5061021e6120a7565b34801561063b57600080fd5b5061025361064a36600461372c565b6120c7565b6001546000906001600160a01b0316158061066c575060045460ff165b905090565b6001546001600160a01b031633146106a45760405162461bcd60e51b815260040161069b90613a86565b60405180910390fd5b6001600160a01b0381166106e45760405162461bcd60e51b81526020600482015260076024820152662341523a30303160c81b604482015260640161069b565b6001600160a01b03811660009081526009602052604090205460ff16156107375760405162461bcd60e51b815260206004820152600760248201526611a0a91d18199960c91b604482015260640161069b565b6001600160a01b038116600081815260096020526040808220805460ff19166001179055513392917fbc68405e644da2aaf25623ce2199da82c6dfd2e1de102b400eba6a091704d4f491a350565b60007f0000000000000000000000000000000000000000000000000000000000000089806107b4574691505090565b919050565b6001546001600160a01b031633146107e35760405162461bcd60e51b815260040161069b90613a86565b6001600160a01b0381166000908152600a602052604090205460ff16156108365760405162461bcd60e51b815260206004820152600760248201526611a0a09d18199960c91b604482015260640161069b565b6001600160a01b0381166000818152600a6020526040808220805460ff19166001179055513392917f0bb5715f0f217c2fe9a0c877ea87d474380c641102f3440ee2a4c8b9d979091891a350565b6001546001600160a01b031633146108ae5760405162461bcd60e51b815260040161069b90613a86565b60065460ff16156108ec5760405162461bcd60e51b8152602060048201526008602482015267046a4829e746066760c31b604482015260640161069b565b6000600754116109295760405162461bcd60e51b81526020600482015260086024820152672352414f3a30333760c01b604482015260640161069b565b62093a806007544261093b9190613eed565b116109735760405162461bcd60e51b815260206004820152600860248201526702352414f3a3033360c41b604482015260640161069b565b61097d600161224c565b565b61098761321e565b600260005414156109aa5760405162461bcd60e51b815260040161069b90613aa7565b600260009081556109c160408c0160208d01613314565b6001600160a01b03161415610a015760405162461bcd60e51b815260206004820152600660248201526523503a30303960d01b604482015260640161069b565b6000610a1360608c0160408d01613314565b6001600160a01b03161415610a535760405162461bcd60e51b815260206004820152600660248201526523503a30303160d01b604482015260640161069b565b610a5b61064f565b80610a93575060096000610a7560608d0160408e01613314565b6001600160a01b0316815260208101919091526040016000205460ff165b610ac85760405162461bcd60e51b815260206004820152600660248201526523503a30303360d01b604482015260640161069b565b6000610ada60c08c0160a08d01613314565b6001600160a01b03161415610b1a5760405162461bcd60e51b8152602060048201526006602482015265023503a3031360d41b604482015260640161069b565b6000610b2c60e08c0160c08d01613314565b6001600160a01b03161415610b6c5760405162461bcd60e51b815260206004820152600660248201526511a81d18191b60d11b604482015260640161069b565b8961012001358a61010001351415610baf5760405162461bcd60e51b815260206004820152600660248201526523503a30313160d01b604482015260640161069b565b6000610bb9610785565b9050808b61010001351480610bd25750808b6101200135145b610c075760405162461bcd60e51b815260206004820152600660248201526511a81d18189960d11b604482015260640161069b565b6000610c13428b613eed565b905062015180811015610c515760405162461bcd60e51b815260206004820152600660248201526523503a30313360d01b604482015260640161069b565b62278d00811115610c8d5760405162461bcd60e51b815260206004820152600660248201526508d40e8c0c4d60d21b604482015260640161069b565b5060008b604051602001610ca19190613ade565b60408051601f1981840301815291815281516020928301206000818152600b90935291205490915015610cff5760405162461bcd60e51b815260206004820152600660248201526523503a30313560d01b604482015260640161069b565b818c61010001351415610df75760008b11610d455760405162461bcd60e51b815260206004820152600660248201526511a81d18181960d11b604482015260640161069b565b610d4d6120a7565b80610d885750600a60008d6060016020810190610d6a9190613314565b6001600160a01b0316815260208101919091526040016000205460ff165b610dbd5760405162461bcd60e51b815260206004820152600660248201526508d40e8c0c0d60d21b604482015260640161069b565b610dd6610dd060808e0160608f01613314565b8c612299565b9a50610de38b8b4361235a565b6000828152600b60205260409020556110a8565b6000610e0a6101008e0160e08f01613314565b6001600160a01b03161480610e345750610e34610e2e6101008e0160e08f01613314565b3b151590565b610e695760405162461bcd60e51b815260206004820152600660248201526523503a30333160d01b604482015260640161069b565b610e716120a7565b80610eac5750600a60008d6080016020810190610e8e9190613314565b6001600160a01b0316815260208101919091526040016000205460ff165b610ee15760405162461bcd60e51b815260206004820152600660248201526508d40e8c0c0d60d21b604482015260640161069b565b610ef160608d0160408e01613314565b6001600160a01b0316336001600160a01b031614610f3a5760405162461bcd60e51b815260206004820152600660248201526511a81d18189b60d11b604482015260640161069b565b3415610f715760405162461bcd60e51b815260206004820152600660248201526523503a30313760d01b604482015260640161069b565b6000600860008e6040016020810190610f8a9190613314565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008e6080016020810190610fbf9190613314565b6001600160a01b03166001600160a01b031681526020019081526020016000205490508b81101561101b5760405162461bcd60e51b8152602060048201526006602482015265046a0746062760d31b604482015260640161069b565b6110268c8c4361235a565b600b6000848152602001908152602001600020819055508b8103600860008f60400160208101906110579190613314565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008f608001602081019061108c9190613314565b6001600160a01b03168152602081019190915260400160002055505b6000604051806101e001604052808e60000160208101906110c99190613314565b6001600160a01b031681526020018e60200160208101906110ea9190613314565b6001600160a01b031681526020018e604001602081019061110b9190613314565b6001600160a01b031681526020018e606001602081019061112c9190613314565b6001600160a01b031681526020018e608001602081019061114d9190613314565b6001600160a01b031681526020018e60a001602081019061116e9190613314565b6001600160a01b031681526020018e60c001602081019061118f9190613314565b6001600160a01b031681526020018e60e00160208101906111b09190613314565b6001600160a01b031681526020018e610140013581526020018e610160013581526020018e610100013581526020018e610120013581526020018d81526020018c815260200143815250905080610120015181604001516001600160a01b031682602001516001600160a01b03167fab398cccfbdc6ce7daf9d26bc84174d4d49bde657c28c1cc456b4eb7c0aa720a84338f8f8f8f8f8f60405161125b989796959493929190613e3c565b60405180910390a460016000559c9b505050505050505050505050565b61128061321e565b600260005414156112a35760405162461bcd60e51b815260040161069b90613aa7565b600260009081556112b3856123a8565b90506112cf856101800135866101a00135876101c0013561235a565b6000828152600b6020526040902054146113145760405162461bcd60e51b815260206004820152600660248201526523433a30313960d01b604482015260640161069b565b6000856101c00135116113525760405162461bcd60e51b815260206004820152600660248201526523433a30323160d01b604482015260640161069b565b611368856101800135866101a00135600061235a565b6000828152600b6020526040812091909155611382610785565b90508086610140013514156114295742866101a00135106113f6576113ad6060870160408801613314565b6001600160a01b0316336001600160a01b0316146113f65760405162461bcd60e51b815260206004820152600660248201526523433a30323560d01b604482015260640161069b565b6114246114096080880160608901613314565b61141960c0890160a08a01613314565b886101800135612506565b611545565b42866101a00135106114ca576114456040870160208801613314565b6001600160a01b0316336001600160a01b03161480611495575061146f6040870160208801613314565b6001600160a01b031661148a8761012001358330898961252f565b6001600160a01b0316145b6114ca5760405162461bcd60e51b815260206004820152600660248201526511a19d18191960d11b604482015260640161069b565b610180860135600860006114e460608a0160408b01613314565b6001600160a01b03168152602081019190915260400160009081209061151060a08a0160808b01613314565b6001600160a01b03166001600160a01b03168152602001908152602001600020600082825461153f9190613ed5565b90915550505b61012086013561155b6060880160408901613314565b6001600160a01b03166115746040890160208a01613314565b6001600160a01b03167f9ff4e119c7d03c442b1656c62e4fb6c3cd6490a27ab86e7ff2ce50dd3b73a4c189336040516115ae929190613d87565b60405180910390a46115c5368790038701876135fe565b60016000559695505050505050565b6001546001600160a01b031633146115fe5760405162461bcd60e51b815260040161069b90613a86565b6001600160a01b03811661163e5760405162461bcd60e51b81526020600482015260076024820152662352523a30303160c81b604482015260640161069b565b6001600160a01b03811660009081526009602052604090205460ff1615156001146116955760405162461bcd60e51b81526020600482015260076024820152662352523a30333360c81b604482015260640161069b565b6001600160a01b038116600081815260096020526040808220805460ff19169055513392917fbee3e974bb6a6f44f20096ede047c191eef60322e65e4ee4bd3392230a8716d591a350565b6001546001600160a01b0316331461170a5760405162461bcd60e51b815260040161069b90613a86565b6000600354116117465760405162461bcd60e51b815260206004820152600760248201526623524f3a30333760c81b604482015260640161069b565b62093a80600354426117589190613eed565b1161178f5760405162461bcd60e51b8152602060048201526007602482015266023524f3a3033360cc1b604482015260640161069b565b6002546001600160a01b0316156117d25760405162461bcd60e51b815260206004820152600760248201526611a9279d18199b60c91b604482015260640161069b565b60025461097d906001600160a01b03166125b1565b6117ef61321e565b600260005414156118125760405162461bcd60e51b815260040161069b90613aa7565b60026000908155611822886123a8565b905061183e886101800135896101a001358a6101c0013561235a565b6000828152600b6020526040902054146118835760405162461bcd60e51b815260206004820152600660248201526523463a30313960d01b604482015260640161069b565b42886101a0013510156118c15760405162461bcd60e51b8152602060048201526006602482015265023463a3032360d41b604482015260640161069b565b6000886101c00135116118ff5760405162461bcd60e51b815260206004820152600660248201526523463a30323160d01b604482015260640161069b565b61190f6040890160208a01613314565b6001600160a01b031661193c6101208a0135896101608c013561193560208e018e613314565b8b8b61260a565b6001600160a01b03161461197b5760405162461bcd60e51b815260206004820152600660248201526511a31d18191960d11b604482015260640161069b565b8761018001358711156119b95760405162461bcd60e51b815260206004820152600660248201526523463a30323360d01b604482015260640161069b565b87610100013584846040516119cf9291906139f8565b604051809103902014611a0d5760405162461bcd60e51b815260206004820152600660248201526508d18e8c0c8d60d21b604482015260640161069b565b611a23886101800135896101a00135600061235a565b6000918252600b60205260408220556060611a3c610785565b8961014001351415611b2157611a5860608a0160408b01613314565b6001600160a01b0316336001600160a01b031614611aa15760405162461bcd60e51b815260206004820152600660248201526511a31d18189b60d11b604482015260640161069b565b61018089013560086000611abb60608d0160408e01613314565b6001600160a01b031681526020810191909152604001600090812090611ae760808d0160608e01613314565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254611b169190613ed5565b90915550611b339050565b611b2d89898787612674565b90925090505b610120890135611b4960608b0160408c01613314565b6001600160a01b0316611b6260408c0160208d01613314565b6001600160a01b03167f61bafb0ebbe27dfee40c81c31c114db452f16caed88c1f653c14d8645f1d78c78c8c8c8c8c8c8b8b33604051611baa99989796959493929190613daf565b60405180910390a4611bc1368a90038a018a6135fe565b60016000559998505050505050505050565b6001546001600160a01b03163314611bfd5760405162461bcd60e51b815260040161069b90613a86565b60065460ff1615611c3c5760405162461bcd60e51b8152602060048201526009602482015268046a0829ea4746066760bb1b604482015260640161069b565b61097d61287f565b6001546001600160a01b03163314611c6e5760405162461bcd60e51b815260040161069b90613a86565b6001600160a01b0381166000908152600a602052604090205460ff161515600114611cc55760405162461bcd60e51b81526020600482015260076024820152662352413a30333360c81b604482015260640161069b565b6001600160a01b0381166000818152600a6020526040808220805460ff19169055513392917f0fa1e4606af435f32f05b3804033d2933e691fab32ee74d2db6fa82d2741f1ea91a350565b6001546001600160a01b03163314611d3a5760405162461bcd60e51b815260040161069b90613a86565b6002546001600160a01b038281169116141580611d5e57506001600160a01b038116155b611d955760405162461bcd60e51b815260206004820152600860248201526711a827279d18199b60c11b604482015260640161069b565b6001546001600160a01b0382811691161415611dde5760405162461bcd60e51b8152602060048201526008602482015267046a09c9e746066760c31b604482015260640161069b565b611de7816128bb565b50565b6001546001600160a01b03163314611e145760405162461bcd60e51b815260040161069b90613a86565b60045460ff1615611e525760405162461bcd60e51b8152602060048201526008602482015267046a4a49e746066760c31b604482015260640161069b565b600060055411611e8f5760405162461bcd60e51b81526020600482015260086024820152672352524f3a30333760c01b604482015260640161069b565b62093a8060055442611ea19190613eed565b11611ed95760405162461bcd60e51b815260206004820152600860248201526702352524f3a3033360c41b604482015260640161069b565b61097d6001612909565b6002546001600160a01b03163314611f275760405162461bcd60e51b8152602060048201526007602482015266234f503a30333560c81b604482015260640161069b565b6002546001546001600160a01b0390811691161415611f735760405162461bcd60e51b815260206004820152600860248201526704682a09e746066760c31b604482015260640161069b565b62093a8060035442611f859190613eed565b116117d25760405162461bcd60e51b815260206004820152600860248201526702341504f3a3033360c41b604482015260640161069b565b60026000541415611fe05760405162461bcd60e51b815260040161069b90613aa7565b6002600055611ff082823361294f565b50506001600055565b6002600054141561201c5760405162461bcd60e51b815260040161069b90613aa7565b600260005561202c83838361294f565b5050600160005550565b6001546001600160a01b031633146120605760405162461bcd60e51b815260040161069b90613a86565b60045460ff161561209f5760405162461bcd60e51b8152602060048201526009602482015268046a0a49ea4746066760bb1b604482015260640161069b565b61097d612b23565b6001546000906001600160a01b0316158061066c57505060065460ff1690565b600260005414156120ea5760405162461bcd60e51b815260040161069b90613aa7565b60026000556001600160a01b03811661212f5760405162461bcd60e51b815260206004820152600760248201526623524c3a30303760c81b604482015260640161069b565b600083116121695760405162461bcd60e51b815260206004820152600760248201526611a9261d18181960c91b604482015260640161069b565b3360009081526008602090815260408083206001600160a01b0386168452909152902054838110156121c75760405162461bcd60e51b8152602060048201526007602482015266046a498746060760cb1b604482015260640161069b565b3360009081526008602090815260408083206001600160a01b0387168452909152902084820390556121fa838386612506565b604080518581526001600160a01b03848116602083015285169133917f7da12116be8cb7af4b2d9e9b4a2ca2c3a3243ddd6fd3a94411902367b8eed568910160405180910390a3505060016000555050565b6006805460ff191682151590811790915560006007556040519081527f868d89ead22a5d10f456845ac0014901d9af7203e71cf0892d70d9dc262c2fb9906020015b60405180910390a150565b6000816001600160a01b0384166122e8578234146122e35760405162461bcd60e51b81526020600482015260076024820152662354413a30303560c81b604482015260640161069b565b612351565b60006122f385612b59565b9050341561232d5760405162461bcd60e51b815260206004820152600760248201526611aa209d18181b60c91b604482015260640161069b565b61233985333087612bed565b8061234386612b59565b61234d9190613eed565b9150505b90505b92915050565b604080516060808201835285825260208083018681529284018581528451808301899052935184860152518383015283518084039092018252608090920190925281519101205b9392505050565b6040805161018081019091526000908190806123c76020860186613314565b6001600160a01b031681526020018460200160208101906123e89190613314565b6001600160a01b031681526020016124066060860160408701613314565b6001600160a01b031681526020016124246080860160608701613314565b6001600160a01b0316815260200161244260a0860160808701613314565b6001600160a01b0316815260200161246060c0860160a08701613314565b6001600160a01b0316815260200161247e60e0860160c08701613314565b6001600160a01b0316815260200161249d610100860160e08701613314565b6001600160a01b031681526020018461014001358152602001846101600135815260200184610100013581526020018461012001358152509050806040516020016124e89190613bd9565b60405160208183030381529060405280519060200120915050919050565b6001600160a01b0383161561252557612520838383612bff565b505050565b6125208282612c0a565b60008060405180608001604052808881526020016040518060400160405280600681526020016518d85b98d95b60d21b8152508152602001878152602001866001600160a01b031681525090506125a6816040516020016125909190613cdb565b6040516020818303038152906040528585612c98565b979650505050505050565b600180546001600160a01b038381166001600160a01b0319831681179093556000600381905560405191909216929183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040805160a0810182528781526020808201889052825180840184526007815266199d5b199a5b1b60ca1b8183015282840152606082018790526001600160a01b038616608083015291516000926126689161259091849101613d2c565b98975050505050505050565b6000606061018086013585900385156126a1576126a161269a60a0890160808a01613314565b3388612506565b60006126b4610100890160e08a01613314565b6001600160a01b0316141561270c5780156126f2576126f26126dc60a0890160808a01613314565b6126ec60e08a0160c08b01613314565b83612506565b604080516000808252602082019092529250925050612876565b600061272e61272160a08a0160808b01613314565b6001600160a01b03161590565b90508015801561273e5750600082115b1561277d5761277d61275660a08a0160808b01613314565b7f0000000000000000000000005b9e4d0dd21f4e071729a9eb522a2366abed149a84612bff565b7f0000000000000000000000005b9e4d0dd21f4e071729a9eb522a2366abed149a6001600160a01b031663cf9a3604826127b85760006127ba565b835b6101208b01356127d16101008d0160e08e01613314565b6127e160a08e0160808f01613314565b8d60c00160208101906127f49190613314565b888d8d6040518963ffffffff1660e01b81526004016128199796959493929190613a24565b6000604051808303818588803b15801561283257600080fd5b505af1158015612846573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f1916820160405261286f9190810190613382565b9350935050505b94509492505050565b4260078190556040519081527fa78fdca214e4619ef34a695316d423f5b0d8274bc919d29733bf8f92ec8cbb7a906020015b60405180910390a1565b42600355600280546001600160a01b0319166001600160a01b0383169081179091556040517f6ab4d119f23076e8ad491bc65ce85f017fb0591dce08755ba8591059cc51737a90600090a250565b6004805460ff191682151590811790915560006005556040519081527f243ebbb2f905234bbf0556bb38e1f7c23b09ffd2e441a16e58b844eb2ab7a3979060200161228e565b6001600160a01b03811661298f5760405162461bcd60e51b815260206004820152600760248201526623414c3a30303160c81b604482015260640161069b565b600083116129c95760405162461bcd60e51b815260206004820152600760248201526611a0a61d18181960c91b604482015260640161069b565b6129d161064f565b806129f457506001600160a01b03811660009081526009602052604090205460ff165b612a2a5760405162461bcd60e51b815260206004820152600760248201526623414c3a30303360c81b604482015260640161069b565b612a326120a7565b80612a5557506001600160a01b0382166000908152600a602052604090205460ff165b612a8b5760405162461bcd60e51b815260206004820152600760248201526608d0530e8c0c0d60ca1b604482015260640161069b565b612a958284612299565b6001600160a01b038083166000908152600860209081526040808320938716835292905290812080549295508592909190612ad1908490613ed5565b9091555050604080518481523360208201526001600160a01b0380851692908416917f4bd28ccd068c4853d24d35f727ef2a3fea11ce55e8d93461e45f785818e1e139910160405180910390a3505050565b4260058190556040519081527fa52048c5f468d21a62e4644ac4db19bcaa1a20f0cf37d163ba49c7217d35feb8906020016128b1565b60006001600160a01b03821615612be6576040516370a0823160e01b81523060048201526001600160a01b038316906370a082319060240160206040518083038186803b158015612ba957600080fd5b505afa158015612bbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612be191906136f0565b612354565b4792915050565b612bf984848484612d3f565b50505050565b612520838383612daa565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612c57576040519150601f19603f3d011682016040523d82523d6000602084013e612c5c565b606091505b50509050806125205760405162461bcd60e51b8152602060048201526008602482015267046a89c82746064760c31b604482015260640161069b565b6000612d37612cfb85805190602001206040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612dda92505050565b949350505050565b6040516001600160a01b0380851660248301528316604482015260648101829052612bf99085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612e7e565b6040516001600160a01b03831660248201526044810182905261252090849063a9059cbb60e01b90606401612d73565b6000815160411415612e0e5760208201516040830151606084015160001a612e0486828585612f50565b9350505050612354565b815160401415612e365760208201516040830151612e2d8583836130f9565b92505050612354565b60405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161069b565b6000612ed3826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166131239092919063ffffffff16565b8051909150156125205780806020019051810190612ef19190613368565b6125205760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161069b565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0821115612fcd5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161069b565b8360ff16601b1480612fe257508360ff16601c145b6130395760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161069b565b6040805160008082526020820180845288905260ff871692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa15801561308d573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166130f05760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161069b565b95945050505050565b60006001600160ff1b03821660ff83901c601b0161311986828785612f50565b9695505050505050565b6060612d37848460008585843b61317c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161069b565b600080866001600160a01b031685876040516131989190613a08565b60006040518083038185875af1925050503d80600081146131d5576040519150601f19603f3d011682016040523d82523d6000602084013e6131da565b606091505b50915091506125a6828286606083156131f45750816123a1565b8251156132045782518084602001fd5b8160405162461bcd60e51b815260040161069b9190613a73565b604080516101e081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081019190915290565b80356107b481613f5c565b805180151581146107b457600080fd5b60008083601f8401126132c6578182fd5b50813567ffffffffffffffff8111156132dd578182fd5b6020830191508360208285010111156132f557600080fd5b9250929050565b60006101e0828403121561330e578081fd5b50919050565b600060208284031215613325578081fd5b813561235181613f5c565b60008060408385031215613342578081fd5b823561334d81613f5c565b9150602083013561335d81613f5c565b809150509250929050565b600060208284031215613379578081fd5b6123a1826132a5565b60008060408385031215613394578182fd5b61339d836132a5565b9150602083015167ffffffffffffffff808211156133b9578283fd5b818501915085601f8301126133cc578283fd5b8151818111156133de576133de613f46565b604051601f8201601f19908116603f0116810190838211818310171561340657613406613f46565b8160405282815288602084870101111561341e578586fd5b61342f836020830160208801613f04565b80955050505050509250929050565b60006020828403121561344f578081fd5b5035919050565b6000806000806000806000806000898b03610220811215613475578586fd5b61018080821215613484578687fd5b8b9a508a01359850506101a089013596506101c089013567ffffffffffffffff808211156134b0578687fd5b6134bc8d838e016132b5565b90985096506101e08c01359150808211156134d5578586fd5b6134e18d838e016132b5565b90965094506102008c01359150808211156134fa578384fd5b506135078c828d016132b5565b915080935050809150509295985092959850929598565b60008060006102008486031215613533578283fd5b61353d85856132fc565b92506101e084013567ffffffffffffffff811115613559578283fd5b613565868287016132b5565b9497909650939450505050565b600080600080600080610240878903121561358b578182fd5b61359588886132fc565b95506101e0870135945061020087013567ffffffffffffffff808211156135ba578384fd5b6135c68a838b016132b5565b90965094506102208901359150808211156135df578384fd5b506135ec89828a016132b5565b979a9699509497509295939492505050565b60006101e08284031215613610578081fd5b613618613eab565b6136218361329a565b815261362f6020840161329a565b60208201526136406040840161329a565b60408201526136516060840161329a565b60608201526136626080840161329a565b608082015261367360a0840161329a565b60a082015261368460c0840161329a565b60c082015261369560e0840161329a565b60e0820152610100838101359082015261012080840135908201526101408084013590820152610160808401359082015261018080840135908201526101a080840135908201526101c0928301359281019290925250919050565b600060208284031215613701578081fd5b5051919050565b6000806040838503121561371a578182fd5b82359150602083013561335d81613f5c565b600080600060608486031215613740578081fd5b83359250602084013561375281613f5c565b9150604084013561376281613f5c565b809150509250925092565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b600081518084526137ae816020860160208601613f04565b601f01601f19169290920160200192915050565b6137dc826137cf8361329a565b6001600160a01b03169052565b6137e86020820161329a565b6001600160a01b031660208301526138026040820161329a565b6001600160a01b0316604083015261381c6060820161329a565b6001600160a01b031660608301526138366080820161329a565b6001600160a01b0316608083015261385060a0820161329a565b6001600160a01b031660a083015261386a60c0820161329a565b6001600160a01b031660c083015261388460e0820161329a565b6001600160a01b031660e0830152610100818101359083015261012080820135908301526101408082013590830152610160808201359083015261018080820135908301526101a080820135908301526101c090810135910152565b80516001600160a01b03168252602081015161390760208401826001600160a01b03169052565b50604081015161392260408401826001600160a01b03169052565b50606081015161393d60608401826001600160a01b03169052565b50608081015161395860808401826001600160a01b03169052565b5060a081015161397360a08401826001600160a01b03169052565b5060c081015161398e60c08401826001600160a01b03169052565b5060e08101516139a960e08401826001600160a01b03169052565b50610100818101519083015261012080820151908301526101408082015190830152610160808201519083015261018080820151908301526101a080820151908301526101c090810151910152565b8183823760009101908152919050565b60008251613a1a818460208701613f04565b9190910192915050565b8781526001600160a01b0387811660208301528681166040830152851660608201526080810184905260c060a08201819052600090613a66908301848661376d565b9998505050505050505050565b6020815260006123a16020830184613796565b602080825260079082015266234f4f3a30323960c81b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6101808101613af0826137cf8561329a565b613afc6020840161329a565b6001600160a01b03166020830152613b166040840161329a565b6001600160a01b03166040830152613b306060840161329a565b6001600160a01b03166060830152613b4a6080840161329a565b6001600160a01b03166080830152613b6460a0840161329a565b6001600160a01b031660a0830152613b7e60c0840161329a565b6001600160a01b031660c0830152613b9860e0840161329a565b6001600160a01b031660e083015261010083810135908301526101208084013590830152610140808401359083015261016092830135929091019190915290565b81516001600160a01b0316815261018081016020830151613c0560208401826001600160a01b03169052565b506040830151613c2060408401826001600160a01b03169052565b506060830151613c3b60608401826001600160a01b03169052565b506080830151613c5660808401826001600160a01b03169052565b5060a0830151613c7160a08401826001600160a01b03169052565b5060c0830151613c8c60c08401826001600160a01b03169052565b5060e0830151613ca760e08401826001600160a01b03169052565b5061010083810151908301526101208084015190830152610140808401519083015261016092830151929091019190915290565b60208152815160208201526000602083015160806040840152613d0160a0840182613796565b6040850151606085810191909152909401516001600160a01b03166080909301929092525090919050565b6020815281516020820152602082015160408201526000604083015160a06060840152613d5c60c0840182613796565b6060850151608085810191909152909401516001600160a01b031660a0909301929092525090919050565b6102008101613d9682856137c2565b6001600160a01b03929092166101e09190910152919050565b60006102a0613dbe838d6137c2565b8a6101e084015280610200840152613dd98184018a8c61376d565b9050828103610220840152613def81888a61376d565b9050851515610240840152828103610260840152613e0d8186613796565b91505060018060a01b0383166102808301529a9950505050505050505050565b6101e0810161235482846138e0565b6000610260613e4b838c6138e0565b6001600160a01b038a166101e08401526102008301819052613e70818401898b61376d565b9050828103610220840152613e8681878961376d565b9050828103610240840152613e9c81858761376d565b9b9a5050505050505050505050565b6040516101e0810167ffffffffffffffff81118282101715613ecf57613ecf613f46565b60405290565b60008219821115613ee857613ee8613f30565b500190565b600082821015613eff57613eff613f30565b500390565b60005b83811015613f1f578181015183820152602001613f07565b83811115612bf95750506000910152565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114611de757600080fdfea264697066735822122038664d80b725d76538324127327ffb672ddf1977b3b07b22156be702f9a8cce964736f6c63430008040033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000000089
-----Decoded View---------------
Arg [0] : _chainId (uint256): 137
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000089
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
BSC | 21.56% | $1 | 55,808.5157 | $55,812.15 | |
BSC | 13.48% | $0.999596 | 34,902.8332 | $34,888.73 | |
BSC | 1.00% | $1 | 2,597.4993 | $2,597.91 | |
POL | 17.45% | $0.999948 | 45,176.1622 | $45,173.81 | |
POL | 7.79% | $0.999596 | 20,182.8066 | $20,174.65 | |
POL | 0.03% | $0.999998 | 78.2743 | $78.27 | |
ETH | 13.55% | $0.002672 | 13,128,801.6154 | $35,074.11 | |
ETH | 1.42% | $0.999996 | 3,681.9952 | $3,681.98 | |
ETH | 0.46% | $1 | 1,193.1516 | $1,193.15 | |
ETH | 0.38% | $0.999596 | 996.5793 | $996.18 | |
ETH | 0.20% | $3,129.97 | 0.1659 | $519.25 | |
ETH | <0.01% | $19.37 | 0.5 | $9.69 | |
GLMR | 7.75% | $0.999955 | 20,058.7148 | $20,057.81 | |
GLMR | 5.94% | $0.999594 | 15,377.3088 | $15,371.07 | |
GLMR | 0.41% | $1 | 1,063.5323 | $1,063.53 | |
OP | 6.33% | $0.999997 | 16,377.7804 | $16,377.73 | |
OP | 0.25% | $1 | 636.7425 | $636.74 | |
OP | 0.12% | $0.999594 | 304.9051 | $304.78 | |
OP | 0.07% | $3,133.45 | 0.0566 | $177.38 | |
ARBNOVA | 1.09% | $0.999948 | 2,822.1283 | $2,821.98 | |
ARBNOVA | 0.03% | $3,133.36 | 0.024 | $75.2 | |
AVAX | 0.22% | $0.999706 | 576.2205 | $576.05 | |
AVAX | 0.21% | $0.999997 | 533.2928 | $533.29 | |
AVAX | 0.11% | $1 | 296.8145 | $296.9 | |
AVAX | <0.01% | $3,110.18 | 0.0052857 | $16.44 | |
GNO | 0.08% | $0.999998 | 197.3071 | $197.31 | |
GNO | 0.06% | $0.999594 | 151.6946 | $151.63 | |
GNO | <0.01% | $1 | 3.999 | $4 | |
CRONOS | 0.01% | $0.999997 | 30.0628 | $30.06 |
[ 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.