More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 138,770 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Fulfill | 73227365 | 358 days ago | IN | 0 FTM | 0.00813649 | ||||
Fulfill | 73224991 | 358 days ago | IN | 0 FTM | 0.00982311 | ||||
Fulfill | 73224885 | 358 days ago | IN | 0 FTM | 0.0094848 | ||||
Prepare | 61854782 | 589 days ago | IN | 0 FTM | 0.04726395 | ||||
Fulfill | 56794217 | 657 days ago | IN | 0 FTM | 0.01704758 | ||||
Fulfill | 56790370 | 657 days ago | IN | 0 FTM | 0.01991651 | ||||
Fulfill | 56782402 | 657 days ago | IN | 0 FTM | 0.00239317 | ||||
Fulfill | 56782318 | 657 days ago | IN | 0 FTM | 0.0195662 | ||||
Fulfill | 56782067 | 657 days ago | IN | 0 FTM | 0.0027161 | ||||
Prepare | 56608916 | 660 days ago | IN | 0 FTM | 0.00366119 | ||||
Fulfill | 56582873 | 661 days ago | IN | 0 FTM | 0.00382041 | ||||
Prepare | 56553933 | 661 days ago | IN | 0 FTM | 0.00365847 | ||||
Fulfill | 56551815 | 661 days ago | IN | 0 FTM | 0.02341671 | ||||
Prepare | 56544065 | 661 days ago | IN | 0 FTM | 0.00336762 | ||||
Fulfill | 56503782 | 662 days ago | IN | 0 FTM | 0.01356122 | ||||
Fulfill | 56406074 | 664 days ago | IN | 0 FTM | 0.0034896 | ||||
Fulfill | 56406002 | 664 days ago | IN | 0 FTM | 0.00930208 | ||||
Prepare | 56397826 | 664 days ago | IN | 0 FTM | 0.00280292 | ||||
Prepare | 56350281 | 664 days ago | IN | 0 FTM | 0.00274664 | ||||
Prepare | 56338413 | 665 days ago | IN | 0 FTM | 0.00397381 | ||||
Prepare | 56294880 | 665 days ago | IN | 0 FTM | 0.00604 | ||||
Prepare | 56293361 | 665 days ago | IN | 0 FTM | 0.00538496 | ||||
Prepare | 56228479 | 666 days ago | IN | 0 FTM | 0.01280049 | ||||
Prepare | 56166288 | 667 days ago | IN | 0 FTM | 0.00359149 | ||||
Prepare | 56161246 | 667 days ago | IN | 0 FTM | 0.00311554 |
Latest 3 internal transactions
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
40168276 | 923 days ago | 0.0601 FTM | ||||
18291901 | 1171 days ago | Contract Creation | 0 FTM | |||
18291901 | 1171 days ago | Contract Creation | 0 FTM |
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 chain = block.chainid; } return 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 args TODO */ function prepare( PrepareArgs calldata args ) external payable override nonReentrant returns (TransactionData memory) { // Sanity check: user is sensible require(args.invariantData.user != address(0), "#P:009"); // Sanity check: router is sensible require(args.invariantData.router != address(0), "#P:001"); // Router is approved *on both chains* require(isRouterOwnershipRenounced() || approvedRouters[args.invariantData.router], "#P:003"); // Sanity check: sendingChainFallback is sensible require(args.invariantData.sendingChainFallback != address(0), "#P:010"); // Sanity check: valid fallback require(args.invariantData.receivingAddress != address(0), "#P:026"); // Make sure the chains are different require(args.invariantData.sendingChainId != args.invariantData.receivingChainId, "#P:011"); // Make sure the chains are relevant uint256 _chainId = getChainId(); require(args.invariantData.sendingChainId == _chainId || args.invariantData.receivingChainId == _chainId, "#P:012"); { // Expiry scope // Make sure the expiry is greater than min uint256 buffer = args.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(args.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. // Amount actually used (if fee-on-transfer will be different than // supplied) uint256 amount = args.amount; // First determine if this is sender side or receiver side if (args.invariantData.sendingChainId == _chainId) { // Check the sender is correct require(msg.sender == args.invariantData.initiator, "#P:039"); // 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(args.amount > 0, "#P:002"); // Assets are approved // NOTE: Cannot check this on receiving chain because of differing // chain contexts require(isAssetOwnershipRenounced() || approvedAssets[args.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( args.invariantData.sendingAssetId, args.amount ); // Store the transaction variants. This happens after transferring to // account for fee on transfer tokens variantTransactionData[digest] = hashVariantTransactionData( amount, args.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(args.invariantData.callTo == address(0) || Address.isContract(args.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[args.invariantData.receivingAssetId], "#P:004"); // Check that the caller is the router require(msg.sender == args.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[args.invariantData.router][args.invariantData.receivingAssetId]; require(balance >= amount, "#P:018"); // Store the transaction variants variantTransactionData[digest] = hashVariantTransactionData( amount, args.expiry, block.number ); // Decrement the router liquidity // using unchecked because underflow protected against with require unchecked { routerBalances[args.invariantData.router][args.invariantData.receivingAssetId] = balance - amount; } } // Emit event TransactionData memory txData = TransactionData({ receivingChainTxManagerAddress: args.invariantData.receivingChainTxManagerAddress, user: args.invariantData.user, router: args.invariantData.router, initiator: args.invariantData.initiator, sendingAssetId: args.invariantData.sendingAssetId, receivingAssetId: args.invariantData.receivingAssetId, sendingChainFallback: args.invariantData.sendingChainFallback, callTo: args.invariantData.callTo, receivingAddress: args.invariantData.receivingAddress, callDataHash: args.invariantData.callDataHash, transactionId: args.invariantData.transactionId, sendingChainId: args.invariantData.sendingChainId, receivingChainId: args.invariantData.receivingChainId, amount: amount, expiry: args.expiry, preparedBlockNumber: block.number }); emit TransactionPrepared( txData.user, txData.router, txData.transactionId, txData, msg.sender, args ); 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 args TODO */ function fulfill( FulfillArgs calldata args ) 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(args.txData); // Make sure that the variant data matches what was stored require(variantTransactionData[digest] == hashVariantTransactionData( args.txData.amount, args.txData.expiry, args.txData.preparedBlockNumber ), "#F:019"); // Make sure the expiry has not elapsed require(args.txData.expiry >= block.timestamp, "#F:020"); // Make sure the transaction wasn't already completed require(args.txData.preparedBlockNumber > 0, "#F:021"); // Check provided callData matches stored hash require(keccak256(args.callData) == args.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( args.txData.amount, args.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; bool isContract; bytes memory returnData; uint256 _chainId = getChainId(); if (args.txData.sendingChainId == _chainId) { // 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 == args.txData.router, "#F:016"); // Validate the user has signed require( recoverFulfillSignature( args.txData.transactionId, args.relayerFee, args.txData.receivingChainId, args.txData.receivingChainTxManagerAddress, args.signature ) == args.txData.user, "#F:022" ); // Complete tx to router for original sending amount routerBalances[args.txData.router][args.txData.sendingAssetId] += args.txData.amount; } else { // Validate the user has signed, using domain of contract require( recoverFulfillSignature( args.txData.transactionId, args.relayerFee, _chainId, address(this), args.signature ) == args.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(args.relayerFee <= args.txData.amount, "#F:023"); (success, isContract, returnData) = _receivingChainFulfill( args.txData, args.relayerFee, args.callData ); } // Emit event emit TransactionFulfilled( args.txData.user, args.txData.router, args.txData.transactionId, args, success, isContract, returnData, msg.sender ); return args.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 args TODO */ function cancel(CancelArgs calldata args) 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(args.txData); // Verify the variant data is correct require(variantTransactionData[digest] == hashVariantTransactionData(args.txData.amount, args.txData.expiry, args.txData.preparedBlockNumber), "#C:019"); // Make sure the transaction wasn't already completed require(args.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(args.txData.amount, args.txData.expiry, 0); // Get chainId for gas uint256 _chainId = getChainId(); // Return the appropriate locked funds if (args.txData.sendingChainId == _chainId) { // Sender side, funds must be returned to the user if (args.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 == args.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( args.txData.sendingAssetId, payable(args.txData.sendingChainFallback), args.txData.amount ); } else { // Receiver side, router liquidity is returned if (args.txData.expiry >= block.timestamp) { // Timeout has not expired and tx may only be cancelled by user // Validate signature require(msg.sender == args.txData.user || recoverCancelSignature(args.txData.transactionId, _chainId, address(this), args.signature) == args.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[args.txData.router][args.txData.receivingAssetId] += args.txData.amount; } // Emit event emit TransactionCancelled( args.txData.user, args.txData.router, args.txData.transactionId, args, msg.sender ); // Return return args.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, initiator: txData.initiator, 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, 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, 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, bool isContract ); 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, bool isContract, 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 initiator; // msg.sender of sending side 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 initiator; // msg.sender of sending side 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 } /** * Arguments for calling prepare() * @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 * @param encodedMeta The meta for the function */ struct PrepareArgs { InvariantTransactionData invariantData; uint256 amount; uint256 expiry; bytes encryptedCallData; bytes encodedBid; bytes bidSignature; bytes encodedMeta; } /** * @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` * @param encodedMeta The meta for the function */ struct FulfillArgs { TransactionData txData; uint256 relayerFee; bytes signature; bytes callData; bytes encodedMeta; } /** * Arguments for calling cancel() * @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 * @param encodedMeta The meta for the function */ struct CancelArgs { TransactionData txData; bytes signature; bytes encodedMeta; } // 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, PrepareArgs args ); event TransactionFulfilled( address indexed user, address indexed router, bytes32 indexed transactionId, FulfillArgs args, bool success, bool isContract, bytes returnData, address caller ); event TransactionCancelled( address indexed user, address indexed router, bytes32 indexed transactionId, CancelArgs args, 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( PrepareArgs calldata args ) external payable returns (TransactionData memory); function fulfill( FulfillArgs calldata args ) external returns (TransactionData memory); function cancel(CancelArgs calldata args) 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, 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; bool isContract = Address.isContract(callTo); if (isContract) { // 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, isContract ); return (success, isContract, returnData); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.4; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/Address.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 { Address.sendValue(recipient, amount); } /** * @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", "devdoc", "userdoc", "metadata", "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":[{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"initiator","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"},{"internalType":"bytes","name":"encodedMeta","type":"bytes"}],"indexed":false,"internalType":"struct ITransactionManager.CancelArgs","name":"args","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":[{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"initiator","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"},{"internalType":"bytes","name":"encodedMeta","type":"bytes"}],"indexed":false,"internalType":"struct ITransactionManager.FulfillArgs","name":"args","type":"tuple"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"bool","name":"isContract","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":"initiator","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"},{"components":[{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"initiator","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"},{"internalType":"bytes","name":"encodedMeta","type":"bytes"}],"indexed":false,"internalType":"struct ITransactionManager.PrepareArgs","name":"args","type":"tuple"}],"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":[{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"initiator","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"},{"internalType":"bytes","name":"encodedMeta","type":"bytes"}],"internalType":"struct ITransactionManager.CancelArgs","name":"args","type":"tuple"}],"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":"initiator","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":[{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"initiator","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"},{"internalType":"bytes","name":"encodedMeta","type":"bytes"}],"internalType":"struct ITransactionManager.FulfillArgs","name":"args","type":"tuple"}],"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":"initiator","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":[{"components":[{"internalType":"address","name":"receivingChainTxManagerAddress","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"router","type":"address"},{"internalType":"address","name":"initiator","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"},{"internalType":"bytes","name":"encodedMeta","type":"bytes"}],"internalType":"struct ITransactionManager.PrepareArgs","name":"args","type":"tuple"}],"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":"initiator","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
60c06040523480156200001157600080fd5b5060405162004fd338038062004fd3833981016040819052620000349162000105565b600160005562000044336200009e565b608081905260405130906200005990620000f7565b6001600160a01b039091168152602001604051809103906000f08015801562000086573d6000803e3d6000fd5b5060601b6001600160601b03191660a052506200011e565b600180546001600160a01b038381166001600160a01b0319831681179093556000600381905560405191909216929183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b610bf080620043e383390190565b60006020828403121562000117578081fd5b5051919050565b60805160a05160601c6142876200015c600039600081816102ee015281816127710152612798015260008181610264015261078901526142876000f3fe6080604052600436106102045760003560e01c80638da5cb5b11610118578063c95f9d0e116100a0578063de38eb3a1161006f578063de38eb3a146105db578063e070da09146105f2578063e47602f714610605578063e8be0dfc1461061a578063f31abcc41461062f57600080fd5b8063c95f9d0e14610578578063d1851c921461058b578063d232c220146105a9578063d9459372146105c857600080fd5b8063b1f8100d116100e7578063b1f8100d146104f9578063be91a2ba14610519578063c0c17baf14610539578063c1a049591461054e578063c5b350df1461056357600080fd5b80638da5cb5b1461045e57806397eb00881461047c5780639b151a80146104ac578063b1d2618d146104d957600080fd5b806341258b5c1161019b5780636a41633a1161016a5780636a41633a146103e95780636a42b8f8146103fe5780636ae0b15414610414578063715018a6146104345780638741eac51461044957600080fd5b806341258b5c1461033d578063445b1e4b14610375578063543ad1df146103a55780635e679856146103bc57600080fd5b806334e9393c116101d757806334e9393c146102a75780633855b467146102c75780633a35cf17146102dc5780633cf52ffb1461032857600080fd5b80632004ef451461020957806324ca984e1461023357806332a130c9146102555780633408e47014610292575b600080fd5b34801561021557600080fd5b5061021e61064f565b60405190151581526020015b60405180910390f35b34801561023f57600080fd5b5061025361024e366004613486565b610671565b005b34801561026157600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405190815260200161022a565b34801561029e57600080fd5b50610284610785565b3480156102b357600080fd5b506102536102c2366004613486565b6107b5565b3480156102d357600080fd5b50610253610880565b3480156102e857600080fd5b506103107f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161022a565b34801561033457600080fd5b50600354610284565b34801561034957600080fd5b506102846103583660046134a2565b600860209081526000928352604080842090915290825290205481565b34801561038157600080fd5b5061021e610390366004613486565b60096020526000908152604090205460ff1681565b3480156103b157600080fd5b506102846201518081565b3480156103c857600080fd5b506102846103d73660046135a7565b600b6020526000908152604090205481565b3480156103f557600080fd5b50600754610284565b34801561040a57600080fd5b5062093a80610284565b34801561042057600080fd5b5061025361042f366004613486565b61097b565b34801561044057600080fd5b50610253610a87565b34801561045557600080fd5b50610253610b8e565b34801561046a57600080fd5b506001546001600160a01b0316610310565b34801561048857600080fd5b5061021e610497366004613486565b600a6020526000908152604090205460ff1681565b3480156104b857600080fd5b506104cc6104c73660046135f8565b610bff565b60405161022a9190613fbf565b3480156104e557600080fd5b506102536104f4366004613486565b61108e565b34801561050557600080fd5b50610253610514366004613486565b61115a565b34801561052557600080fd5b506104cc6105343660046135bf565b611234565b34801561054557600080fd5b50610253611597565b34801561055a57600080fd5b50600554610284565b34801561056f57600080fd5b50610253611690565b610253610586366004613786565b61176a565b34801561059757600080fd5b506002546001600160a01b0316610310565b3480156105b557600080fd5b506001546001600160a01b03161561021e565b6104cc6105d6366004613631565b6117a6565b3480156105e757600080fd5b5061028462278d0081565b6102536106003660046137aa565b612104565b34801561061157600080fd5b50610253612141565b34801561062657600080fd5b5061021e6121b2565b34801561063b57600080fd5b5061025361064a3660046137aa565b6121d2565b6001546000906001600160a01b0316158061066c575060045460ff165b905090565b6001546001600160a01b031633146106a45760405162461bcd60e51b815260040161069b90613c3e565b60405180910390fd5b6001600160a01b0381166106e45760405162461bcd60e51b81526020600482015260076024820152662341523a30303160c81b604482015260640161069b565b6001600160a01b03811660009081526009602052604090205460ff16156107375760405162461bcd60e51b815260206004820152600760248201526611a0a91d18199960c91b604482015260640161069b565b6001600160a01b038116600081815260096020526040808220805460ff19166001179055513392917fbc68405e644da2aaf25623ce2199da82c6dfd2e1de102b400eba6a091704d4f491a350565b60007f0000000000000000000000000000000000000000000000000000000000000000806107b05750465b919050565b6001546001600160a01b031633146107df5760405162461bcd60e51b815260040161069b90613c3e565b6001600160a01b0381166000908152600a602052604090205460ff16156108325760405162461bcd60e51b815260206004820152600760248201526611a0a09d18199960c91b604482015260640161069b565b6001600160a01b0381166000818152600a6020526040808220805460ff19166001179055513392917f0bb5715f0f217c2fe9a0c877ea87d474380c641102f3440ee2a4c8b9d979091891a350565b6001546001600160a01b031633146108aa5760405162461bcd60e51b815260040161069b90613c3e565b60065460ff16156108e85760405162461bcd60e51b8152602060048201526008602482015267046a4829e746066760c31b604482015260640161069b565b6000600754116109255760405162461bcd60e51b81526020600482015260086024820152672352414f3a30333760c01b604482015260640161069b565b62093a806007544261093791906141cd565b1161096f5760405162461bcd60e51b815260206004820152600860248201526702352414f3a3033360c41b604482015260640161069b565b6109796001612357565b565b6001546001600160a01b031633146109a55760405162461bcd60e51b815260040161069b90613c3e565b6001600160a01b0381166109e55760405162461bcd60e51b81526020600482015260076024820152662352523a30303160c81b604482015260640161069b565b6001600160a01b03811660009081526009602052604090205460ff161515600114610a3c5760405162461bcd60e51b81526020600482015260076024820152662352523a30333360c81b604482015260640161069b565b6001600160a01b038116600081815260096020526040808220805460ff19169055513392917fbee3e974bb6a6f44f20096ede047c191eef60322e65e4ee4bd3392230a8716d591a350565b6001546001600160a01b03163314610ab15760405162461bcd60e51b815260040161069b90613c3e565b600060035411610aed5760405162461bcd60e51b815260206004820152600760248201526623524f3a30333760c81b604482015260640161069b565b62093a8060035442610aff91906141cd565b11610b365760405162461bcd60e51b8152602060048201526007602482015266023524f3a3033360cc1b604482015260640161069b565b6002546001600160a01b031615610b795760405162461bcd60e51b815260206004820152600760248201526611a9279d18199b60c91b604482015260640161069b565b600254610979906001600160a01b03166123a4565b6001546001600160a01b03163314610bb85760405162461bcd60e51b815260040161069b90613c3e565b60065460ff1615610bf75760405162461bcd60e51b8152602060048201526009602482015268046a0829ea4746066760bb1b604482015260640161069b565b6109796123fd565b610c076133e7565b60026000541415610c2a5760405162461bcd60e51b815260040161069b90613c5f565b60026000908155610c3a83612439565b9050610c566101a08401356101c08501356101e08601356125b7565b6000828152600b602052604090205414610c9b5760405162461bcd60e51b815260206004820152600660248201526523463a30313960d01b604482015260640161069b565b426101c08401351015610cd95760405162461bcd60e51b8152602060048201526006602482015265023463a3032360d41b604482015260640161069b565b6101e0830135610d145760405162461bcd60e51b815260206004820152600660248201526523463a30323160d01b604482015260640161069b565b610120830135610d286102408501856140c9565b604051610d36929190613bb0565b604051809103902014610d745760405162461bcd60e51b815260206004820152600660248201526508d18e8c0c8d60d21b604482015260640161069b565b610d8a6101a08401356101c085013560006125b7565b6000918252600b602052604082205580606081610da5610785565b9050610160860135811415610f1a57610dc46060870160408801613486565b6001600160a01b0316336001600160a01b031614610e0d5760405162461bcd60e51b815260206004820152600660248201526511a31d18189b60d11b604482015260640161069b565b610e1d6040870160208801613486565b6001600160a01b0316610e5b6101408801356102008901356101808a0135610e4860208c018c613486565b610e566102208d018d6140c9565b612605565b6001600160a01b031614610e9a5760405162461bcd60e51b815260206004820152600660248201526511a31d18191960d11b604482015260640161069b565b6101a086013560086000610eb460608a0160408b01613486565b6001600160a01b031681526020810191909152604001600090812090610ee060a08a0160808b01613486565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254610f0f91906141b5565b90915550610ff99050565b610f2a6040870160208801613486565b6001600160a01b0316610f526101408801356102008901358430610e566102208d018d6140c9565b6001600160a01b031614610f915760405162461bcd60e51b815260206004820152600660248201526511a31d18191960d11b604482015260640161069b565b6101a08601356102008701351115610fd45760405162461bcd60e51b815260206004820152600660248201526523463a30323360d01b604482015260640161069b565b610ff186610200810135610fec6102408301836140c9565b612687565b919550935091505b61014086013561100f6060880160408901613486565b6001600160a01b03166110286040890160208a01613486565b6001600160a01b03167f8e5df24f8b9ac0e3455417a1d7060762388ce3c1d4941aa49dc1b61943031d328988888833604051611068959493929190613d10565b60405180910390a461107f3687900387018761366a565b60016000559695505050505050565b6001546001600160a01b031633146110b85760405162461bcd60e51b815260040161069b90613c3e565b6001600160a01b0381166000908152600a602052604090205460ff16151560011461110f5760405162461bcd60e51b81526020600482015260076024820152662352413a30333360c81b604482015260640161069b565b6001600160a01b0381166000818152600a6020526040808220805460ff19169055513392917f0fa1e4606af435f32f05b3804033d2933e691fab32ee74d2db6fa82d2741f1ea91a350565b6001546001600160a01b031633146111845760405162461bcd60e51b815260040161069b90613c3e565b6002546001600160a01b0382811691161415806111a857506001600160a01b038116155b6111df5760405162461bcd60e51b815260206004820152600860248201526711a827279d18199b60c11b604482015260640161069b565b6001546001600160a01b03828116911614156112285760405162461bcd60e51b8152602060048201526008602482015267046a09c9e746066760c31b604482015260640161069b565b6112318161289f565b50565b61123c6133e7565b6002600054141561125f5760405162461bcd60e51b815260040161069b90613c5f565b6002600090815561126f83612439565b905061128b6101a08401356101c08501356101e08601356125b7565b6000828152600b6020526040902054146112d05760405162461bcd60e51b815260206004820152600660248201526523433a30313960d01b604482015260640161069b565b6101e083013561130b5760405162461bcd60e51b815260206004820152600660248201526523433a30323160d01b604482015260640161069b565b6113216101a08401356101c085013560006125b7565b6000828152600b602052604081209190915561133b610785565b90506101608401358114156113e257426101c0850135106113af576113666060850160408601613486565b6001600160a01b0316336001600160a01b0316146113af5760405162461bcd60e51b815260206004820152600660248201526523433a30323560d01b604482015260640161069b565b6113dd6113c260a0860160808701613486565b6113d260e0870160c08801613486565b6101a08701356128ed565b61150a565b426101c08501351061148f576113fe6040850160208601613486565b6001600160a01b0316336001600160a01b0316148061145a57506114286040850160208601613486565b6001600160a01b031661144f610140860135833061144a6102008a018a6140c9565b612916565b6001600160a01b0316145b61148f5760405162461bcd60e51b815260206004820152600660248201526511a19d18191960d11b604482015260640161069b565b6101a0840135600860006114a96060880160408901613486565b6001600160a01b0316815260208101919091526040016000908120906114d560c0880160a08901613486565b6001600160a01b03166001600160a01b03168152602001908152602001600020600082825461150491906141b5565b90915550505b6101408401356115206060860160408701613486565b6001600160a01b03166115396040870160208801613486565b6001600160a01b03167f56a92405e111173b950d90846413f755ca35bb7631d49a4a564778b21affe2878733604051611573929190613c96565b60405180910390a461158a3685900385018561366a565b6001600055949350505050565b6001546001600160a01b031633146115c15760405162461bcd60e51b815260040161069b90613c3e565b60045460ff16156115ff5760405162461bcd60e51b8152602060048201526008602482015267046a4a49e746066760c31b604482015260640161069b565b60006005541161163c5760405162461bcd60e51b81526020600482015260086024820152672352524f3a30333760c01b604482015260640161069b565b62093a806005544261164e91906141cd565b116116865760405162461bcd60e51b815260206004820152600860248201526702352524f3a3033360c41b604482015260640161069b565b6109796001612982565b6002546001600160a01b031633146116d45760405162461bcd60e51b8152602060048201526007602482015266234f503a30333560c81b604482015260640161069b565b6002546001546001600160a01b03908116911614156117205760405162461bcd60e51b815260206004820152600860248201526704682a09e746066760c31b604482015260640161069b565b62093a806003544261173291906141cd565b11610b795760405162461bcd60e51b815260206004820152600860248201526702341504f3a3033360c41b604482015260640161069b565b6002600054141561178d5760405162461bcd60e51b815260040161069b90613c5f565b600260005561179d8282336129c8565b50506001600055565b6117ae6133e7565b600260005414156117d15760405162461bcd60e51b815260040161069b90613c5f565b600260009081556117e86040840160208501613486565b6001600160a01b031614156118285760405162461bcd60e51b815260206004820152600660248201526523503a30303960d01b604482015260640161069b565b600061183a6060840160408501613486565b6001600160a01b0316141561187a5760405162461bcd60e51b815260206004820152600660248201526523503a30303160d01b604482015260640161069b565b61188261064f565b806118ba57506009600061189c6060850160408601613486565b6001600160a01b0316815260208101919091526040016000205460ff165b6118ef5760405162461bcd60e51b815260206004820152600660248201526523503a30303360d01b604482015260640161069b565b600061190160e0840160c08501613486565b6001600160a01b031614156119415760405162461bcd60e51b8152602060048201526006602482015265023503a3031360d41b604482015260640161069b565b6000611954610100840160e08501613486565b6001600160a01b031614156119945760405162461bcd60e51b815260206004820152600660248201526511a81d18191b60d11b604482015260640161069b565b61012082013561014083013514156119d75760405162461bcd60e51b815260206004820152600660248201526523503a30313160d01b604482015260640161069b565b60006119e1610785565b90506101208301358114806119fa575061014083013581145b611a2f5760405162461bcd60e51b815260206004820152600660248201526511a81d18189960d11b604482015260640161069b565b6000611a40426101c08601356141cd565b905062015180811015611a7e5760405162461bcd60e51b815260206004820152600660248201526523503a30313360d01b604482015260640161069b565b62278d00811115611aba5760405162461bcd60e51b815260206004820152600660248201526508d40e8c0c4d60d21b604482015260640161069b565b50604051600090611acf908590602001613dee565b60408051601f1981840301815291815281516020928301206000818152600b90935291205490915015611b2d5760405162461bcd60e51b815260206004820152600660248201526523503a30313560d01b604482015260640161069b565b6101a0840135610120850135831415611c9057611b506080860160608701613486565b6001600160a01b0316336001600160a01b031614611b995760405162461bcd60e51b815260206004820152600660248201526523503a30333960d01b604482015260640161069b565b6000856101a0013511611bd75760405162461bcd60e51b815260206004820152600660248201526511a81d18181960d11b604482015260640161069b565b611bdf6121b2565b80611c175750600a6000611bf960a0880160808901613486565b6001600160a01b0316815260208101919091526040016000205460ff165b611c4c5760405162461bcd60e51b815260206004820152600660248201526508d40e8c0c0d60d21b604482015260640161069b565b611c6a611c5f60a0870160808801613486565b866101a00135612b9c565b9050611c7c81866101c00135436125b7565b6000838152600b6020526040902055611f29565b6000611ca461012087016101008801613486565b6001600160a01b03161480611ccf5750611ccf611cc961012087016101008801613486565b3b151590565b611d045760405162461bcd60e51b815260206004820152600660248201526523503a30333160d01b604482015260640161069b565b611d0c6121b2565b80611d445750600a6000611d2660c0880160a08901613486565b6001600160a01b0316815260208101919091526040016000205460ff165b611d795760405162461bcd60e51b815260206004820152600660248201526508d40e8c0c0d60d21b604482015260640161069b565b611d896060860160408701613486565b6001600160a01b0316336001600160a01b031614611dd25760405162461bcd60e51b815260206004820152600660248201526511a81d18189b60d11b604482015260640161069b565b3415611e095760405162461bcd60e51b815260206004820152600660248201526523503a30313760d01b604482015260640161069b565b6000600881611e1e6060890160408a01613486565b6001600160a01b031681526020810191909152604001600090812090611e4a60c0890160a08a01613486565b6001600160a01b03166001600160a01b0316815260200190815260200160002054905081811015611ea65760405162461bcd60e51b8152602060048201526006602482015265046a0746062760d31b604482015260640161069b565b611eb682876101c00135436125b7565b6000848152600b6020526040808220929092558383039160089190611ee19060608b01908b01613486565b6001600160a01b031681526020810191909152604001600090812090611f0d60c08a0160a08b01613486565b6001600160a01b03168152602081019190915260400160002055505b60408051610200810190915260009080611f466020890189613486565b6001600160a01b03168152602090810190611f679060408a01908a01613486565b6001600160a01b03168152602001611f856060890160408a01613486565b6001600160a01b03168152602001611fa36080890160608a01613486565b6001600160a01b03168152602001611fc160a0890160808a01613486565b6001600160a01b03168152602001611fdf60c0890160a08a01613486565b6001600160a01b03168152602001611ffd60e0890160c08a01613486565b6001600160a01b0316815260200161201c610100890160e08a01613486565b6001600160a01b0316815260200161203c61012089016101008a01613486565b6001600160a01b031681526020018760000161016001358152602001876000016101800135815260200187600001610120013581526020018760000161014001358152602001838152602001876101c00135815260200143815250905080610140015181604001516001600160a01b031682602001516001600160a01b03167f88fbf1dbc326c404155bad4643bd0ddadd23f0636929c66442f0433208b2c90584338b6040516120ee93929190613fce565b60405180910390a4600160005595945050505050565b600260005414156121275760405162461bcd60e51b815260040161069b90613c5f565b60026000556121378383836129c8565b5050600160005550565b6001546001600160a01b0316331461216b5760405162461bcd60e51b815260040161069b90613c3e565b60045460ff16156121aa5760405162461bcd60e51b8152602060048201526009602482015268046a0a49ea4746066760bb1b604482015260640161069b565b610979612c5d565b6001546000906001600160a01b0316158061066c57505060065460ff1690565b600260005414156121f55760405162461bcd60e51b815260040161069b90613c5f565b60026000556001600160a01b03811661223a5760405162461bcd60e51b815260206004820152600760248201526623524c3a30303760c81b604482015260640161069b565b600083116122745760405162461bcd60e51b815260206004820152600760248201526611a9261d18181960c91b604482015260640161069b565b3360009081526008602090815260408083206001600160a01b0386168452909152902054838110156122d25760405162461bcd60e51b8152602060048201526007602482015266046a498746060760cb1b604482015260640161069b565b3360009081526008602090815260408083206001600160a01b0387168452909152902084820390556123058383866128ed565b604080518581526001600160a01b03848116602083015285169133917f7da12116be8cb7af4b2d9e9b4a2ca2c3a3243ddd6fd3a94411902367b8eed568910160405180910390a3505060016000555050565b6006805460ff191682151590811790915560006007556040519081527f868d89ead22a5d10f456845ac0014901d9af7203e71cf0892d70d9dc262c2fb9906020015b60405180910390a150565b600180546001600160a01b038381166001600160a01b0319831681179093556000600381905560405191909216929183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b4260078190556040519081527fa78fdca214e4619ef34a695316d423f5b0d8274bc919d29733bf8f92ec8cbb7a906020015b60405180910390a1565b604080516101a081019091526000908190806124586020860186613486565b6001600160a01b031681526020018460200160208101906124799190613486565b6001600160a01b031681526020016124976060860160408701613486565b6001600160a01b031681526020016124b56080860160608701613486565b6001600160a01b031681526020016124d360a0860160808701613486565b6001600160a01b031681526020016124f160c0860160a08701613486565b6001600160a01b0316815260200161250f60e0860160c08701613486565b6001600160a01b0316815260200161252e610100860160e08701613486565b6001600160a01b0316815260200161254e61012086016101008701613486565b6001600160a01b031681526020018461016001358152602001846101800135815260200184610120013581526020018461014001358152509050806040516020016125999190613dfd565b60405160208183030381529060405280519060200120915050919050565b604080516060808201835285825260208083018681529284018581528451808301899052935184860152518383015283518084039092018252608090920190925281519101205b9392505050565b6040805160a0810182528781526020808201889052825180840184526007815266199d5b199a5b1b60ca1b8183015282840152606082018790526001600160a01b038616608083015291516000926126799161266391849101613f64565b6040516020818303038152906040528585612c93565b9150505b9695505050505050565b60008060606101a087013586900386156126b5576126b56126ae60c08a0160a08b01613486565b33896128ed565b60006126c96101208a016101008b01613486565b6001600160a01b03161415612725578015612708576127086126f160c08a0160a08b01613486565b6127026101008b0160e08c01613486565b836128ed565b505060408051600080825260208201909252909250829150612895565b600061274761273a60c08b0160a08c01613486565b6001600160a01b03161590565b9050801580156127575750600082115b156127965761279661276f60c08b0160a08c01613486565b7f000000000000000000000000000000000000000000000000000000000000000084612d3a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cf9a3604826127d15760006127d3565b835b6101408c01356127eb6101208e016101008f01613486565b8d60a00160208101906127fe9190613486565b8e60e00160208101906128119190613486565b888e8e6040518963ffffffff1660e01b81526004016128369796959493929190613bdc565b6000604051808303818588803b15801561284f57600080fd5b505af1158015612863573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f1916820160405261288c91908101906134f4565b94509450945050505b9450945094915050565b42600355600280546001600160a01b0319166001600160a01b0383169081179091556040517f6ab4d119f23076e8ad491bc65ce85f017fb0591dce08755ba8591059cc51737a90600090a250565b6001600160a01b0383161561290c57612907838383612d3a565b505050565b6129078282612d45565b60008060405180608001604052808881526020016040518060400160405280600681526020016518d85b98d95b60d21b8152508152602001878152602001866001600160a01b03168152509050612977816040516020016126639190613f13565b979650505050505050565b6004805460ff191682151590811790915560006005556040519081527f243ebbb2f905234bbf0556bb38e1f7c23b09ffd2e441a16e58b844eb2ab7a39790602001612399565b6001600160a01b038116612a085760405162461bcd60e51b815260206004820152600760248201526623414c3a30303160c81b604482015260640161069b565b60008311612a425760405162461bcd60e51b815260206004820152600760248201526611a0a61d18181960c91b604482015260640161069b565b612a4a61064f565b80612a6d57506001600160a01b03811660009081526009602052604090205460ff165b612aa35760405162461bcd60e51b815260206004820152600760248201526623414c3a30303360c81b604482015260640161069b565b612aab6121b2565b80612ace57506001600160a01b0382166000908152600a602052604090205460ff165b612b045760405162461bcd60e51b815260206004820152600760248201526608d0530e8c0c0d60ca1b604482015260640161069b565b612b0e8284612b9c565b6001600160a01b038083166000908152600860209081526040808320938716835292905290812080549295508592909190612b4a9084906141b5565b9091555050604080518481523360208201526001600160a01b0380851692908416917f4bd28ccd068c4853d24d35f727ef2a3fea11ce55e8d93461e45f785818e1e139910160405180910390a3505050565b6000816001600160a01b038416612beb57823414612be65760405162461bcd60e51b81526020600482015260076024820152662354413a30303560c81b604482015260640161069b565b612c54565b6000612bf685612d53565b90503415612c305760405162461bcd60e51b815260206004820152600760248201526611aa209d18181b60c91b604482015260640161069b565b612c3c85333087612de7565b80612c4686612d53565b612c5091906141cd565b9150505b90505b92915050565b4260058190556040519081527fa52048c5f468d21a62e4644ac4db19bcaa1a20f0cf37d163ba49c7217d35feb89060200161242f565b6000612d32612cf685805190602001206040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612df992505050565b949350505050565b612907838383612e9d565b612d4f8282612f00565b5050565b60006001600160a01b03821615612de0576040516370a0823160e01b81523060048201526001600160a01b038316906370a082319060240160206040518083038186803b158015612da357600080fd5b505afa158015612db7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddb919061376e565b612c57565b4792915050565b612df384848484613019565b50505050565b6000815160411415612e2d5760208201516040830151606084015160001a612e2386828585613051565b9350505050612c57565b815160401415612e555760208201516040830151612e4c8583836131fa565b92505050612c57565b60405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161069b565b6040516001600160a01b03831660248201526044810182905261290790849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261321a565b80471015612f505760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015260640161069b565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612f9d576040519150601f19603f3d011682016040523d82523d6000602084013e612fa2565b606091505b50509050806129075760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d61792068617665207265766572746564000000000000606482015260840161069b565b6040516001600160a01b0380851660248301528316604482015260648101829052612df39085906323b872dd60e01b90608401612ec9565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08211156130ce5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161069b565b8360ff16601b14806130e357508360ff16601c145b61313a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161069b565b6040805160008082526020820180845288905260ff871692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa15801561318e573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166131f15760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161069b565b95945050505050565b60006001600160ff1b03821660ff83901c601b0161267d86828785613051565b600061326f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166132ec9092919063ffffffff16565b805190915015612907578080602001905181019061328d91906134da565b6129075760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161069b565b6060612d32848460008585843b6133455760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161069b565b600080866001600160a01b031685876040516133619190613bc0565b60006040518083038185875af1925050503d806000811461339e576040519150601f19603f3d011682016040523d82523d6000602084013e6133a3565b606091505b5091509150612977828286606083156133bd5750816125fe565b8251156133cd5782518084602001fd5b8160405162461bcd60e51b815260040161069b9190613c2b565b6040805161020081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290526101e081019190915290565b80356107b08161423c565b805180151581146107b057600080fd5b600060208284031215613497578081fd5b8135612c548161423c565b600080604083850312156134b4578081fd5b82356134bf8161423c565b915060208301356134cf8161423c565b809150509250929050565b6000602082840312156134eb578081fd5b6125fe82613476565b600080600060608486031215613508578081fd5b61351184613476565b925061351f60208501613476565b9150604084015167ffffffffffffffff8082111561353b578283fd5b818601915086601f83011261354e578283fd5b81518181111561356057613560614226565b613573601f8201601f191660200161413f565b9150808252876020828501011115613589578384fd5b61359a8160208401602086016141e4565b5080925050509250925092565b6000602082840312156135b8578081fd5b5035919050565b6000602082840312156135d0578081fd5b813567ffffffffffffffff8111156135e6578182fd5b82016102408185031215612c54578182fd5b600060208284031215613609578081fd5b813567ffffffffffffffff81111561361f578182fd5b82016102808185031215612c54578182fd5b600060208284031215613642578081fd5b813567ffffffffffffffff811115613658578182fd5b82016102608185031215612c54578182fd5b6000610200828403121561367c578081fd5b613684614115565b61368d8361346b565b815261369b6020840161346b565b60208201526136ac6040840161346b565b60408201526136bd6060840161346b565b60608201526136ce6080840161346b565b60808201526136df60a0840161346b565b60a08201526136f060c0840161346b565b60c082015261370160e0840161346b565b60e082015261010061371481850161346b565b9082015261012083810135908201526101408084013590820152610160808401359082015261018080840135908201526101a080840135908201526101c080840135908201526101e0928301359281019290925250919050565b60006020828403121561377f578081fd5b5051919050565b60008060408385031215613798578182fd5b8235915060208301356134cf8161423c565b6000806000606084860312156137be578081fd5b8335925060208401356137d08161423c565b915060408401356137e08161423c565b809150509250925092565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261382c8160208601602086016141e4565b601f01601f19169290920160200192915050565b61385a8261384d8361346b565b6001600160a01b03169052565b6138666020820161346b565b6001600160a01b031660208301526138806040820161346b565b6001600160a01b0316604083015261389a6060820161346b565b6001600160a01b031660608301526138b46080820161346b565b6001600160a01b031660808301526138ce60a0820161346b565b6001600160a01b031660a08301526138e860c0820161346b565b6001600160a01b031660c083015261390260e0820161346b565b6001600160a01b031660e083015261010061391e82820161346b565b6001600160a01b03169083015261012081810135908301526101408082013590830152610160808201359083015261018090810135910152565b6139658261384d8361346b565b6139716020820161346b565b6001600160a01b0316602083015261398b6040820161346b565b6001600160a01b031660408301526139a56060820161346b565b6001600160a01b031660608301526139bf6080820161346b565b6001600160a01b031660808301526139d960a0820161346b565b6001600160a01b031660a08301526139f360c0820161346b565b6001600160a01b031660c0830152613a0d60e0820161346b565b6001600160a01b031660e0830152610100613a2982820161346b565b6001600160a01b03169083015261012081810135908301526101408082013590830152610160808201359083015261018080820135908301526101a080820135908301526101c080820135908301526101e090810135910152565b80516001600160a01b031682526020810151613aab60208401826001600160a01b03169052565b506040810151613ac660408401826001600160a01b03169052565b506060810151613ae160608401826001600160a01b03169052565b506080810151613afc60808401826001600160a01b03169052565b5060a0810151613b1760a08401826001600160a01b03169052565b5060c0810151613b3260c08401826001600160a01b03169052565b5060e0810151613b4d60e08401826001600160a01b03169052565b50610100818101516001600160a01b03169083015261012080820151908301526101408082015190830152610160808201519083015261018080820151908301526101a080820151908301526101c080820151908301526101e090810151910152565b8183823760009101908152919050565b60008251613bd28184602087016141e4565b9190910192915050565b8781526001600160a01b0387811660208301528681166040830152851660608201526080810184905260c060a08201819052600090613c1e90830184866137eb565b9998505050505050505050565b6020815260006125fe6020830184613814565b602080825260079082015266234f4f3a30323960c81b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60408152613ca76040820184613958565b6000613cb7610200850185614170565b61024084810152613ccd610280850182846137eb565b915050613cde610220860186614170565b848303603f1901610260860152613cf68382846137eb565b935050505060018060a01b03831660208301529392505050565b60a08152613d2160a0820187613958565b6102008601356102a08201526000613d3d610220880188614170565b6102806102c0850152613d55610320850182846137eb565b915050613d66610240890189614170565b609f1980868503016102e0870152613d7f8483856137eb565b9350613d8f6102608c018c614170565b93509150808685030161030087015250613daa8383836137eb565b92505050613dbc602084018815159052565b85151560408401528281036060840152613dd68186613814565b91505061267d60808301846001600160a01b03169052565b6101a08101612c578284613840565b81516001600160a01b031681526101a081016020830151613e2960208401826001600160a01b03169052565b506040830151613e4460408401826001600160a01b03169052565b506060830151613e5f60608401826001600160a01b03169052565b506080830151613e7a60808401826001600160a01b03169052565b5060a0830151613e9560a08401826001600160a01b03169052565b5060c0830151613eb060c08401826001600160a01b03169052565b5060e0830151613ecb60e08401826001600160a01b03169052565b50610100838101516001600160a01b03169083015261012080840151908301526101408084015190830152610160808401519083015261018092830151929091019190915290565b60208152815160208201526000602083015160806040840152613f3960a0840182613814565b6040850151606085810191909152909401516001600160a01b03166080909301929092525090919050565b6020815281516020820152602082015160408201526000604083015160a06060840152613f9460c0840182613814565b6060850151608085810191909152909401516001600160a01b031660a0909301929092525090919050565b6102008101612c578284613a84565b6000610240613fdd8387613a84565b61020060018060a01b03861681850152610220828186015261400183860187613840565b6101a08601356103e08601526101c08601356104008601526140276101e0870187614170565b61026061042088015261403f6104a0880182846137eb565b91505061404e83880188614170565b935061023f19808884030161044089015261406a8386846137eb565b9450614078848a018a614170565b9450925080888603016104608901526140928585856137eb565b94506140a0868a018a614170565b9650935080888603016104808901525050506140bd8284836137eb565b98975050505050505050565b6000808335601e198436030181126140df578283fd5b83018035915067ffffffffffffffff8211156140f9578283fd5b60200191503681900382131561410e57600080fd5b9250929050565b604051610200810167ffffffffffffffff8111828210171561413957614139614226565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561416857614168614226565b604052919050565b6000808335601e19843603018112614186578283fd5b830160208101925035905067ffffffffffffffff8111156141a657600080fd5b80360383131561410e57600080fd5b600082198211156141c8576141c8614210565b500190565b6000828210156141df576141df614210565b500390565b60005b838110156141ff5781810151838201526020016141e7565b83811115612df35750506000910152565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461123157600080fdfea2646970667358221220a05c87d31e3a6ea060c72e56be8ebb28bec7975311797ac9ae2c0cf4b2d3d5a264736f6c6343000804003360a060405234801561001057600080fd5b50604051610bf0380380610bf083398101604081905261002f91610049565b600160005560601b6001600160601b031916608052610077565b60006020828403121561005a578081fd5b81516001600160a01b0381168114610070578182fd5b9392505050565b60805160601c610b5661009a600039600081816048015260a90152610b566000f3fe6080604052600436106100295760003560e01c806396f32fb81461002e578063cf9a360414610077575b600080fd5b34801561003a57600080fd5b506040516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681526020015b60405180910390f35b61008a6100853660046108c4565b610099565b60405161006e93929190610a79565b6000806060336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101065760405162461bcd60e51b8152602060048201526008602482015267234f544d3a30323760c01b60448201526064015b60405180910390fd5b6001600160a01b038816158061012157610121898b8961021b565b600060608b3b158015906101a0578c6001600160a01b031684610145576000610147565b8a5b8a8a6040516101579291906109c1565b60006040518083038185875af1925050503d8060008114610194576040519150601f19603f3d011682016040523d82523d6000602084013e610199565b606091505b5090935091505b826101c0576101b08c8c8c61026b565b836101c0576101c08c8e8c61028f565b8d7f03196b76502b81bbf14393f8b5ed67dff323f1f86667b064820f1fdf293686a18e8e8e8e8e8e898b8a604051610200999897969594939291906109ed565b60405180910390a2919d919c509a5098505050505050505050565b6001600160a01b03831661025b5760405162461bcd60e51b815260206004820152600760248201526608d2504e8c0ccd60ca1b60448201526064016100fd565b6102668383836102da565b505050565b6001600160a01b03831615610285576102668383836103d4565b61026682826103df565b6001600160a01b0383166102cf5760405162461bcd60e51b815260206004820152600760248201526608d1104e8c0ccd60ca1b60448201526064016100fd565b6102668383836103ed565b604051636eb1769f60e11b81523060048201526001600160a01b038381166024830152600091839186169063dd62ed3e9060440160206040518083038186803b15801561032657600080fd5b505afa15801561033a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061035e919061097d565b6103689190610ab8565b6040516001600160a01b0385166024820152604481018290529091506103ce90859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261050f565b50505050565b6102668383836105e1565b6103e98282610611565b5050565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e9060440160206040518083038186803b15801561043857600080fd5b505afa15801561044c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610470919061097d565b9050818110156104d45760405162461bcd60e51b815260206004820152602960248201527f5361666545524332303a2064656372656173656420616c6c6f77616e63652062604482015268656c6f77207a65726f60b81b60648201526084016100fd565b6040516001600160a01b0384166024820152828203604482018190529061050890869063095ea7b360e01b90606401610397565b5050505050565b6000610564826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661072a9092919063ffffffff16565b805190915015610266578080602001905181019061058291906108a4565b6102665760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016100fd565b6040516001600160a01b03831660248201526044810182905261026690849063a9059cbb60e01b90606401610397565b804710156106615760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e636500000060448201526064016100fd565b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146106ae576040519150601f19603f3d011682016040523d82523d6000602084013e6106b3565b606091505b50509050806102665760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d6179206861766520726576657274656400000000000060648201526084016100fd565b60606107398484600085610743565b90505b9392505050565b6060824710156107a45760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016100fd565b843b6107f25760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016100fd565b600080866001600160a01b0316858760405161080e91906109d1565b60006040518083038185875af1925050503d806000811461084b576040519150601f19603f3d011682016040523d82523d6000602084013e610850565b606091505b509150915061086082828661086b565b979650505050505050565b6060831561087a57508161073c565b82511561088a5782518084602001fd5b8160405162461bcd60e51b81526004016100fd9190610aa5565b6000602082840312156108b5578081fd5b8151801515811461073c578182fd5b600080600080600080600060c0888a0312156108de578283fd5b8735965060208801356108f081610b08565b9550604088013561090081610b08565b9450606088013561091081610b08565b93506080880135925060a088013567ffffffffffffffff80821115610933578384fd5b818a0191508a601f830112610946578384fd5b813581811115610954578485fd5b8b6020828501011115610965578485fd5b60208301945080935050505092959891949750929550565b60006020828403121561098e578081fd5b5051919050565b600081518084526109ad816020860160208601610adc565b601f01601f19169290920160200192915050565b8183823760009101908152919050565b600082516109e3818460208701610adc565b9190910192915050565b6001600160a01b038a8116825289811660208301528816604082015260608101879052610100608082018190528101859052600061012086888285013781818885010152601f19601f8801168301818482030160a0850152610a5182820188610995565b9250505083151560c0830152610a6b60e083018415159052565b9a9950505050505050505050565b83151581528215156020820152606060408201526000610a9c6060830184610995565b95945050505050565b60208152600061073c6020830184610995565b60008219821115610ad757634e487b7160e01b81526011600452602481fd5b500190565b60005b83811015610af7578181015183820152602001610adf565b838111156103ce5750506000910152565b6001600160a01b0381168114610b1d57600080fd5b5056fea26469706673582212202269da452bba446914352b77d48fb1282f9d93d6579e7d5164e4949a9439643864736f6c6343000804003300000000000000000000000000000000000000000000000000000000000000fa
Deployed Bytecode
0x6080604052600436106102045760003560e01c80638da5cb5b11610118578063c95f9d0e116100a0578063de38eb3a1161006f578063de38eb3a146105db578063e070da09146105f2578063e47602f714610605578063e8be0dfc1461061a578063f31abcc41461062f57600080fd5b8063c95f9d0e14610578578063d1851c921461058b578063d232c220146105a9578063d9459372146105c857600080fd5b8063b1f8100d116100e7578063b1f8100d146104f9578063be91a2ba14610519578063c0c17baf14610539578063c1a049591461054e578063c5b350df1461056357600080fd5b80638da5cb5b1461045e57806397eb00881461047c5780639b151a80146104ac578063b1d2618d146104d957600080fd5b806341258b5c1161019b5780636a41633a1161016a5780636a41633a146103e95780636a42b8f8146103fe5780636ae0b15414610414578063715018a6146104345780638741eac51461044957600080fd5b806341258b5c1461033d578063445b1e4b14610375578063543ad1df146103a55780635e679856146103bc57600080fd5b806334e9393c116101d757806334e9393c146102a75780633855b467146102c75780633a35cf17146102dc5780633cf52ffb1461032857600080fd5b80632004ef451461020957806324ca984e1461023357806332a130c9146102555780633408e47014610292575b600080fd5b34801561021557600080fd5b5061021e61064f565b60405190151581526020015b60405180910390f35b34801561023f57600080fd5b5061025361024e366004613486565b610671565b005b34801561026157600080fd5b507f00000000000000000000000000000000000000000000000000000000000000fa5b60405190815260200161022a565b34801561029e57600080fd5b50610284610785565b3480156102b357600080fd5b506102536102c2366004613486565b6107b5565b3480156102d357600080fd5b50610253610880565b3480156102e857600080fd5b506103107f0000000000000000000000000e893a2ca06da26a483d03c14a260847b218a23181565b6040516001600160a01b03909116815260200161022a565b34801561033457600080fd5b50600354610284565b34801561034957600080fd5b506102846103583660046134a2565b600860209081526000928352604080842090915290825290205481565b34801561038157600080fd5b5061021e610390366004613486565b60096020526000908152604090205460ff1681565b3480156103b157600080fd5b506102846201518081565b3480156103c857600080fd5b506102846103d73660046135a7565b600b6020526000908152604090205481565b3480156103f557600080fd5b50600754610284565b34801561040a57600080fd5b5062093a80610284565b34801561042057600080fd5b5061025361042f366004613486565b61097b565b34801561044057600080fd5b50610253610a87565b34801561045557600080fd5b50610253610b8e565b34801561046a57600080fd5b506001546001600160a01b0316610310565b34801561048857600080fd5b5061021e610497366004613486565b600a6020526000908152604090205460ff1681565b3480156104b857600080fd5b506104cc6104c73660046135f8565b610bff565b60405161022a9190613fbf565b3480156104e557600080fd5b506102536104f4366004613486565b61108e565b34801561050557600080fd5b50610253610514366004613486565b61115a565b34801561052557600080fd5b506104cc6105343660046135bf565b611234565b34801561054557600080fd5b50610253611597565b34801561055a57600080fd5b50600554610284565b34801561056f57600080fd5b50610253611690565b610253610586366004613786565b61176a565b34801561059757600080fd5b506002546001600160a01b0316610310565b3480156105b557600080fd5b506001546001600160a01b03161561021e565b6104cc6105d6366004613631565b6117a6565b3480156105e757600080fd5b5061028462278d0081565b6102536106003660046137aa565b612104565b34801561061157600080fd5b50610253612141565b34801561062657600080fd5b5061021e6121b2565b34801561063b57600080fd5b5061025361064a3660046137aa565b6121d2565b6001546000906001600160a01b0316158061066c575060045460ff165b905090565b6001546001600160a01b031633146106a45760405162461bcd60e51b815260040161069b90613c3e565b60405180910390fd5b6001600160a01b0381166106e45760405162461bcd60e51b81526020600482015260076024820152662341523a30303160c81b604482015260640161069b565b6001600160a01b03811660009081526009602052604090205460ff16156107375760405162461bcd60e51b815260206004820152600760248201526611a0a91d18199960c91b604482015260640161069b565b6001600160a01b038116600081815260096020526040808220805460ff19166001179055513392917fbc68405e644da2aaf25623ce2199da82c6dfd2e1de102b400eba6a091704d4f491a350565b60007f00000000000000000000000000000000000000000000000000000000000000fa806107b05750465b919050565b6001546001600160a01b031633146107df5760405162461bcd60e51b815260040161069b90613c3e565b6001600160a01b0381166000908152600a602052604090205460ff16156108325760405162461bcd60e51b815260206004820152600760248201526611a0a09d18199960c91b604482015260640161069b565b6001600160a01b0381166000818152600a6020526040808220805460ff19166001179055513392917f0bb5715f0f217c2fe9a0c877ea87d474380c641102f3440ee2a4c8b9d979091891a350565b6001546001600160a01b031633146108aa5760405162461bcd60e51b815260040161069b90613c3e565b60065460ff16156108e85760405162461bcd60e51b8152602060048201526008602482015267046a4829e746066760c31b604482015260640161069b565b6000600754116109255760405162461bcd60e51b81526020600482015260086024820152672352414f3a30333760c01b604482015260640161069b565b62093a806007544261093791906141cd565b1161096f5760405162461bcd60e51b815260206004820152600860248201526702352414f3a3033360c41b604482015260640161069b565b6109796001612357565b565b6001546001600160a01b031633146109a55760405162461bcd60e51b815260040161069b90613c3e565b6001600160a01b0381166109e55760405162461bcd60e51b81526020600482015260076024820152662352523a30303160c81b604482015260640161069b565b6001600160a01b03811660009081526009602052604090205460ff161515600114610a3c5760405162461bcd60e51b81526020600482015260076024820152662352523a30333360c81b604482015260640161069b565b6001600160a01b038116600081815260096020526040808220805460ff19169055513392917fbee3e974bb6a6f44f20096ede047c191eef60322e65e4ee4bd3392230a8716d591a350565b6001546001600160a01b03163314610ab15760405162461bcd60e51b815260040161069b90613c3e565b600060035411610aed5760405162461bcd60e51b815260206004820152600760248201526623524f3a30333760c81b604482015260640161069b565b62093a8060035442610aff91906141cd565b11610b365760405162461bcd60e51b8152602060048201526007602482015266023524f3a3033360cc1b604482015260640161069b565b6002546001600160a01b031615610b795760405162461bcd60e51b815260206004820152600760248201526611a9279d18199b60c91b604482015260640161069b565b600254610979906001600160a01b03166123a4565b6001546001600160a01b03163314610bb85760405162461bcd60e51b815260040161069b90613c3e565b60065460ff1615610bf75760405162461bcd60e51b8152602060048201526009602482015268046a0829ea4746066760bb1b604482015260640161069b565b6109796123fd565b610c076133e7565b60026000541415610c2a5760405162461bcd60e51b815260040161069b90613c5f565b60026000908155610c3a83612439565b9050610c566101a08401356101c08501356101e08601356125b7565b6000828152600b602052604090205414610c9b5760405162461bcd60e51b815260206004820152600660248201526523463a30313960d01b604482015260640161069b565b426101c08401351015610cd95760405162461bcd60e51b8152602060048201526006602482015265023463a3032360d41b604482015260640161069b565b6101e0830135610d145760405162461bcd60e51b815260206004820152600660248201526523463a30323160d01b604482015260640161069b565b610120830135610d286102408501856140c9565b604051610d36929190613bb0565b604051809103902014610d745760405162461bcd60e51b815260206004820152600660248201526508d18e8c0c8d60d21b604482015260640161069b565b610d8a6101a08401356101c085013560006125b7565b6000918252600b602052604082205580606081610da5610785565b9050610160860135811415610f1a57610dc46060870160408801613486565b6001600160a01b0316336001600160a01b031614610e0d5760405162461bcd60e51b815260206004820152600660248201526511a31d18189b60d11b604482015260640161069b565b610e1d6040870160208801613486565b6001600160a01b0316610e5b6101408801356102008901356101808a0135610e4860208c018c613486565b610e566102208d018d6140c9565b612605565b6001600160a01b031614610e9a5760405162461bcd60e51b815260206004820152600660248201526511a31d18191960d11b604482015260640161069b565b6101a086013560086000610eb460608a0160408b01613486565b6001600160a01b031681526020810191909152604001600090812090610ee060a08a0160808b01613486565b6001600160a01b03166001600160a01b031681526020019081526020016000206000828254610f0f91906141b5565b90915550610ff99050565b610f2a6040870160208801613486565b6001600160a01b0316610f526101408801356102008901358430610e566102208d018d6140c9565b6001600160a01b031614610f915760405162461bcd60e51b815260206004820152600660248201526511a31d18191960d11b604482015260640161069b565b6101a08601356102008701351115610fd45760405162461bcd60e51b815260206004820152600660248201526523463a30323360d01b604482015260640161069b565b610ff186610200810135610fec6102408301836140c9565b612687565b919550935091505b61014086013561100f6060880160408901613486565b6001600160a01b03166110286040890160208a01613486565b6001600160a01b03167f8e5df24f8b9ac0e3455417a1d7060762388ce3c1d4941aa49dc1b61943031d328988888833604051611068959493929190613d10565b60405180910390a461107f3687900387018761366a565b60016000559695505050505050565b6001546001600160a01b031633146110b85760405162461bcd60e51b815260040161069b90613c3e565b6001600160a01b0381166000908152600a602052604090205460ff16151560011461110f5760405162461bcd60e51b81526020600482015260076024820152662352413a30333360c81b604482015260640161069b565b6001600160a01b0381166000818152600a6020526040808220805460ff19169055513392917f0fa1e4606af435f32f05b3804033d2933e691fab32ee74d2db6fa82d2741f1ea91a350565b6001546001600160a01b031633146111845760405162461bcd60e51b815260040161069b90613c3e565b6002546001600160a01b0382811691161415806111a857506001600160a01b038116155b6111df5760405162461bcd60e51b815260206004820152600860248201526711a827279d18199b60c11b604482015260640161069b565b6001546001600160a01b03828116911614156112285760405162461bcd60e51b8152602060048201526008602482015267046a09c9e746066760c31b604482015260640161069b565b6112318161289f565b50565b61123c6133e7565b6002600054141561125f5760405162461bcd60e51b815260040161069b90613c5f565b6002600090815561126f83612439565b905061128b6101a08401356101c08501356101e08601356125b7565b6000828152600b6020526040902054146112d05760405162461bcd60e51b815260206004820152600660248201526523433a30313960d01b604482015260640161069b565b6101e083013561130b5760405162461bcd60e51b815260206004820152600660248201526523433a30323160d01b604482015260640161069b565b6113216101a08401356101c085013560006125b7565b6000828152600b602052604081209190915561133b610785565b90506101608401358114156113e257426101c0850135106113af576113666060850160408601613486565b6001600160a01b0316336001600160a01b0316146113af5760405162461bcd60e51b815260206004820152600660248201526523433a30323560d01b604482015260640161069b565b6113dd6113c260a0860160808701613486565b6113d260e0870160c08801613486565b6101a08701356128ed565b61150a565b426101c08501351061148f576113fe6040850160208601613486565b6001600160a01b0316336001600160a01b0316148061145a57506114286040850160208601613486565b6001600160a01b031661144f610140860135833061144a6102008a018a6140c9565b612916565b6001600160a01b0316145b61148f5760405162461bcd60e51b815260206004820152600660248201526511a19d18191960d11b604482015260640161069b565b6101a0840135600860006114a96060880160408901613486565b6001600160a01b0316815260208101919091526040016000908120906114d560c0880160a08901613486565b6001600160a01b03166001600160a01b03168152602001908152602001600020600082825461150491906141b5565b90915550505b6101408401356115206060860160408701613486565b6001600160a01b03166115396040870160208801613486565b6001600160a01b03167f56a92405e111173b950d90846413f755ca35bb7631d49a4a564778b21affe2878733604051611573929190613c96565b60405180910390a461158a3685900385018561366a565b6001600055949350505050565b6001546001600160a01b031633146115c15760405162461bcd60e51b815260040161069b90613c3e565b60045460ff16156115ff5760405162461bcd60e51b8152602060048201526008602482015267046a4a49e746066760c31b604482015260640161069b565b60006005541161163c5760405162461bcd60e51b81526020600482015260086024820152672352524f3a30333760c01b604482015260640161069b565b62093a806005544261164e91906141cd565b116116865760405162461bcd60e51b815260206004820152600860248201526702352524f3a3033360c41b604482015260640161069b565b6109796001612982565b6002546001600160a01b031633146116d45760405162461bcd60e51b8152602060048201526007602482015266234f503a30333560c81b604482015260640161069b565b6002546001546001600160a01b03908116911614156117205760405162461bcd60e51b815260206004820152600860248201526704682a09e746066760c31b604482015260640161069b565b62093a806003544261173291906141cd565b11610b795760405162461bcd60e51b815260206004820152600860248201526702341504f3a3033360c41b604482015260640161069b565b6002600054141561178d5760405162461bcd60e51b815260040161069b90613c5f565b600260005561179d8282336129c8565b50506001600055565b6117ae6133e7565b600260005414156117d15760405162461bcd60e51b815260040161069b90613c5f565b600260009081556117e86040840160208501613486565b6001600160a01b031614156118285760405162461bcd60e51b815260206004820152600660248201526523503a30303960d01b604482015260640161069b565b600061183a6060840160408501613486565b6001600160a01b0316141561187a5760405162461bcd60e51b815260206004820152600660248201526523503a30303160d01b604482015260640161069b565b61188261064f565b806118ba57506009600061189c6060850160408601613486565b6001600160a01b0316815260208101919091526040016000205460ff165b6118ef5760405162461bcd60e51b815260206004820152600660248201526523503a30303360d01b604482015260640161069b565b600061190160e0840160c08501613486565b6001600160a01b031614156119415760405162461bcd60e51b8152602060048201526006602482015265023503a3031360d41b604482015260640161069b565b6000611954610100840160e08501613486565b6001600160a01b031614156119945760405162461bcd60e51b815260206004820152600660248201526511a81d18191b60d11b604482015260640161069b565b61012082013561014083013514156119d75760405162461bcd60e51b815260206004820152600660248201526523503a30313160d01b604482015260640161069b565b60006119e1610785565b90506101208301358114806119fa575061014083013581145b611a2f5760405162461bcd60e51b815260206004820152600660248201526511a81d18189960d11b604482015260640161069b565b6000611a40426101c08601356141cd565b905062015180811015611a7e5760405162461bcd60e51b815260206004820152600660248201526523503a30313360d01b604482015260640161069b565b62278d00811115611aba5760405162461bcd60e51b815260206004820152600660248201526508d40e8c0c4d60d21b604482015260640161069b565b50604051600090611acf908590602001613dee565b60408051601f1981840301815291815281516020928301206000818152600b90935291205490915015611b2d5760405162461bcd60e51b815260206004820152600660248201526523503a30313560d01b604482015260640161069b565b6101a0840135610120850135831415611c9057611b506080860160608701613486565b6001600160a01b0316336001600160a01b031614611b995760405162461bcd60e51b815260206004820152600660248201526523503a30333960d01b604482015260640161069b565b6000856101a0013511611bd75760405162461bcd60e51b815260206004820152600660248201526511a81d18181960d11b604482015260640161069b565b611bdf6121b2565b80611c175750600a6000611bf960a0880160808901613486565b6001600160a01b0316815260208101919091526040016000205460ff165b611c4c5760405162461bcd60e51b815260206004820152600660248201526508d40e8c0c0d60d21b604482015260640161069b565b611c6a611c5f60a0870160808801613486565b866101a00135612b9c565b9050611c7c81866101c00135436125b7565b6000838152600b6020526040902055611f29565b6000611ca461012087016101008801613486565b6001600160a01b03161480611ccf5750611ccf611cc961012087016101008801613486565b3b151590565b611d045760405162461bcd60e51b815260206004820152600660248201526523503a30333160d01b604482015260640161069b565b611d0c6121b2565b80611d445750600a6000611d2660c0880160a08901613486565b6001600160a01b0316815260208101919091526040016000205460ff165b611d795760405162461bcd60e51b815260206004820152600660248201526508d40e8c0c0d60d21b604482015260640161069b565b611d896060860160408701613486565b6001600160a01b0316336001600160a01b031614611dd25760405162461bcd60e51b815260206004820152600660248201526511a81d18189b60d11b604482015260640161069b565b3415611e095760405162461bcd60e51b815260206004820152600660248201526523503a30313760d01b604482015260640161069b565b6000600881611e1e6060890160408a01613486565b6001600160a01b031681526020810191909152604001600090812090611e4a60c0890160a08a01613486565b6001600160a01b03166001600160a01b0316815260200190815260200160002054905081811015611ea65760405162461bcd60e51b8152602060048201526006602482015265046a0746062760d31b604482015260640161069b565b611eb682876101c00135436125b7565b6000848152600b6020526040808220929092558383039160089190611ee19060608b01908b01613486565b6001600160a01b031681526020810191909152604001600090812090611f0d60c08a0160a08b01613486565b6001600160a01b03168152602081019190915260400160002055505b60408051610200810190915260009080611f466020890189613486565b6001600160a01b03168152602090810190611f679060408a01908a01613486565b6001600160a01b03168152602001611f856060890160408a01613486565b6001600160a01b03168152602001611fa36080890160608a01613486565b6001600160a01b03168152602001611fc160a0890160808a01613486565b6001600160a01b03168152602001611fdf60c0890160a08a01613486565b6001600160a01b03168152602001611ffd60e0890160c08a01613486565b6001600160a01b0316815260200161201c610100890160e08a01613486565b6001600160a01b0316815260200161203c61012089016101008a01613486565b6001600160a01b031681526020018760000161016001358152602001876000016101800135815260200187600001610120013581526020018760000161014001358152602001838152602001876101c00135815260200143815250905080610140015181604001516001600160a01b031682602001516001600160a01b03167f88fbf1dbc326c404155bad4643bd0ddadd23f0636929c66442f0433208b2c90584338b6040516120ee93929190613fce565b60405180910390a4600160005595945050505050565b600260005414156121275760405162461bcd60e51b815260040161069b90613c5f565b60026000556121378383836129c8565b5050600160005550565b6001546001600160a01b0316331461216b5760405162461bcd60e51b815260040161069b90613c3e565b60045460ff16156121aa5760405162461bcd60e51b8152602060048201526009602482015268046a0a49ea4746066760bb1b604482015260640161069b565b610979612c5d565b6001546000906001600160a01b0316158061066c57505060065460ff1690565b600260005414156121f55760405162461bcd60e51b815260040161069b90613c5f565b60026000556001600160a01b03811661223a5760405162461bcd60e51b815260206004820152600760248201526623524c3a30303760c81b604482015260640161069b565b600083116122745760405162461bcd60e51b815260206004820152600760248201526611a9261d18181960c91b604482015260640161069b565b3360009081526008602090815260408083206001600160a01b0386168452909152902054838110156122d25760405162461bcd60e51b8152602060048201526007602482015266046a498746060760cb1b604482015260640161069b565b3360009081526008602090815260408083206001600160a01b0387168452909152902084820390556123058383866128ed565b604080518581526001600160a01b03848116602083015285169133917f7da12116be8cb7af4b2d9e9b4a2ca2c3a3243ddd6fd3a94411902367b8eed568910160405180910390a3505060016000555050565b6006805460ff191682151590811790915560006007556040519081527f868d89ead22a5d10f456845ac0014901d9af7203e71cf0892d70d9dc262c2fb9906020015b60405180910390a150565b600180546001600160a01b038381166001600160a01b0319831681179093556000600381905560405191909216929183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b4260078190556040519081527fa78fdca214e4619ef34a695316d423f5b0d8274bc919d29733bf8f92ec8cbb7a906020015b60405180910390a1565b604080516101a081019091526000908190806124586020860186613486565b6001600160a01b031681526020018460200160208101906124799190613486565b6001600160a01b031681526020016124976060860160408701613486565b6001600160a01b031681526020016124b56080860160608701613486565b6001600160a01b031681526020016124d360a0860160808701613486565b6001600160a01b031681526020016124f160c0860160a08701613486565b6001600160a01b0316815260200161250f60e0860160c08701613486565b6001600160a01b0316815260200161252e610100860160e08701613486565b6001600160a01b0316815260200161254e61012086016101008701613486565b6001600160a01b031681526020018461016001358152602001846101800135815260200184610120013581526020018461014001358152509050806040516020016125999190613dfd565b60405160208183030381529060405280519060200120915050919050565b604080516060808201835285825260208083018681529284018581528451808301899052935184860152518383015283518084039092018252608090920190925281519101205b9392505050565b6040805160a0810182528781526020808201889052825180840184526007815266199d5b199a5b1b60ca1b8183015282840152606082018790526001600160a01b038616608083015291516000926126799161266391849101613f64565b6040516020818303038152906040528585612c93565b9150505b9695505050505050565b60008060606101a087013586900386156126b5576126b56126ae60c08a0160a08b01613486565b33896128ed565b60006126c96101208a016101008b01613486565b6001600160a01b03161415612725578015612708576127086126f160c08a0160a08b01613486565b6127026101008b0160e08c01613486565b836128ed565b505060408051600080825260208201909252909250829150612895565b600061274761273a60c08b0160a08c01613486565b6001600160a01b03161590565b9050801580156127575750600082115b156127965761279661276f60c08b0160a08c01613486565b7f0000000000000000000000000e893a2ca06da26a483d03c14a260847b218a23184612d3a565b7f0000000000000000000000000e893a2ca06da26a483d03c14a260847b218a2316001600160a01b031663cf9a3604826127d15760006127d3565b835b6101408c01356127eb6101208e016101008f01613486565b8d60a00160208101906127fe9190613486565b8e60e00160208101906128119190613486565b888e8e6040518963ffffffff1660e01b81526004016128369796959493929190613bdc565b6000604051808303818588803b15801561284f57600080fd5b505af1158015612863573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f1916820160405261288c91908101906134f4565b94509450945050505b9450945094915050565b42600355600280546001600160a01b0319166001600160a01b0383169081179091556040517f6ab4d119f23076e8ad491bc65ce85f017fb0591dce08755ba8591059cc51737a90600090a250565b6001600160a01b0383161561290c57612907838383612d3a565b505050565b6129078282612d45565b60008060405180608001604052808881526020016040518060400160405280600681526020016518d85b98d95b60d21b8152508152602001878152602001866001600160a01b03168152509050612977816040516020016126639190613f13565b979650505050505050565b6004805460ff191682151590811790915560006005556040519081527f243ebbb2f905234bbf0556bb38e1f7c23b09ffd2e441a16e58b844eb2ab7a39790602001612399565b6001600160a01b038116612a085760405162461bcd60e51b815260206004820152600760248201526623414c3a30303160c81b604482015260640161069b565b60008311612a425760405162461bcd60e51b815260206004820152600760248201526611a0a61d18181960c91b604482015260640161069b565b612a4a61064f565b80612a6d57506001600160a01b03811660009081526009602052604090205460ff165b612aa35760405162461bcd60e51b815260206004820152600760248201526623414c3a30303360c81b604482015260640161069b565b612aab6121b2565b80612ace57506001600160a01b0382166000908152600a602052604090205460ff165b612b045760405162461bcd60e51b815260206004820152600760248201526608d0530e8c0c0d60ca1b604482015260640161069b565b612b0e8284612b9c565b6001600160a01b038083166000908152600860209081526040808320938716835292905290812080549295508592909190612b4a9084906141b5565b9091555050604080518481523360208201526001600160a01b0380851692908416917f4bd28ccd068c4853d24d35f727ef2a3fea11ce55e8d93461e45f785818e1e139910160405180910390a3505050565b6000816001600160a01b038416612beb57823414612be65760405162461bcd60e51b81526020600482015260076024820152662354413a30303560c81b604482015260640161069b565b612c54565b6000612bf685612d53565b90503415612c305760405162461bcd60e51b815260206004820152600760248201526611aa209d18181b60c91b604482015260640161069b565b612c3c85333087612de7565b80612c4686612d53565b612c5091906141cd565b9150505b90505b92915050565b4260058190556040519081527fa52048c5f468d21a62e4644ac4db19bcaa1a20f0cf37d163ba49c7217d35feb89060200161242f565b6000612d32612cf685805190602001206040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612df992505050565b949350505050565b612907838383612e9d565b612d4f8282612f00565b5050565b60006001600160a01b03821615612de0576040516370a0823160e01b81523060048201526001600160a01b038316906370a082319060240160206040518083038186803b158015612da357600080fd5b505afa158015612db7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ddb919061376e565b612c57565b4792915050565b612df384848484613019565b50505050565b6000815160411415612e2d5760208201516040830151606084015160001a612e2386828585613051565b9350505050612c57565b815160401415612e555760208201516040830151612e4c8583836131fa565b92505050612c57565b60405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161069b565b6040516001600160a01b03831660248201526044810182905261290790849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261321a565b80471015612f505760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015260640161069b565b6000826001600160a01b03168260405160006040518083038185875af1925050503d8060008114612f9d576040519150601f19603f3d011682016040523d82523d6000602084013e612fa2565b606091505b50509050806129075760405162461bcd60e51b815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d61792068617665207265766572746564000000000000606482015260840161069b565b6040516001600160a01b0380851660248301528316604482015260648101829052612df39085906323b872dd60e01b90608401612ec9565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08211156130ce5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161069b565b8360ff16601b14806130e357508360ff16601c145b61313a5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b606482015260840161069b565b6040805160008082526020820180845288905260ff871692820192909252606081018590526080810184905260019060a0016020604051602081039080840390855afa15801561318e573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166131f15760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161069b565b95945050505050565b60006001600160ff1b03821660ff83901c601b0161267d86828785613051565b600061326f826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166132ec9092919063ffffffff16565b805190915015612907578080602001905181019061328d91906134da565b6129075760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161069b565b6060612d32848460008585843b6133455760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161069b565b600080866001600160a01b031685876040516133619190613bc0565b60006040518083038185875af1925050503d806000811461339e576040519150601f19603f3d011682016040523d82523d6000602084013e6133a3565b606091505b5091509150612977828286606083156133bd5750816125fe565b8251156133cd5782518084602001fd5b8160405162461bcd60e51b815260040161069b9190613c2b565b6040805161020081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101829052610160810182905261018081018290526101a081018290526101c081018290526101e081019190915290565b80356107b08161423c565b805180151581146107b057600080fd5b600060208284031215613497578081fd5b8135612c548161423c565b600080604083850312156134b4578081fd5b82356134bf8161423c565b915060208301356134cf8161423c565b809150509250929050565b6000602082840312156134eb578081fd5b6125fe82613476565b600080600060608486031215613508578081fd5b61351184613476565b925061351f60208501613476565b9150604084015167ffffffffffffffff8082111561353b578283fd5b818601915086601f83011261354e578283fd5b81518181111561356057613560614226565b613573601f8201601f191660200161413f565b9150808252876020828501011115613589578384fd5b61359a8160208401602086016141e4565b5080925050509250925092565b6000602082840312156135b8578081fd5b5035919050565b6000602082840312156135d0578081fd5b813567ffffffffffffffff8111156135e6578182fd5b82016102408185031215612c54578182fd5b600060208284031215613609578081fd5b813567ffffffffffffffff81111561361f578182fd5b82016102808185031215612c54578182fd5b600060208284031215613642578081fd5b813567ffffffffffffffff811115613658578182fd5b82016102608185031215612c54578182fd5b6000610200828403121561367c578081fd5b613684614115565b61368d8361346b565b815261369b6020840161346b565b60208201526136ac6040840161346b565b60408201526136bd6060840161346b565b60608201526136ce6080840161346b565b60808201526136df60a0840161346b565b60a08201526136f060c0840161346b565b60c082015261370160e0840161346b565b60e082015261010061371481850161346b565b9082015261012083810135908201526101408084013590820152610160808401359082015261018080840135908201526101a080840135908201526101c080840135908201526101e0928301359281019290925250919050565b60006020828403121561377f578081fd5b5051919050565b60008060408385031215613798578182fd5b8235915060208301356134cf8161423c565b6000806000606084860312156137be578081fd5b8335925060208401356137d08161423c565b915060408401356137e08161423c565b809150509250925092565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000815180845261382c8160208601602086016141e4565b601f01601f19169290920160200192915050565b61385a8261384d8361346b565b6001600160a01b03169052565b6138666020820161346b565b6001600160a01b031660208301526138806040820161346b565b6001600160a01b0316604083015261389a6060820161346b565b6001600160a01b031660608301526138b46080820161346b565b6001600160a01b031660808301526138ce60a0820161346b565b6001600160a01b031660a08301526138e860c0820161346b565b6001600160a01b031660c083015261390260e0820161346b565b6001600160a01b031660e083015261010061391e82820161346b565b6001600160a01b03169083015261012081810135908301526101408082013590830152610160808201359083015261018090810135910152565b6139658261384d8361346b565b6139716020820161346b565b6001600160a01b0316602083015261398b6040820161346b565b6001600160a01b031660408301526139a56060820161346b565b6001600160a01b031660608301526139bf6080820161346b565b6001600160a01b031660808301526139d960a0820161346b565b6001600160a01b031660a08301526139f360c0820161346b565b6001600160a01b031660c0830152613a0d60e0820161346b565b6001600160a01b031660e0830152610100613a2982820161346b565b6001600160a01b03169083015261012081810135908301526101408082013590830152610160808201359083015261018080820135908301526101a080820135908301526101c080820135908301526101e090810135910152565b80516001600160a01b031682526020810151613aab60208401826001600160a01b03169052565b506040810151613ac660408401826001600160a01b03169052565b506060810151613ae160608401826001600160a01b03169052565b506080810151613afc60808401826001600160a01b03169052565b5060a0810151613b1760a08401826001600160a01b03169052565b5060c0810151613b3260c08401826001600160a01b03169052565b5060e0810151613b4d60e08401826001600160a01b03169052565b50610100818101516001600160a01b03169083015261012080820151908301526101408082015190830152610160808201519083015261018080820151908301526101a080820151908301526101c080820151908301526101e090810151910152565b8183823760009101908152919050565b60008251613bd28184602087016141e4565b9190910192915050565b8781526001600160a01b0387811660208301528681166040830152851660608201526080810184905260c060a08201819052600090613c1e90830184866137eb565b9998505050505050505050565b6020815260006125fe6020830184613814565b602080825260079082015266234f4f3a30323960c81b604082015260600190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60408152613ca76040820184613958565b6000613cb7610200850185614170565b61024084810152613ccd610280850182846137eb565b915050613cde610220860186614170565b848303603f1901610260860152613cf68382846137eb565b935050505060018060a01b03831660208301529392505050565b60a08152613d2160a0820187613958565b6102008601356102a08201526000613d3d610220880188614170565b6102806102c0850152613d55610320850182846137eb565b915050613d66610240890189614170565b609f1980868503016102e0870152613d7f8483856137eb565b9350613d8f6102608c018c614170565b93509150808685030161030087015250613daa8383836137eb565b92505050613dbc602084018815159052565b85151560408401528281036060840152613dd68186613814565b91505061267d60808301846001600160a01b03169052565b6101a08101612c578284613840565b81516001600160a01b031681526101a081016020830151613e2960208401826001600160a01b03169052565b506040830151613e4460408401826001600160a01b03169052565b506060830151613e5f60608401826001600160a01b03169052565b506080830151613e7a60808401826001600160a01b03169052565b5060a0830151613e9560a08401826001600160a01b03169052565b5060c0830151613eb060c08401826001600160a01b03169052565b5060e0830151613ecb60e08401826001600160a01b03169052565b50610100838101516001600160a01b03169083015261012080840151908301526101408084015190830152610160808401519083015261018092830151929091019190915290565b60208152815160208201526000602083015160806040840152613f3960a0840182613814565b6040850151606085810191909152909401516001600160a01b03166080909301929092525090919050565b6020815281516020820152602082015160408201526000604083015160a06060840152613f9460c0840182613814565b6060850151608085810191909152909401516001600160a01b031660a0909301929092525090919050565b6102008101612c578284613a84565b6000610240613fdd8387613a84565b61020060018060a01b03861681850152610220828186015261400183860187613840565b6101a08601356103e08601526101c08601356104008601526140276101e0870187614170565b61026061042088015261403f6104a0880182846137eb565b91505061404e83880188614170565b935061023f19808884030161044089015261406a8386846137eb565b9450614078848a018a614170565b9450925080888603016104608901526140928585856137eb565b94506140a0868a018a614170565b9650935080888603016104808901525050506140bd8284836137eb565b98975050505050505050565b6000808335601e198436030181126140df578283fd5b83018035915067ffffffffffffffff8211156140f9578283fd5b60200191503681900382131561410e57600080fd5b9250929050565b604051610200810167ffffffffffffffff8111828210171561413957614139614226565b60405290565b604051601f8201601f1916810167ffffffffffffffff8111828210171561416857614168614226565b604052919050565b6000808335601e19843603018112614186578283fd5b830160208101925035905067ffffffffffffffff8111156141a657600080fd5b80360383131561410e57600080fd5b600082198211156141c8576141c8614210565b500190565b6000828210156141df576141df614210565b500390565b60005b838110156141ff5781810151838201526020016141e7565b83811115612df35750506000910152565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461123157600080fdfea2646970667358221220a05c87d31e3a6ea060c72e56be8ebb28bec7975311797ac9ae2c0cf4b2d3d5a264736f6c63430008040033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000000000000000000fa
-----Decoded View---------------
Arg [0] : _chainId (uint256): 250
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000fa
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.