More Info
Private Name Tags
ContractCreator
Multichain Info
4 addresses found via
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x7fe29fda6278b6ba20c028a61f42786039205afac864e94df48d1c365ae49bd9 | - | (pending) | 28 days ago | IN | 0 CELO | (Pending) | |||
Update Relayer F... | 33501006 | 4 mins ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33500993 | 4 mins ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33500989 | 4 mins ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33500984 | 4 mins ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33500980 | 5 mins ago | IN | 0 CELO | 0.00094244 | ||||
Update Swap Rate | 33500972 | 5 mins ago | IN | 0 CELO | 0.00102499 | ||||
Update Relayer F... | 33497393 | 1 hr ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33497385 | 1 hr ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33497376 | 1 hr ago | IN | 0 CELO | 0.00094244 | ||||
Update Swap Rate | 33497371 | 1 hr ago | IN | 0 CELO | 0.00125541 | ||||
Update Relayer F... | 33493805 | 2 hrs ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33493797 | 2 hrs ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33493788 | 2 hrs ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33493767 | 2 hrs ago | IN | 0 CELO | 0.00094244 | ||||
Update Relayer F... | 33490186 | 3 hrs ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33490181 | 3 hrs ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33490177 | 3 hrs ago | IN | 0 CELO | 0.00094244 | ||||
Update Swap Rate | 33490172 | 3 hrs ago | IN | 0 CELO | 0.00102499 | ||||
Update Relayer F... | 33486580 | 4 hrs ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33486572 | 4 hrs ago | IN | 0 CELO | 0.00094244 | ||||
Update Relayer F... | 33482999 | 5 hrs ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33482994 | 5 hrs ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33482990 | 5 hrs ago | IN | 0 CELO | 0.00094212 | ||||
Update Relayer F... | 33482978 | 5 hrs ago | IN | 0 CELO | 0.00094244 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
33241227 | 3 days ago | 0.00745573 CELO | ||||
33093161 | 4 days ago | 0.00249999 CELO | ||||
33091967 | 4 days ago | 0.00499999 CELO | ||||
32816142 | 7 days ago | 0.00745403 CELO | ||||
32287662 | 14 days ago | 0.00749954 CELO | ||||
32002060 | 17 days ago | 0.04999414 CELO | ||||
31988236 | 17 days ago | 0.01246926 CELO | ||||
31085584 | 27 days ago | 0.04999116 CELO | ||||
31075425 | 28 days ago | 0.01494999 CELO | ||||
30714051 | 48 days ago | 0.04997382 CELO | ||||
30255353 | 74 days ago | 0.04999935 CELO | ||||
30255353 | 74 days ago | 0.00000064 CELO | ||||
30227565 | 76 days ago | 0.04998694 CELO | ||||
30227546 | 76 days ago | 0.04998694 CELO | ||||
30214970 | 77 days ago | 0.04949601 CELO | ||||
30125262 | 82 days ago | 0.00149811 CELO | ||||
30092510 | 84 days ago | 0.01699994 CELO | ||||
30053304 | 86 days ago | 0.04999999 CELO | ||||
30046211 | 86 days ago | 0.04995998 CELO | ||||
29862758 | 97 days ago | 0.04999782 CELO | ||||
29851635 | 98 days ago | 0.0014998 CELO | ||||
29827304 | 99 days ago | 0.00249898 CELO | ||||
29741750 | 104 days ago | 0.00999961 CELO | ||||
29447472 | 121 days ago | 0.04999253 CELO | ||||
29359255 | 126 days ago | 0.00711996 CELO |
Loading...
Loading
Contract Name:
TokenBridgeRelayer
Compiler Version
v0.8.17+commit.8df45f5f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.17; import {IWormhole} from "../interfaces/IWormhole.sol"; import {ITokenBridge} from "../interfaces/ITokenBridge.sol"; import "../libraries/BytesLib.sol"; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./TokenBridgeRelayerGovernance.sol"; import "./TokenBridgeRelayerMessages.sol"; /** * @title Wormhole Token Bridge Relayer * @notice This contract composes on Wormhole's Token Bridge contracts to faciliate * one-click transfers of Token Bridge supported assets cross chain. */ contract TokenBridgeRelayer is TokenBridgeRelayerGovernance, TokenBridgeRelayerMessages, ReentrancyGuard { using BytesLib for bytes; // contract version string public constant VERSION = "0.2.0"; constructor( address tokenBridge_, address wethAddress, address feeRecipient_, address ownerAssistant_, bool unwrapWeth_ ) { require(tokenBridge_ != address(0), "invalid token bridge address"); require(wethAddress != address(0), "invalid weth address"); require(feeRecipient_ != address(0), "invalid fee recipient"); require(ownerAssistant_ != address(0), "invalid owner assistant"); // set initial state setOwner(msg.sender); setFeeRecipient(feeRecipient_); setTokenBridge(tokenBridge_); setWethAddress(wethAddress); setOwnerAssistant(ownerAssistant_); setUnwrapWethFlag(unwrapWeth_); // fetch wormhole info from token bridge ITokenBridge bridge = ITokenBridge(tokenBridge_); setChainId(bridge.chainId()); setWormhole(address(bridge.wormhole())); // set the initial swapRate/relayer precisions to 1e8 setSwapRatePrecision(1e8); setRelayerFeePrecision(1e8); } /** * @notice Emitted when a transfer is completed by the Wormhole token bridge * @param emitterChainId Wormhole chain ID of emitter contract on the source chain * @param emitterAddress Address (bytes32 zero-left-padded) of emitter on the source chain * @param sequence Sequence of the Wormhole message */ event TransferRedeemed( uint16 indexed emitterChainId, bytes32 indexed emitterAddress, uint64 indexed sequence ); /** * @notice Emitted when a swap is executed with an off-chain relayer * @param recipient Address of the recipient of the native assets * @param relayer Address of the relayer that performed the swap * @param token Address of the token being swapped * @param tokenAmount Amount of token being swapped * @param nativeAmount Amount of native assets swapped for tokens */ event SwapExecuted( address indexed recipient, address indexed relayer, address indexed token, uint256 tokenAmount, uint256 nativeAmount ); /** * @notice Calls Wormhole's Token Bridge contract to emit a contract-controlled * transfer. The transfer message includes an arbitrary payload with instructions * for how to handle relayer payments on the target contract and the quantity of * tokens to convert into native assets for the user. * @param token ERC20 token address to transfer cross chain. * @param amount Quantity of tokens to be transferred. * @param toNativeTokenAmount Amount of tokens to swap into native assets on * the target chain. * @param targetChain Wormhole chain ID of the target blockchain. * @param targetRecipient User's wallet address on the target blockchain in bytes32 format * (zero-left-padded). * @param batchId ID for Wormhole message batching * @return messageSequence Wormhole sequence for emitted TransferTokensWithRelay message. */ function transferTokensWithRelay( address token, uint256 amount, uint256 toNativeTokenAmount, uint16 targetChain, bytes32 targetRecipient, uint32 batchId ) public payable nonReentrant notPaused returns (uint64 messageSequence) { // Cache wormhole fee and confirm that the user has passed enough // value to cover the wormhole protocol fee. uint256 wormholeFee = wormhole().messageFee(); require(msg.value == wormholeFee, "insufficient value"); // Cache token decimals, and remove dust from the amount argument. This // ensures that the dust is never transferred to this contract. uint8 tokenDecimals = getDecimals(token); amount = denormalizeAmount( normalizeAmount(amount, tokenDecimals), tokenDecimals ); // Transfer tokens from user to the this contract, and // override amount with actual amount received. amount = custodyTokens(token, amount); // call the internal _transferTokensWithRelay function messageSequence = _transferTokensWithRelay( InternalTransferParams({ token: token, amount: amount, tokenDecimals: tokenDecimals, toNativeTokenAmount: toNativeTokenAmount, targetChain: targetChain, targetRecipient: targetRecipient }), batchId, wormholeFee ); } /** * @notice Wraps Ether and calls Wormhole's Token Bridge contract to emit * a contract-controlled transfer. The transfer message includes an arbitrary * payload with instructions for how to handle relayer payments on the target * contract and the quantity of tokens to convert into native assets for the user. * @param toNativeTokenAmount Amount of tokens to swap into native assets on * the target chain. * @param targetChain Wormhole chain ID of the target blockchain. * @param targetRecipient User's wallet address on the target blockchain in bytes32 format * (zero-left-padded). * @param batchId ID for Wormhole message batching * @return messageSequence Wormhole sequence for emitted TransferTokensWithRelay message. */ function wrapAndTransferEthWithRelay( uint256 toNativeTokenAmount, uint16 targetChain, bytes32 targetRecipient, uint32 batchId ) public payable notPaused returns (uint64 messageSequence) { require(unwrapWeth(), "WETH functionality not supported"); // Cache wormhole fee and confirm that the user has passed enough // value to cover the wormhole protocol fee. uint256 wormholeFee = wormhole().messageFee(); require(msg.value > wormholeFee, "insufficient value"); // remove the wormhole protocol fee from the amount uint256 amount = msg.value - wormholeFee; // refund dust uint256 dust = amount - denormalizeAmount(normalizeAmount(amount, 18), 18); if (dust > 0) { payable(msg.sender).transfer(dust); } // remove dust from amount and cache WETH uint256 amountLessDust = amount - dust; IWETH weth = WETH(); // deposit into the WETH contract weth.deposit{ value : amountLessDust }(); // call the internal _transferTokensWithRelay function messageSequence = _transferTokensWithRelay( InternalTransferParams({ token: address(weth), tokenDecimals: 18, amount: amountLessDust, toNativeTokenAmount: toNativeTokenAmount, targetChain: targetChain, targetRecipient: targetRecipient }), batchId, wormholeFee ); } function _transferTokensWithRelay( InternalTransferParams memory params, uint32 batchId, uint256 wormholeFee ) internal returns (uint64 messageSequence) { // sanity check function arguments require(isAcceptedToken(params.token), "token not accepted"); require( params.targetRecipient != bytes32(0), "targetRecipient cannot be bytes32(0)" ); /** * Cache the normalized amount and verify that it's nonzero. * The token bridge peforms the same operation before encoding * the amount in the `TransferWithPayload` message. */ uint256 normalizedAmount = normalizeAmount( params.amount, params.tokenDecimals ); require(normalizedAmount > 0, "normalized amount must be > 0"); // normalized toNativeTokenAmount should be nonzero uint256 normalizedToNativeTokenAmount = normalizeAmount( params.toNativeTokenAmount, params.tokenDecimals ); require( params.toNativeTokenAmount == 0 || normalizedToNativeTokenAmount > 0, "invalid toNativeTokenAmount" ); // Cache the target contract address and verify that there // is a registered contract for the specified targetChain. bytes32 targetContract = getRegisteredContract(params.targetChain); require(targetContract != bytes32(0), "target not registered"); // Confirm that the user has sent enough tokens to cover the native swap // on the target chain and to pay the relayer fee. uint256 normalizedRelayerFee = normalizeAmount( calculateRelayerFee( params.targetChain, params.token, params.tokenDecimals ), params.tokenDecimals ); require( normalizedAmount > normalizedRelayerFee + normalizedToNativeTokenAmount, "insufficient amount" ); /** * Encode instructions (TransferWithRelay) to send with the token transfer. * The `targetRecipient` address is in bytes32 format (zero-left-padded) to * support non-evm smart contracts that have addresses that are longer * than 20 bytes. * * We normalize the relayerFee and toNativeTokenAmount to support * non-evm smart contracts that can only handle uint64.max values. */ bytes memory messagePayload = encodeTransferWithRelay( TransferWithRelay({ payloadId: 1, targetRelayerFee: normalizedRelayerFee, toNativeTokenAmount: normalizedToNativeTokenAmount, targetRecipient: params.targetRecipient }) ); // cache TokenBridge instance ITokenBridge bridge = tokenBridge(); // approve the token bridge to spend the specified tokens SafeERC20.safeApprove( IERC20(params.token), address(bridge), params.amount ); /** * Call `transferTokensWithPayload` method on the token bridge and pay * the Wormhole network fee. The token bridge will emit a Wormhole * message with an encoded `TransferWithPayload` struct (see the * ITokenBridge.sol interface file in this repo). */ messageSequence = bridge.transferTokensWithPayload{value: wormholeFee}( params.token, params.amount, params.targetChain, targetContract, batchId, messagePayload ); } /** * @notice Calls Wormhole's Token Bridge contract to complete token transfers. Takes * custody of the wrapped (or released) tokens and sends the tokens to the target recipient. * It pays the fee recipient in the minted token denomination. If requested by the user, * it will perform a swap with the off-chain relayer to provide the user with native assets. * If the `token` being transferred is WETH, the contract will unwrap native assets and send * the transferred amount to the recipient and pay the fee recipient in native assets. * @dev reverts if: * - the transferred token is not accepted by this contract * - the transffered token is not attested on this blockchain's Token Bridge contract * - the emitter of the transfer message is not registered with this contract * - the relayer fails to provide enough native assets to faciliate a native swap * - the recipient attempts to swap native assets when performing a self redemption * @param encodedTransferMessage Attested `TransferWithPayload` wormhole message. */ function completeTransferWithRelay(bytes calldata encodedTransferMessage) public payable { // complete the transfer by calling the token bridge (bytes memory payload, uint256 amount, address token) = _completeTransfer(encodedTransferMessage); // parse the payload into the `TransferWithRelay` struct TransferWithRelay memory transferWithRelay = decodeTransferWithRelay( payload ); // cache the recipient address and unwrap weth flag address recipient = bytes32ToAddress(transferWithRelay.targetRecipient); bool unwrapWeth = unwrapWeth(); // handle self redemptions if (msg.sender == recipient) { _completeSelfRedemption( token, recipient, amount, unwrapWeth ); // bail out return; } // cache token decimals uint8 tokenDecimals = getDecimals(token); // denormalize the encoded relayerFee transferWithRelay.targetRelayerFee = denormalizeAmount( transferWithRelay.targetRelayerFee, tokenDecimals ); // unwrap and transfer ETH if (token == address(WETH())) { _completeWethTransfer( amount, recipient, transferWithRelay.targetRelayerFee, unwrapWeth ); // bail out return; } // handle native asset payments and refunds if (transferWithRelay.toNativeTokenAmount > 0) { // denormalize the toNativeTokenAmount transferWithRelay.toNativeTokenAmount = denormalizeAmount( transferWithRelay.toNativeTokenAmount, tokenDecimals ); /** * Compute the maximum amount of tokens that the user is allowed * to swap for native assets. * * Override the toNativeTokenAmount in transferWithRelay if the * toNativeTokenAmount is greater than the maxToNativeAllowed. * * Compute the amount of native assets to send the recipient. */ uint256 maxToNativeAllowed = calculateMaxSwapAmountIn(token); if (transferWithRelay.toNativeTokenAmount > maxToNativeAllowed) { transferWithRelay.toNativeTokenAmount = maxToNativeAllowed; } // compute amount of native asset to pay the recipient uint256 nativeAmountForRecipient = calculateNativeSwapAmountOut( token, transferWithRelay.toNativeTokenAmount ); /** * The nativeAmountForRecipient can be zero if the user specifed * a toNativeTokenAmount that is too little to convert to native * asset. We need to override the toNativeTokenAmount to be zero * if that is the case, that way the user receives the full amount * of transferred tokens. */ if (nativeAmountForRecipient > 0) { // check to see if the relayer sent enough value require( msg.value >= nativeAmountForRecipient, "insufficient native asset amount" ); // refund excess native asset to relayer if applicable uint256 relayerRefund = msg.value - nativeAmountForRecipient; if (relayerRefund > 0) { payable(msg.sender).transfer(relayerRefund); } // send requested native asset to target recipient payable(recipient).transfer(nativeAmountForRecipient); // emit swap event emit SwapExecuted( recipient, msg.sender, token, transferWithRelay.toNativeTokenAmount, nativeAmountForRecipient ); } else { // override the toNativeTokenAmount in transferWithRelay transferWithRelay.toNativeTokenAmount = 0; // refund the relayer any native asset sent to this contract if (msg.value > 0) { payable(msg.sender).transfer(msg.value); } } } // add the token swap amount to the relayer fee uint256 amountForRelayer = transferWithRelay.targetRelayerFee + transferWithRelay.toNativeTokenAmount; // pay the fee recipient if amountForRelayer > 0 if (amountForRelayer > 0) { SafeERC20.safeTransfer( IERC20(token), feeRecipient(), amountForRelayer ); } // pay the target recipient the remaining tokens SafeERC20.safeTransfer( IERC20(token), recipient, amount - amountForRelayer ); } function _completeTransfer( bytes memory encodedTransferMessage ) internal returns (bytes memory, uint256, address) { /** * parse the encoded Wormhole message * * SECURITY: This message not been verified by the Wormhole core layer yet. * The encoded payload can only be trusted once the message has been verified * by the Wormhole core contract. In this case, the message will be verified * by a call to the token bridge contract in subsequent actions. */ IWormhole.VM memory parsedMessage = wormhole().parseVM( encodedTransferMessage ); /** * The amount encoded in the payload could be incorrect, * since fee-on-transfer tokens are supported by the token bridge. * * NOTE: The token bridge truncates the encoded amount for any token * with decimals greater than 8. This is to support blockchains that * cannot handle transfer amounts exceeding max(uint64). */ address localTokenAddress = fetchLocalAddressFromTransferMessage( parsedMessage.payload ); require(isAcceptedToken(localTokenAddress), "token not registered"); // check balance before completing the transfer uint256 balanceBefore = getBalance(localTokenAddress); // cache the token bridge instance ITokenBridge bridge = tokenBridge(); /** * Call `completeTransferWithPayload` on the token bridge. This * method acts as a reentrancy protection since it does not allow * transfers to be redeemed more than once. */ bytes memory transferPayload = bridge.completeTransferWithPayload( encodedTransferMessage ); // compute and save the balance difference after completing the transfer uint256 amountReceived = getBalance(localTokenAddress) - balanceBefore; // parse the wormhole message payload into the `TransferWithPayload` struct ITokenBridge.TransferWithPayload memory transfer = bridge.parseTransferWithPayload(transferPayload); // confirm that the message sender is a registered TokenBridgeRelayer contract require( transfer.fromAddress == getRegisteredContract(parsedMessage.emitterChainId), "contract not registered" ); // emit event with information about the TransferWithPayload message emit TransferRedeemed( parsedMessage.emitterChainId, parsedMessage.emitterAddress, parsedMessage.sequence ); return ( transfer.payload, amountReceived, localTokenAddress ); } function _completeSelfRedemption( address token, address recipient, uint256 amount, bool unwrapWeth ) internal { // revert if the caller sends ether to this contract require(msg.value == 0, "recipient cannot swap native assets"); // cache WETH instance IWETH weth = WETH(); // transfer the full amount to the recipient if (token == address(weth) && unwrapWeth) { // withdraw weth and send to the recipient weth.withdraw(amount); payable(recipient).transfer(amount); } else { SafeERC20.safeTransfer( IERC20(token), recipient, amount ); } } function _completeWethTransfer( uint256 amount, address recipient, uint256 relayerFee, bool unwrapWeth ) internal { // revert if the relayer sends ether to this contract require(msg.value == 0, "value must be zero"); /** * Check if the weth is unwrappable. Some wrapped native assets * are not unwrappable (e.g. CELO) and must be transferred via * the ERC20 interface. */ if (unwrapWeth) { // withdraw eth WETH().withdraw(amount); // transfer eth to recipient payable(recipient).transfer(amount - relayerFee); // transfer relayer fee to the fee recipient if (relayerFee > 0) { payable(feeRecipient()).transfer(relayerFee); } } else { // cache WETH instance IWETH weth = WETH(); // transfer the native asset to the caller SafeERC20.safeTransfer( IERC20(address(weth)), recipient, amount - relayerFee ); // transfer relayer fee to the fee recipient if (relayerFee > 0) { SafeERC20.safeTransfer( IERC20(address(weth)), feeRecipient(), relayerFee ); } } } /** * @notice Parses the encoded address and chainId from a `TransferWithPayload` * message. Finds the address of the wrapped token contract if the token is not * native to this chain. * @param payload Encoded `TransferWithPayload` message * @return localAddress Address of the encoded (bytes32 format) token address on * this chain. */ function fetchLocalAddressFromTransferMessage( bytes memory payload ) public view returns (address localAddress) { // parse the source token address and chainId bytes32 sourceAddress = payload.toBytes32(33); uint16 tokenChain = payload.toUint16(65); // Fetch the wrapped address from the token bridge if the token // is not from this chain. if (tokenChain != chainId()) { // identify wormhole token bridge wrapper localAddress = tokenBridge().wrappedAsset(tokenChain, sourceAddress); require(localAddress != address(0), "token not attested"); } else { // return the encoded address if the token is native to this chain localAddress = bytes32ToAddress(sourceAddress); } } /** * @notice Calculates the max amount of tokens the user can convert to * native assets on this chain. * @dev The max amount of native assets the contract will swap with the user * is governed by the `maxNativeSwapAmount` state variable. * @param token Address of token being transferred. * @return maxAllowed The maximum number of tokens the user is allowed to * swap for native assets. */ function calculateMaxSwapAmountIn( address token ) public view returns (uint256 maxAllowed) { // fetch the decimals for the token and native token uint8 tokenDecimals = getDecimals(token); uint8 nativeDecimals = getDecimals(address(WETH())); if (tokenDecimals > nativeDecimals) { maxAllowed = maxNativeSwapAmount(token) * nativeSwapRate(token) * 10 ** (tokenDecimals - nativeDecimals) / swapRatePrecision(); } else { maxAllowed = (maxNativeSwapAmount(token) * nativeSwapRate(token)) / (10 ** (nativeDecimals - tokenDecimals) * swapRatePrecision()); } } /** * @notice Calculates the amount of native assets that a user will receive * when swapping transferred tokens for native assets. * @param token Address of token being transferred. * @param toNativeAmount Quantity of tokens to be converted to native assets. * @return nativeAmount The exchange rate between native assets and the `toNativeAmount` * of transferred tokens. */ function calculateNativeSwapAmountOut( address token, uint256 toNativeAmount ) public view returns (uint256 nativeAmount) { // fetch the decimals for the token and native token uint8 tokenDecimals = getDecimals(token); uint8 nativeDecimals = getDecimals(address(WETH())); if (tokenDecimals > nativeDecimals) { nativeAmount = swapRatePrecision() * toNativeAmount / (nativeSwapRate(token) * 10 ** (tokenDecimals - nativeDecimals)); } else { nativeAmount = swapRatePrecision() * toNativeAmount * 10 ** (nativeDecimals - tokenDecimals) / nativeSwapRate(token); } } /** * @notice Converts the USD denominated relayer fee into the specified token * denomination. * @param targetChainId Wormhole chain ID of the target blockchain. * @param token Address of token being transferred. * @param decimals Token decimals of token being transferred. * @return feeInTokenDenomination Relayer fee denominated in tokens. */ function calculateRelayerFee( uint16 targetChainId, address token, uint8 decimals ) public view returns (uint256 feeInTokenDenomination) { // cache swap rate uint256 tokenSwapRate = swapRate(token); require(tokenSwapRate != 0, "swap rate not set"); feeInTokenDenomination = 10 ** decimals * relayerFee(targetChainId) * swapRatePrecision() / (tokenSwapRate * relayerFeePrecision()); } function custodyTokens( address token, uint256 amount ) internal returns (uint256) { // query own token balance before transfer uint256 balanceBefore = getBalance(token); // deposit tokens SafeERC20.safeTransferFrom( IERC20(token), msg.sender, address(this), amount ); // return the balance difference return getBalance(token) - balanceBefore; } function bytes32ToAddress(bytes32 address_) internal pure returns (address) { require(bytes12(address_) == 0, "invalid EVM address"); return address(uint160(uint256(address_))); } // necessary for receiving native assets receive() external payable {} }
// contracts/Messages.sol // SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.17; interface IWormhole { struct GuardianSet { address[] keys; uint32 expirationTime; } struct Signature { bytes32 r; bytes32 s; uint8 v; uint8 guardianIndex; } struct VM { uint8 version; uint32 timestamp; uint32 nonce; uint16 emitterChainId; bytes32 emitterAddress; uint64 sequence; uint8 consistencyLevel; bytes payload; uint32 guardianSetIndex; Signature[] signatures; bytes32 hash; } event LogMessagePublished(address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel); function publishMessage( uint32 nonce, bytes memory payload, uint8 consistencyLevel ) external payable returns (uint64 sequence); function parseAndVerifyVM(bytes calldata encodedVM) external view returns (VM memory vm, bool valid, string memory reason); function verifyVM(VM memory vm) external view returns (bool valid, string memory reason); function verifySignatures(bytes32 hash, Signature[] memory signatures, GuardianSet memory guardianSet) external pure returns (bool valid, string memory reason); function parseVM(bytes memory encodedVM) external pure returns (VM memory vm); function getGuardianSet(uint32 index) external view returns (GuardianSet memory); function getCurrentGuardianSetIndex() external view returns (uint32); function getGuardianSetExpiry() external view returns (uint32); function governanceActionIsConsumed(bytes32 hash) external view returns (bool); function isInitialized(address impl) external view returns (bool); function chainId() external view returns (uint16); function governanceChainId() external view returns (uint16); function governanceContract() external view returns (bytes32); function messageFee() external view returns (uint256); function evmChainId() external view returns (uint256); function nextSequence(address emitter) external view returns (uint64); }
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.17; import "./IWETH.sol"; import "./IWormhole.sol"; interface ITokenBridge { struct Transfer { uint8 payloadID; uint256 amount; bytes32 tokenAddress; uint16 tokenChain; bytes32 to; uint16 toChain; uint256 fee; } struct TransferWithPayload { uint8 payloadID; uint256 amount; bytes32 tokenAddress; uint16 tokenChain; bytes32 to; uint16 toChain; bytes32 fromAddress; bytes payload; } struct AssetMeta { uint8 payloadID; bytes32 tokenAddress; uint16 tokenChain; uint8 decimals; bytes32 symbol; bytes32 name; } struct RegisterChain { bytes32 module; uint8 action; uint16 chainId; uint16 emitterChainID; bytes32 emitterAddress; } struct UpgradeContract { bytes32 module; uint8 action; uint16 chainId; bytes32 newContract; } struct RecoverChainId { bytes32 module; uint8 action; uint256 evmChainId; uint16 newChainId; } event ContractUpgraded(address indexed oldContract, address indexed newContract); function _parseTransferCommon(bytes memory encoded) external pure returns (Transfer memory transfer); function attestToken(address tokenAddress, uint32 nonce) external payable returns (uint64 sequence); function wrapAndTransferETH(uint16 recipientChain, bytes32 recipient, uint256 arbiterFee, uint32 nonce) external payable returns (uint64 sequence); function wrapAndTransferETHWithPayload(uint16 recipientChain, bytes32 recipient, uint32 nonce, bytes memory payload) external payable returns (uint64 sequence); function transferTokens(address token, uint256 amount, uint16 recipientChain, bytes32 recipient, uint256 arbiterFee, uint32 nonce) external payable returns (uint64 sequence); function transferTokensWithPayload(address token, uint256 amount, uint16 recipientChain, bytes32 recipient, uint32 nonce, bytes memory payload) external payable returns (uint64 sequence); function updateWrapped(bytes memory encodedVm) external returns (address token); function createWrapped(bytes memory encodedVm) external returns (address token); function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory); function completeTransferAndUnwrapETHWithPayload(bytes memory encodedVm) external returns (bytes memory); function completeTransfer(bytes memory encodedVm) external; function completeTransferAndUnwrapETH(bytes memory encodedVm) external; function encodeAssetMeta(AssetMeta memory meta) external pure returns (bytes memory encoded); function encodeTransfer(Transfer memory transfer) external pure returns (bytes memory encoded); function encodeTransferWithPayload(TransferWithPayload memory transfer) external pure returns (bytes memory encoded); function parsePayloadID(bytes memory encoded) external pure returns (uint8 payloadID); function parseAssetMeta(bytes memory encoded) external pure returns (AssetMeta memory meta); function parseTransfer(bytes memory encoded) external pure returns (Transfer memory transfer); function parseTransferWithPayload(bytes memory encoded) external pure returns (TransferWithPayload memory transfer); function governanceActionIsConsumed(bytes32 hash) external view returns (bool); function isInitialized(address impl) external view returns (bool); function isTransferCompleted(bytes32 hash) external view returns (bool); function wormhole() external view returns (IWormhole); function chainId() external view returns (uint16); function evmChainId() external view returns (uint256); function isFork() external view returns (bool); function governanceChainId() external view returns (uint16); function governanceContract() external view returns (bytes32); function wrappedAsset(uint16 tokenChainId, bytes32 tokenAddress) external view returns (address); function bridgeContracts(uint16 chainId_) external view returns (bytes32); function tokenImplementation() external view returns (address); function WETH() external view returns (IWETH); function outstandingBridged(address token) external view returns (uint256); function isWrappedAsset(address token) external view returns (bool); function finality() external view returns (uint8); function implementation() external view returns (address); function initialize() external; function registerChain(bytes memory encodedVM) external; function upgrade(bytes memory encodedVM) external; function submitRecoverChainId(bytes memory encodedVM) external; function parseRegisterChain(bytes memory encoded) external pure returns (RegisterChain memory chain); function parseUpgrade(bytes memory encoded) external pure returns (UpgradeContract memory chain); function parseRecoverChainId(bytes memory encodedRecoverChainId) external pure returns (RecoverChainId memory rci); }
// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore(0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. )) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1 , "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol) 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 making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // 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 // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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); /** * @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 `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.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)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @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: Apache 2 pragma solidity ^0.8.17; import {IWormhole} from "../interfaces/IWormhole.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./TokenBridgeRelayerGetters.sol"; import "./TokenBridgeRelayerStructs.sol"; abstract contract TokenBridgeRelayerGovernance is TokenBridgeRelayerGetters { event OwnershipTransfered(address indexed oldOwner, address indexed newOwner); event FeeRecipientUpdated(address indexed oldRecipient, address indexed newRecipient); event SwapRateUpdated(TokenBridgeRelayerStructs.SwapRateUpdate[] indexed swapRates); /** * @notice Starts the ownership transfer process of the contracts. It saves * an address in the pending owner state variable. * @param chainId_ Wormhole chain ID. * @param newOwner Address of the pending owner. */ function submitOwnershipTransferRequest( uint16 chainId_, address newOwner ) public onlyOwner onlyCurrentChain(chainId_) { require(newOwner != address(0), "newOwner cannot equal address(0)"); setPendingOwner(newOwner); } /** * @notice Cancels the ownership transfer process. * @dev Sets the pending owner state variable to the zero address. */ function cancelOwnershipTransferRequest( uint16 chainId_ ) public onlyOwner onlyCurrentChain(chainId_) { setPendingOwner(address(0)); } /** * @notice Finalizes the ownership transfer to the pending owner. * @dev It checks that the caller is the pendingOwner to validate the wallet * address. It updates the owner state variable with the pendingOwner state * variable. */ function confirmOwnershipTransferRequest() public { // cache the new owner address address newOwner = pendingOwner(); require(msg.sender == newOwner, "caller must be pendingOwner"); // cache currentOwner for Event address currentOwner = owner(); // update the owner in the contract state and reset the pending owner setOwner(newOwner); setPendingOwner(address(0)); emit OwnershipTransfered(currentOwner, newOwner); } /** * @notice Updates the `ownerAssistant` state variable. This method can * only be executed by the owner. * @param chainId_ Wormhole chain ID. * @param newAssistant Address of the new `ownerAssistant`. */ function updateOwnerAssistant( uint16 chainId_, address newAssistant ) public onlyOwner onlyCurrentChain(chainId_) { require( newAssistant != address(0), "newAssistant cannot equal address(0)" ); // update the owner assistant setOwnerAssistant(newAssistant); } /** * @notice Updates the `feeRecipient` state variable. This method can * only be executed by the owner. * @param chainId_ Wormhole chain ID. * @param newFeeRecipient Address of the new `feeRecipient`. */ function updateFeeRecipient( uint16 chainId_, address newFeeRecipient ) public onlyOwner onlyCurrentChain(chainId_) { require( newFeeRecipient != address(0), "newFeeRecipient cannot equal address(0)" ); // cache current fee recipient address currentFeeRecipient = feeRecipient(); // update the fee recipient setFeeRecipient(newFeeRecipient); emit FeeRecipientUpdated(currentFeeRecipient, newFeeRecipient); } /** * @notice Updates the unwrapWeth state variable. * @dev This variable should only be set to true for chains that * support a WETH contract. Some chains (e.g. Celo, Karura, Acala) * do not support a WETH contract, and the address is set as a placeholder * for the native asset address for swapRate lookups. * @param chainId_ Wormhole chain ID. * @param unwrapWeth_ Boolean that determines if WETH is unwrapped * when transferred back to its native blockchain. */ function updateUnwrapWethFlag( uint16 chainId_, bool unwrapWeth_ ) public onlyOwner onlyCurrentChain(chainId_) { setUnwrapWethFlag(unwrapWeth_); } /** * @notice Registers foreign Token Bridge Relayer contracts. * @param chainId_ Wormhole chain ID of the foreign contract. * @param contractAddress Address of the foreign contract in bytes32 format * (zero-left-padded address). */ function registerContract( uint16 chainId_, bytes32 contractAddress ) public onlyOwner { // sanity check both input arguments require( contractAddress != bytes32(0), "contractAddress cannot equal bytes32(0)" ); require( chainId_ != 0 && chainId_ != chainId(), "chainId_ cannot equal 0 or this chainId" ); // update the registeredContracts state variable _registerContract(chainId_, contractAddress); } /** * @notice Register tokens accepted by this contract. * @param chainId_ Wormhole chain ID. * @param token Address of the token. */ function registerToken( uint16 chainId_, address token ) public onlyOwner onlyCurrentChain(chainId_) { require(token != address(0), "invalid token"); addAcceptedToken(token); } /** * @notice Deregister tokens accepted by this contract. * @dev The `removeAcceptedToken` function will revert * if the token is not registered. * @param chainId_ Wormhole chain ID. * @param token Address of the token. */ function deregisterToken( uint16 chainId_, address token ) public onlyOwner onlyCurrentChain(chainId_) { require(token != address(0), "invalid token"); removeAcceptedToken(token); } /** * @notice Updates the fee for relaying transfers to foreign contracts. * @param chainId_ Wormhole chain ID. * @param amount Amount of USD to pay the relayer upon redemption. * @dev The relayerFee is scaled by the relayerFeePrecision. For example, * if the relayerFee is $15 and the relayerFeePrecision is 1000000, the * relayerFee should be set to 15000000. */ function updateRelayerFee( uint16 chainId_, uint256 amount ) public onlyOwnerOrAssistant { require(chainId_ != chainId(), "invalid chain"); require( getRegisteredContract(chainId_) != bytes32(0), "contract doesn't exist" ); setRelayerFee(chainId_, amount); } /** * @notice Updates the precision of the relayer fee. * @param chainId_ Wormhole chain ID. * @param relayerFeePrecision_ Precision of relayer fee. */ function updateRelayerFeePrecision( uint16 chainId_, uint256 relayerFeePrecision_ ) public onlyOwner onlyCurrentChain(chainId_) { require(relayerFeePrecision_ > 0, "precision must be > 0"); setRelayerFeePrecision(relayerFeePrecision_); } /** * @notice Updates the swap rates for a batch of tokens. * @param chainId_ Wormhole chain ID. * @param swapRateUpdate Array of structs with token -> swap rate pairs. * @dev The swapRate is the conversion rate using asset prices denominated in * USD multiplied by the swapRatePrecision. For example, if the conversion * rate is $15 and the swapRatePrecision is 1000000, the swapRate should be set * to 15000000. * * NOTE: This function does NOT check if a token is specified twice. It is up to the * owner to correctly construct the `SwapRateUpdate` struct. */ function updateSwapRate( uint16 chainId_, TokenBridgeRelayerStructs.SwapRateUpdate[] calldata swapRateUpdate ) public onlyOwnerOrAssistant onlyCurrentChain(chainId_) { // cache length of swapRateUpdate array uint256 numTokens = swapRateUpdate.length; require(numTokens > 0, "invalid array size"); // set the swap rate for each token for (uint256 i = 0; i < numTokens;) { require( isAcceptedToken(swapRateUpdate[i].token), "token not accepted" ); require( swapRateUpdate[i].value > 0, "swap rate must be nonzero" ); setSwapRate(swapRateUpdate[i].token, swapRateUpdate[i].value); unchecked { i += 1; } } emit SwapRateUpdated(swapRateUpdate); } /** * @notice Updates the precision of the swap rate. * @param chainId_ Wormhole chain ID. * @param swapRatePrecision_ Precision of swap rate. */ function updateSwapRatePrecision( uint16 chainId_, uint256 swapRatePrecision_ ) public onlyOwner onlyCurrentChain(chainId_) { require(swapRatePrecision_ > 0, "precision must be > 0"); setSwapRatePrecision(swapRatePrecision_); } /** * @notice Updates the max amount of native assets the contract will pay * to the target recipient. * @param chainId_ Wormhole chain ID. * @param token Address of the token to update the max native swap amount for. * @param maxAmount Max amount of native assets. */ function updateMaxNativeSwapAmount( uint16 chainId_, address token, uint256 maxAmount ) public onlyOwner onlyCurrentChain(chainId_) { require(isAcceptedToken(token), "token not accepted"); setMaxNativeSwapAmount(token, maxAmount); } /** * @notice Sets the pause state of the relayer. If paused, token transfer * requests are blocked. In flight transfers, i.e. those that have a VAA * emitted, can still be processed if paused. * @param chainId_ Wormhole chain ID * @param paused If true, requests for token transfers will be blocked * and no VAAs will be generated. */ function setPauseForTransfers( uint16 chainId_, bool paused ) public onlyOwner onlyCurrentChain(chainId_) { setPaused(paused); } modifier onlyOwner() { require(owner() == msg.sender, "caller not the owner"); _; } modifier onlyOwnerOrAssistant() { require( owner() == msg.sender || ownerAssistant() == msg.sender, "caller not the owner or assistant" ); _; } modifier onlyCurrentChain(uint16 chainId_) { require(chainId() == chainId_, "wrong chain"); _; } modifier notPaused() { require(!getPaused(), "relayer is paused"); _; } }
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.17; import "../libraries/BytesLib.sol"; import "./TokenBridgeRelayerStructs.sol"; abstract contract TokenBridgeRelayerMessages is TokenBridgeRelayerStructs { using BytesLib for bytes; /** * @notice Encodes the TransferWithRelay struct into bytes. * @param transfer TransferWithRelay struct. * @return encoded TransferWithRelay struct encoded into bytes. */ function encodeTransferWithRelay( TransferWithRelay memory transfer ) public pure returns (bytes memory encoded) { require(transfer.payloadId == 1, "invalid payloadId"); encoded = abi.encodePacked( transfer.payloadId, transfer.targetRelayerFee, transfer.toNativeTokenAmount, transfer.targetRecipient ); } /** * @notice Decodes an encoded `TransferWithRelay` struct. * @dev reverts if: * - the first byte (payloadId) does not equal 1 * - the length of the payload has an unexpected length * @param encoded Encoded `TransferWithRelay` struct. * @return transfer `TransferTokenRelay` struct. */ function decodeTransferWithRelay( bytes memory encoded ) public pure returns (TransferWithRelay memory transfer) { uint256 index = 0; // parse the payloadId transfer.payloadId = encoded.toUint8(index); index += 1; require(transfer.payloadId == 1, "invalid payloadId"); // target relayer fee transfer.targetRelayerFee = encoded.toUint256(index); index += 32; // amount of tokens to convert to native assets transfer.toNativeTokenAmount = encoded.toUint256(index); index += 32; // recipient of the transfered tokens and native assets transfer.targetRecipient = encoded.toBytes32(index); index += 32; require(index == encoded.length, "invalid message length"); } }
// contracts/Bridge.sol // SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.17; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IWETH is IERC20 { function deposit() external payable; function withdraw(uint amount) external; function balanceOf() external returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @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 * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 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 functionCallWithValue(target, data, 0, "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"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, 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) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // 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 /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.17; import {IWormhole} from "../interfaces/IWormhole.sol"; import {ITokenBridge} from "../interfaces/ITokenBridge.sol"; import {IWETH} from "../interfaces/IWETH.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./TokenBridgeRelayerSetters.sol"; abstract contract TokenBridgeRelayerGetters is TokenBridgeRelayerSetters { function owner() public view returns (address) { return _state.owner; } function pendingOwner() public view returns (address) { return _state.pendingOwner; } function ownerAssistant() public view returns (address) { return _state.ownerAssistant; } function feeRecipient() public view returns (address) { return _state.feeRecipient; } function wormhole() public view returns (IWormhole) { return IWormhole(_state.wormhole); } function tokenBridge() public view returns (ITokenBridge) { return ITokenBridge(payable(_state.tokenBridge)); } function WETH() public view returns (IWETH) { return IWETH(_state.wethAddress); } function unwrapWeth() public view returns (bool) { return _state.unwrapWeth; } function chainId() public view returns (uint16) { return _state.chainId; } function getPaused() public view returns (bool) { return _state.paused; } function getRegisteredContract(uint16 emitterChainId) public view returns (bytes32) { return _state.registeredContracts[emitterChainId]; } function swapRatePrecision() public view returns (uint256) { return _state.swapRatePrecision; } function isAcceptedToken(address token) public view returns (bool) { return _state.acceptedTokens[token]; } function getAcceptedTokensList() public view returns (address[] memory) { return _state.acceptedTokensList; } function relayerFeePrecision() public view returns (uint256) { return _state.relayerFeePrecision; } function relayerFee(uint16 chainId_) public view returns (uint256) { return _state.relayerFees[chainId_]; } function maxNativeSwapAmount(address token) public view returns (uint256) { return _state.maxNativeSwapAmount[token]; } function swapRate(address token) public view returns (uint256) { return _state.swapRates[token]; } function nativeSwapRate(address token) public view returns (uint256) { uint256 nativeSwapRate_ = swapRate(_state.wethAddress); uint256 tokenSwapRate = swapRate(token); require( nativeSwapRate_ > 0 && tokenSwapRate > 0, "swap rate not set" ); return swapRatePrecision() * nativeSwapRate_ / tokenSwapRate; } function normalizeAmount( uint256 amount, uint8 decimals ) public pure returns (uint256) { if (decimals > 8) { amount /= 10 ** (decimals - 8); } return amount; } function denormalizeAmount( uint256 amount, uint8 decimals ) public pure returns (uint256) { if (decimals > 8) { amount *= 10 ** (decimals - 8); } return amount; } function getDecimals(address token) internal view returns (uint8) { (,bytes memory queriedDecimals) = token.staticcall( abi.encodeWithSignature("decimals()") ); return abi.decode(queriedDecimals, (uint8)); } function getBalance(address token) internal view returns (uint256 balance) { // fetch the specified token balance for this contract (, bytes memory queriedBalance) = token.staticcall( abi.encodeWithSelector(IERC20.balanceOf.selector, address(this)) ); balance = abi.decode(queriedBalance, (uint256)); } }
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.17; abstract contract TokenBridgeRelayerStructs { struct TransferWithRelay { uint8 payloadId; // == 1 uint256 targetRelayerFee; uint256 toNativeTokenAmount; bytes32 targetRecipient; } struct InternalTransferParams { address token; uint8 tokenDecimals; uint256 amount; uint256 toNativeTokenAmount; uint16 targetChain; bytes32 targetRecipient; } struct SwapRateUpdate { address token; uint256 value; } }
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.17; import "./TokenBridgeRelayerState.sol"; abstract contract TokenBridgeRelayerSetters is TokenBridgeRelayerState { function setOwner(address owner_) internal { _state.owner = owner_; } function setPendingOwner(address pendingOwner_) internal { _state.pendingOwner = pendingOwner_; } function setOwnerAssistant(address ownerAssistant_) internal { _state.ownerAssistant = ownerAssistant_; } function setFeeRecipient(address feeRecipient_) internal { _state.feeRecipient = feeRecipient_; } function setWormhole(address wormhole_) internal { _state.wormhole = payable(wormhole_); } function setTokenBridge(address tokenBridge_) internal { _state.tokenBridge = payable(tokenBridge_); } function setUnwrapWethFlag(bool unwrapWeth_) internal { _state.unwrapWeth = unwrapWeth_; } function setWethAddress(address weth_) internal { _state.wethAddress = weth_; } function setChainId(uint16 chainId_) internal { _state.chainId = chainId_; } function setPaused(bool paused) internal { _state.paused = paused; } function _registerContract(uint16 chainId_, bytes32 contract_) internal { _state.registeredContracts[chainId_] = contract_; } function setSwapRatePrecision(uint256 precision) internal { _state.swapRatePrecision = precision; } function setRelayerFeePrecision(uint256 precision) internal { _state.relayerFeePrecision = precision; } function addAcceptedToken(address token) internal { require( _state.acceptedTokens[token] == false, "token already registered" ); _state.acceptedTokens[token] = true; _state.acceptedTokensList.push(token); } function removeAcceptedToken(address token) internal { require( _state.acceptedTokens[token], "token not registered" ); // Remove the token from the acceptedTokens mapping, and // clear the token's swapRate and maxNativeSwapAmount. _state.acceptedTokens[token] = false; _state.swapRates[token] = 0; _state.maxNativeSwapAmount[token] = 0; // cache array length uint256 length_ = _state.acceptedTokensList.length; // Replace `token` in the acceptedTokensList with the last // element in the acceptedTokensList array. uint256 i = 0; for (; i < length_;) { if (_state.acceptedTokensList[i] == token) { break; } unchecked { i += 1; } } if (i != length_) { if (length_ > 1) { _state.acceptedTokensList[i] = _state.acceptedTokensList[length_ - 1]; } _state.acceptedTokensList.pop(); } } function setRelayerFee(uint16 chainId_, uint256 fee) internal { _state.relayerFees[chainId_] = fee; } function setSwapRate(address token, uint256 swapRate) internal { _state.swapRates[token] = swapRate; } function setMaxNativeSwapAmount(address token, uint256 maximum) internal { _state.maxNativeSwapAmount[token] = maximum; } }
// SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.17; import {IWormhole} from "../interfaces/IWormhole.sol"; abstract contract TokenBridgeRelayerStorage { struct State { // Wormhole chain ID of this contract uint16 chainId; // boolean to determine if weth is unwrappable bool unwrapWeth; // if true, token transfer requests are blocked bool paused; // address of WETH on this chain address wethAddress; // owner of this contract address owner; // address that can update swap rates and relayer fees address ownerAssistant; // recipient of relayer fees address feeRecipient; // intermediate state when transfering contract ownership address pendingOwner; // address of the Wormhole contract on this chain address wormhole; // address of the Wormhole TokenBridge contract on this chain address tokenBridge; // precision of the nativeSwapRates, this value should NEVER be set to zero uint256 swapRatePrecision; // precision of the relayerFee, this value should NEVER be set to zero uint256 relayerFeePrecision; // Wormhole chain ID to known relayer contract address mapping mapping(uint16 => bytes32) registeredContracts; // token swap rate in USD terms mapping(address => uint256) swapRates; /** * Mapping of source token address to maximum native asset swap amount * allowed. */ mapping(address => uint256) maxNativeSwapAmount; // mapping of chainId to relayerFee in USD mapping(uint16 => uint256) relayerFees; // accepted token to bool mapping mapping(address => bool) acceptedTokens; // list of accepted token addresses address[] acceptedTokensList; } } abstract contract TokenBridgeRelayerState { TokenBridgeRelayerStorage.State _state; }
{ "remappings": [ "@openzeppelin/=node_modules/@openzeppelin/", "@solidity-parser/=node_modules/@solidity-parser/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "wormhole-solidity/=modules/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"tokenBridge_","type":"address"},{"internalType":"address","name":"wethAddress","type":"address"},{"internalType":"address","name":"feeRecipient_","type":"address"},{"internalType":"address","name":"ownerAssistant_","type":"address"},{"internalType":"bool","name":"unwrapWeth_","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"newRecipient","type":"address"}],"name":"FeeRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransfered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nativeAmount","type":"uint256"}],"name":"SwapExecuted","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"indexed":true,"internalType":"struct TokenBridgeRelayerStructs.SwapRateUpdate[]","name":"swapRates","type":"tuple[]"}],"name":"SwapRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"emitterChainId","type":"uint16"},{"indexed":true,"internalType":"bytes32","name":"emitterAddress","type":"bytes32"},{"indexed":true,"internalType":"uint64","name":"sequence","type":"uint64"}],"name":"TransferRedeemed","type":"event"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"calculateMaxSwapAmountIn","outputs":[{"internalType":"uint256","name":"maxAllowed","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"toNativeAmount","type":"uint256"}],"name":"calculateNativeSwapAmountOut","outputs":[{"internalType":"uint256","name":"nativeAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChainId","type":"uint16"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"calculateRelayerFee","outputs":[{"internalType":"uint256","name":"feeInTokenDenomination","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"}],"name":"cancelOwnershipTransferRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTransferMessage","type":"bytes"}],"name":"completeTransferWithRelay","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"confirmOwnershipTransferRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encoded","type":"bytes"}],"name":"decodeTransferWithRelay","outputs":[{"components":[{"internalType":"uint8","name":"payloadId","type":"uint8"},{"internalType":"uint256","name":"targetRelayerFee","type":"uint256"},{"internalType":"uint256","name":"toNativeTokenAmount","type":"uint256"},{"internalType":"bytes32","name":"targetRecipient","type":"bytes32"}],"internalType":"struct TokenBridgeRelayerStructs.TransferWithRelay","name":"transfer","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"denormalizeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"address","name":"token","type":"address"}],"name":"deregisterToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint8","name":"payloadId","type":"uint8"},{"internalType":"uint256","name":"targetRelayerFee","type":"uint256"},{"internalType":"uint256","name":"toNativeTokenAmount","type":"uint256"},{"internalType":"bytes32","name":"targetRecipient","type":"bytes32"}],"internalType":"struct TokenBridgeRelayerStructs.TransferWithRelay","name":"transfer","type":"tuple"}],"name":"encodeTransferWithRelay","outputs":[{"internalType":"bytes","name":"encoded","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"feeRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"fetchLocalAddressFromTransferMessage","outputs":[{"internalType":"address","name":"localAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAcceptedTokensList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"emitterChainId","type":"uint16"}],"name":"getRegisteredContract","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"isAcceptedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"maxNativeSwapAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"nativeSwapRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"normalizeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownerAssistant","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"bytes32","name":"contractAddress","type":"bytes32"}],"name":"registerContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"address","name":"token","type":"address"}],"name":"registerToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"}],"name":"relayerFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"relayerFeePrecision","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"bool","name":"paused","type":"bool"}],"name":"setPauseForTransfers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"submitOwnershipTransferRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"swapRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapRatePrecision","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenBridge","outputs":[{"internalType":"contract ITokenBridge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"toNativeTokenAmount","type":"uint256"},{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"bytes32","name":"targetRecipient","type":"bytes32"},{"internalType":"uint32","name":"batchId","type":"uint32"}],"name":"transferTokensWithRelay","outputs":[{"internalType":"uint64","name":"messageSequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"unwrapWeth","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"address","name":"newFeeRecipient","type":"address"}],"name":"updateFeeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"maxAmount","type":"uint256"}],"name":"updateMaxNativeSwapAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"address","name":"newAssistant","type":"address"}],"name":"updateOwnerAssistant","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"updateRelayerFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"uint256","name":"relayerFeePrecision_","type":"uint256"}],"name":"updateRelayerFeePrecision","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct TokenBridgeRelayerStructs.SwapRateUpdate[]","name":"swapRateUpdate","type":"tuple[]"}],"name":"updateSwapRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"uint256","name":"swapRatePrecision_","type":"uint256"}],"name":"updateSwapRatePrecision","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"},{"internalType":"bool","name":"unwrapWeth_","type":"bool"}],"name":"updateUnwrapWethFlag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wormhole","outputs":[{"internalType":"contract IWormhole","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"toNativeTokenAmount","type":"uint256"},{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"bytes32","name":"targetRecipient","type":"bytes32"},{"internalType":"uint32","name":"batchId","type":"uint32"}],"name":"wrapAndTransferEthWithRelay","outputs":[{"internalType":"uint64","name":"messageSequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040523480156200001157600080fd5b50604051620049823803806200498283398101604081905262000034916200038c565b6001600f556001600160a01b038516620000955760405162461bcd60e51b815260206004820152601c60248201527f696e76616c696420746f6b656e2062726964676520616464726573730000000060448201526064015b60405180910390fd5b6001600160a01b038416620000ed5760405162461bcd60e51b815260206004820152601460248201527f696e76616c69642077657468206164647265737300000000000000000000000060448201526064016200008c565b6001600160a01b038316620001455760405162461bcd60e51b815260206004820152601560248201527f696e76616c69642066656520726563697069656e74000000000000000000000060448201526064016200008c565b6001600160a01b0382166200019d5760405162461bcd60e51b815260206004820152601760248201527f696e76616c6964206f776e657220617373697374616e7400000000000000000060448201526064016200008c565b600180546001600160a01b03191633179055600380546001600160a01b0319166001600160a01b038516179055600680546001600160a01b0319166001600160a01b03871617905560008054600160201b600160c01b0319166401000000006001600160a01b03871602179055600280546001600160a01b0319166001600160a01b0384161790556000805462ff0000191662010000831515021790556000859050620002c0816001600160a01b0316639a8a05926040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000282573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002a8919062000410565b6000805461ffff191661ffff92909216919091179055565b6200034b816001600160a01b03166384acd1bb6040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000303573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200032991906200043d565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b620003596305f5e100600755565b620003676305f5e100600855565b5050505050506200045d565b6001600160a01b03811681146200038957600080fd5b50565b600080600080600060a08688031215620003a557600080fd5b8551620003b28162000373565b6020870151909550620003c58162000373565b6040870151909450620003d88162000373565b6060870151909350620003eb8162000373565b608087015190925080151581146200040257600080fd5b809150509295509295909350565b6000602082840312156200042357600080fd5b815161ffff811681146200043657600080fd5b9392505050565b6000602082840312156200045057600080fd5b8151620004368162000373565b614515806200046d6000396000f3fe6080604052600436106102815760003560e01c80636805b84b1161014f5780639fe089ad116100c1578063cd601c781161007a578063cd601c781461083b578063df160d761461085b578063e30c39781461087d578063ea1d2e4a1461089b578063ffa1ad74146108bb578063fff982a8146108ec57600080fd5b80639fe089ad1461076b578063a2f32c8f14610798578063ad5c4648146107b8578063b5419523146107dd578063c6328a46146107fd578063c9c22f9f1461081b57600080fd5b80638da5cb5b116101135780638da5cb5b146106ac5780638e151dd1146106ca57806390a1afaa146106ea57806394cc743d1461070a5780639a8a05921461072a5780639cf278cd1461074d57600080fd5b80636805b84b146105db57806368aa9ef4146105fa5780637c9dec7a146106185780638335572f1461066e57806384acd1bb1461068e57600080fd5b80632def3e16116101f3578063415828bf116101ac578063415828bf14610517578063469048401461052c57806351e2d7b51461054a5780635b9cf0e11461056a578063640d946b1461058a57806366775a6b146105aa57600080fd5b80632def3e16146104145780632efe4f42146104345780632f25e25f1461046a57806339ba66111461047d5780633b6e750f1461049d5780633d62cca0146104e657600080fd5b8063203c509511610245578063203c50951461033357806327105ab91461035357806328ded8e31461037357806329ac8361146103935780632ca8008c146103a65780632d77e8fe146103dc57600080fd5b8063016aa2051461028d578063038c0b66146102af5780631019d654146102c45780631a282195146102f45780631acdab4b1461031457600080fd5b3661028857005b600080fd5b34801561029957600080fd5b506102ad6102a83660046137da565b61090c565b005b3480156102bb57600080fd5b506102ad6109d6565b6102d76102d2366004613825565b610ac3565b6040516001600160401b0390911681526020015b60405180910390f35b34801561030057600080fd5b506102ad61030f36600461389a565b610c63565b34801561032057600080fd5b506007545b6040519081526020016102eb565b34801561033f57600080fd5b506102ad61034e3660046137da565b610cec565b34801561035f57600080fd5b5061032561036e3660046138d7565b610e36565b34801561037f57600080fd5b5061032561038e3660046138d7565b610e70565b6102d76103a13660046138fc565b610e9e565b3480156103b257600080fd5b506103256103c1366004613946565b6001600160a01b03166000908152600a602052604090205490565b3480156103e857600080fd5b506103fc6103f7366004613a3e565b61113c565b6040516001600160a01b0390911681526020016102eb565b34801561042057600080fd5b506102ad61042f366004613abd565b61125c565b34801561044057600080fd5b5061032561044f366004613946565b6001600160a01b03166000908152600b602052604090205490565b6102ad610478366004613ae9565b61131a565b34801561048957600080fd5b50610325610498366004613b5a565b611647565b3480156104a957600080fd5b506104d66104b8366004613946565b6001600160a01b03166000908152600d602052604090205460ff1690565b60405190151581526020016102eb565b3480156104f257600080fd5b50610325610501366004613ba5565b61ffff1660009081526009602052604090205490565b34801561052357600080fd5b50600854610325565b34801561053857600080fd5b506003546001600160a01b03166103fc565b34801561055657600080fd5b506102ad610565366004613abd565b6116fa565b34801561057657600080fd5b506102ad610585366004613abd565b611824565b34801561059657600080fd5b506102ad6105a5366004613bc2565b61193f565b3480156105b657600080fd5b506103256105c5366004613ba5565b61ffff166000908152600c602052604090205490565b3480156105e757600080fd5b506000546301000000900460ff166104d6565b34801561060657600080fd5b506002546001600160a01b03166103fc565b34801561062457600080fd5b50610638610633366004613a3e565b611b83565b6040516102eb9190815160ff16815260208083015190820152604080830151908201526060918201519181019190915260800190565b34801561067a57600080fd5b506102ad61068936600461389a565b611cb4565b34801561069a57600080fd5b506005546001600160a01b03166103fc565b3480156106b857600080fd5b506001546001600160a01b03166103fc565b3480156106d657600080fd5b506103256106e5366004613c49565b611d3b565b3480156106f657600080fd5b506102ad610705366004613abd565b611e1b565b34801561071657600080fd5b506102ad6107253660046137da565b611ed9565b34801561073657600080fd5b5060005460405161ffff90911681526020016102eb565b34801561075957600080fd5b5060005462010000900460ff166104d6565b34801561077757600080fd5b5061078b610786366004613c67565b611fa5565b6040516102eb9190613d25565b3480156107a457600080fd5b506102ad6107b3366004613ba5565b612050565b3480156107c457600080fd5b50600054600160201b90046001600160a01b03166103fc565b3480156107e957600080fd5b506103256107f8366004613946565b6120c7565b34801561080957600080fd5b506006546001600160a01b03166103fc565b34801561082757600080fd5b506102ad6108363660046137da565b612161565b34801561084757600080fd5b50610325610856366004613946565b61221d565b34801561086757600080fd5b50610870612302565b6040516102eb9190613d38565b34801561088957600080fd5b506004546001600160a01b03166103fc565b3480156108a757600080fd5b506102ad6108b63660046137da565b612367565b3480156108c757600080fd5b5061078b604051806040016040528060058152602001640302e322e360dc1b81525081565b3480156108f857600080fd5b506102ad610907366004613d85565b612456565b3361091f6001546001600160a01b031690565b6001600160a01b03161461094e5760405162461bcd60e51b815260040161094590613dc6565b60405180910390fd5b818061ffff1661096160005461ffff1690565b61ffff16146109825760405162461bcd60e51b815260040161094590613df4565b6001600160a01b0382166109c85760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b2103a37b5b2b760991b6044820152606401610945565b6109d18261251d565b505050565b60006109ea6004546001600160a01b031690565b9050336001600160a01b03821614610a445760405162461bcd60e51b815260206004820152601b60248201527f63616c6c6572206d7573742062652070656e64696e674f776e657200000000006044820152606401610945565b6000610a586001546001600160a01b031690565b600180546001600160a01b0319166001600160a01b0385161790559050610a7f60006126c2565b816001600160a01b0316816001600160a01b03167f0d18b5fd22306e373229b9439188228edca81207d1667f604daf6cef8aa3ee6760405160405180910390a35050565b6000610acd6126e4565b6000546301000000900460ff1615610b1b5760405162461bcd60e51b81526020600482015260116024820152701c995b185e595c881a5cc81c185d5cd959607a1b6044820152606401610945565b6000610b2f6005546001600160a01b031690565b6001600160a01b0316631a90a2196040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b909190613e19565b9050803414610bd65760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742076616c756560701b6044820152606401610945565b6000610be18961273d565b9050610bf6610bf08983610e36565b82610e70565b9750610c0289896127df565b9750610c4b6040518060c001604052808b6001600160a01b031681526020018360ff1681526020018a81526020018981526020018861ffff168152602001878152508584612815565b92505050610c596001600f55565b9695505050505050565b33610c766001546001600160a01b031690565b6001600160a01b031614610c9c5760405162461bcd60e51b815260040161094590613dc6565b818061ffff16610caf60005461ffff1690565b61ffff1614610cd05760405162461bcd60e51b815260040161094590613df4565b6000805463ff0000001916630100000084151502179055505050565b33610cff6001546001600160a01b031690565b6001600160a01b031614610d255760405162461bcd60e51b815260040161094590613dc6565b818061ffff16610d3860005461ffff1690565b61ffff1614610d595760405162461bcd60e51b815260040161094590613df4565b6001600160a01b038216610dbf5760405162461bcd60e51b815260206004820152602760248201527f6e6577466565526563697069656e742063616e6e6f7420657175616c206164646044820152667265737328302960c81b6064820152608401610945565b6000610dd36003546001600160a01b031690565b600380546001600160a01b0319166001600160a01b0386161790559050826001600160a01b0316816001600160a01b03167faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d360405160405180910390a350505050565b600060088260ff161115610e6757610e4f600883613e48565b610e5a90600a613f45565b610e649084613f54565b92505b50815b92915050565b600060088260ff161115610e6757610e89600883613e48565b610e9490600a613f45565b610e649084613f76565b600080546301000000900460ff1615610eed5760405162461bcd60e51b81526020600482015260116024820152701c995b185e595c881a5cc81c185d5cd959607a1b6044820152606401610945565b60005462010000900460ff16610f455760405162461bcd60e51b815260206004820181905260248201527f574554482066756e6374696f6e616c697479206e6f7420737570706f727465646044820152606401610945565b6000610f596005546001600160a01b031690565b6001600160a01b0316631a90a2196040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fba9190613e19565b90508034116110005760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742076616c756560701b6044820152606401610945565b600061100c8234613f8d565b9050600061102561101e836012610e36565b6012610e70565b61102f9083613f8d565b9050801561106657604051339082156108fc029083906000818181858888f19350505050158015611064573d6000803e3d6000fd5b505b60006110728284613f8d565b905060006110906000546001600160a01b03600160201b9091041690565b9050806001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b1580156110cd57600080fd5b505af11580156110e1573d6000803e3d6000fd5b505050505061112e6040518060c00160405280836001600160a01b03168152602001601260ff1681526020018481526020018c81526020018b61ffff1681526020018a8152508887612815565b9a9950505050505050505050565b60008061114a836021612b3d565b90506000611159846041612b9b565b905061116860005461ffff1690565b61ffff168161ffff1614611249576006546001600160a01b0316604051630ff8f14360e11b815261ffff83166004820152602481018490526001600160a01b039190911690631ff1e28690604401602060405180830381865afa1580156111d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f79190613fa0565b92506001600160a01b0383166112445760405162461bcd60e51b81526020600482015260126024820152711d1bdad95b881b9bdd08185d1d195cdd195960721b6044820152606401610945565b611255565b61125282612bf8565b92505b5050919050565b3361126f6001546001600160a01b031690565b6001600160a01b0316146112955760405162461bcd60e51b815260040161094590613dc6565b818061ffff166112a860005461ffff1690565b61ffff16146112c95760405162461bcd60e51b815260040161094590613df4565b600082116113115760405162461bcd60e51b81526020600482015260156024820152740707265636973696f6e206d757374206265203e203605c1b6044820152606401610945565b6109d182600755565b600080600061135e85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612c4c92505050565b925092509250600061136f84611b83565b905060006113808260600151612bf8565b9050600061139760005460ff620100009091041690565b90506001600160a01b03821633036113bf576113b584838784612f41565b5050505050505050565b60006113ca8561273d565b90506113da846020015182610e70565b6020850152600054600160201b90046001600160a01b03166001600160a01b0316856001600160a01b0316036114255761141a868486602001518561306b565b505050505050505050565b6040840151156115ed5761143d846040015182610e70565b6040850152600061144d8661221d565b9050808560400151111561146357604085018190525b6000611473878760400151611d3b565b905080156115af57803410156114cb5760405162461bcd60e51b815260206004820181905260248201527f696e73756666696369656e74206e617469766520617373657420616d6f756e746044820152606401610945565b60006114d78234613f8d565b9050801561150e57604051339082156108fc029083906000818181858888f1935050505015801561150c573d6000803e3d6000fd5b505b6040516001600160a01b0387169083156108fc029084906000818181858888f19350505050158015611544573d6000803e3d6000fd5b50876001600160a01b0316336001600160a01b0316876001600160a01b03167f764f0dc063c06f32d89a3f3af80c0db4be8a090901f589a478b447e0a51f09f18a60400151866040516115a1929190918252602082015260400190565b60405180910390a4506115ea565b6000604087015234156115ea5760405133903480156108fc02916000818181858888f193505050501580156115e8573d6000803e3d6000fd5b505b50505b6000846040015185602001516116039190613fbd565b9050801561162757611627866116216003546001600160a01b031690565b836131e1565b61163b8685611636848b613f8d565b6131e1565b50505050505050505050565b6001600160a01b0382166000908152600a6020526040812054806000036116a45760405162461bcd60e51b81526020600482015260116024820152701cddd85c081c985d19481b9bdd081cd95d607a1b6044820152606401610945565b6008546116b19082613f76565b60075461ffff87166000908152600c60205260409020546116d386600a613f45565b6116dd9190613f76565b6116e79190613f76565b6116f19190613f54565b95945050505050565b3361170d6001546001600160a01b031690565b6001600160a01b0316146117335760405162461bcd60e51b815260040161094590613dc6565b806117905760405162461bcd60e51b815260206004820152602760248201527f636f6e7472616374416464726573732063616e6e6f7420657175616c206279746044820152666573333228302960c81b6064820152608401610945565b61ffff8216158015906117ac575060005461ffff838116911614155b6118085760405162461bcd60e51b815260206004820152602760248201527f636861696e49645f2063616e6e6f7420657175616c2030206f7220746869732060448201526618da185a5b925960ca1b6064820152608401610945565b61ffff91909116600090815260096020526040902055565b5050565b336118376001546001600160a01b031690565b6001600160a01b0316148061186557503361185a6002546001600160a01b031690565b6001600160a01b0316145b6118815760405162461bcd60e51b815260040161094590613fd0565b60005461ffff1661ffff168261ffff16036118ce5760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b21031b430b4b760991b6044820152606401610945565b61ffff82166000908152600960205260409020546119275760405162461bcd60e51b815260206004820152601660248201527518dbdb9d1c9858dd08191bd95cdb89dd08195e1a5cdd60521b6044820152606401610945565b61ffff919091166000908152600c6020526040902055565b336119526001546001600160a01b031690565b6001600160a01b031614806119805750336119756002546001600160a01b031690565b6001600160a01b0316145b61199c5760405162461bcd60e51b815260040161094590613fd0565b828061ffff166119af60005461ffff1690565b61ffff16146119d05760405162461bcd60e51b815260040161094590613df4565b8180611a135760405162461bcd60e51b8152602060048201526012602482015271696e76616c69642061727261792073697a6560701b6044820152606401610945565b60005b81811015611b3b57611a49858583818110611a3357611a33614011565b6104b89260206040909202019081019150613946565b611a655760405162461bcd60e51b815260040161094590614027565b6000858583818110611a7957611a79614011565b9050604002016020013511611ad05760405162461bcd60e51b815260206004820152601960248201527f737761702072617465206d757374206265206e6f6e7a65726f000000000000006044820152606401610945565b611b33858583818110611ae557611ae5614011565b611afb9260206040909202019081019150613946565b868684818110611b0d57611b0d614011565b905060400201602001356001600160a01b039091166000908152600a6020526040902055565b600101611a16565b508383604051611b4c929190614053565b604051908190038120907f7abf49a6ebb116bc314846377cd82a3d2c8c1ea48149a652356009fc37100dd790600090a25050505050565b604080516080810182526000808252602082018190529181018290526060810182905290611bb18382613244565b60ff168252611bc1600182613fbd565b9050816000015160ff16600114611c0e5760405162461bcd60e51b81526020600482015260116024820152701a5b9d985b1a59081c185e5b1bd8591259607a1b6044820152606401610945565b611c1883826132a0565b602080840191909152611c2b9082613fbd565b9050611c3783826132a0565b6040830152611c47602082613fbd565b9050611c538382612b3d565b6060830152611c63602082613fbd565b905082518114611cae5760405162461bcd60e51b81526020600482015260166024820152750d2dcecc2d8d2c840dacae6e6c2ceca40d8cadccee8d60531b6044820152606401610945565b50919050565b33611cc76001546001600160a01b031690565b6001600160a01b031614611ced5760405162461bcd60e51b815260040161094590613dc6565b818061ffff16611d0060005461ffff1690565b61ffff1614611d215760405162461bcd60e51b815260040161094590613df4565b6000805462ff000019166201000084151502179055505050565b600080611d478461273d565b90506000611d6d611d686000546001600160a01b03600160201b9091041690565b61273d565b90508060ff168260ff161115611dca57611d878183613e48565b611d9290600a613f45565b611d9b866120c7565b611da59190613f76565b84611daf60075490565b611db99190613f76565b611dc39190613f54565b9250611e13565b611dd3856120c7565b611ddd8383613e48565b611de890600a613f45565b85611df260075490565b611dfc9190613f76565b611e069190613f76565b611e109190613f54565b92505b505092915050565b33611e2e6001546001600160a01b031690565b6001600160a01b031614611e545760405162461bcd60e51b815260040161094590613dc6565b818061ffff16611e6760005461ffff1690565b61ffff1614611e885760405162461bcd60e51b815260040161094590613df4565b60008211611ed05760405162461bcd60e51b81526020600482015260156024820152740707265636973696f6e206d757374206265203e203605c1b6044820152606401610945565b6109d182600855565b33611eec6001546001600160a01b031690565b6001600160a01b031614611f125760405162461bcd60e51b815260040161094590613dc6565b818061ffff16611f2560005461ffff1690565b61ffff1614611f465760405162461bcd60e51b815260040161094590613df4565b6001600160a01b038216611f9c5760405162461bcd60e51b815260206004820181905260248201527f6e65774f776e65722063616e6e6f7420657175616c20616464726573732830296044820152606401610945565b6109d1826126c2565b6060816000015160ff16600114611ff25760405162461bcd60e51b81526020600482015260116024820152701a5b9d985b1a59081c185e5b1bd8591259607a1b6044820152606401610945565b81516020808401516040808601516060870151915161203a95949192910160f89490941b6001600160f81b031916845260018401929092526021830152604182015260610190565b6040516020818303038152906040529050919050565b336120636001546001600160a01b031690565b6001600160a01b0316146120895760405162461bcd60e51b815260040161094590613dc6565b808061ffff1661209c60005461ffff1690565b61ffff16146120bd5760405162461bcd60e51b815260040161094590613df4565b61182060006126c2565b600080546001600160a01b03600160201b90910481168252600a60205260408083205491841683528220546000821180156121025750600081115b6121425760405162461bcd60e51b81526020600482015260116024820152701cddd85c081c985d19481b9bdd081cd95d607a1b6044820152606401610945565b808261214d60075490565b6121579190613f76565b6112529190613f54565b336121746001546001600160a01b031690565b6001600160a01b03161461219a5760405162461bcd60e51b815260040161094590613dc6565b818061ffff166121ad60005461ffff1690565b61ffff16146121ce5760405162461bcd60e51b815260040161094590613df4565b6001600160a01b0382166122145760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b2103a37b5b2b760991b6044820152606401610945565b6109d1826132f5565b6000806122298361273d565b9050600061224a611d686000546001600160a01b03600160201b9091041690565b90508060ff168260ff1611156122b9576007546122678284613e48565b61227290600a613f45565b61227b866120c7565b6001600160a01b0387166000908152600b602052604090205461229e9190613f76565b6122a89190613f76565b6122b29190613f54565b9250611255565b6007546122c68383613e48565b6122d190600a613f45565b6122db9190613f76565b6122e4856120c7565b6001600160a01b0386166000908152600b602052604090205461214d565b60606000600e0180548060200260200160405190810160405280929190818152602001828054801561235d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161233f575b5050505050905090565b3361237a6001546001600160a01b031690565b6001600160a01b0316146123a05760405162461bcd60e51b815260040161094590613dc6565b818061ffff166123b360005461ffff1690565b61ffff16146123d45760405162461bcd60e51b815260040161094590613df4565b6001600160a01b0382166124365760405162461bcd60e51b8152602060048201526024808201527f6e6577417373697374616e742063616e6e6f7420657175616c206164647265736044820152637328302960e01b6064820152608401610945565b600280546001600160a01b0319166001600160a01b038416179055505050565b336124696001546001600160a01b031690565b6001600160a01b03161461248f5760405162461bcd60e51b815260040161094590613dc6565b828061ffff166124a260005461ffff1690565b61ffff16146124c35760405162461bcd60e51b815260040161094590613df4565b6001600160a01b0383166000908152600d602052604090205460ff166124fb5760405162461bcd60e51b815260040161094590614027565b6001600160a01b0383166000908152600b602052604090208290555b50505050565b6001600160a01b0381166000908152600d602052604090205460ff1661257c5760405162461bcd60e51b81526020600482015260146024820152731d1bdad95b881b9bdd081c9959da5cdd195c995960621b6044820152606401610945565b6001600160a01b0381166000908152600d60209081526040808320805460ff19169055600a8252808320839055600b9091528120819055600e54905b8181101561260257826001600160a01b03166000600e0182815481106125e0576125e0614011565b6000918252602090912001546001600160a01b031614612602576001016125b8565b8181146109d157600182111561268a57600e61261f600184613f8d565b8154811061262f5761262f614011565b600091825260209091200154600e80546001600160a01b03909216918390811061265b5761265b614011565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b600e80548061269b5761269b61409e565b600082815260209020810160001990810180546001600160a01b0319169055019055505050565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6002600f54036127365760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610945565b6002600f55565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b179052905160009182916001600160a01b03851691612780916140b4565b600060405180830381855afa9150503d80600081146127bb576040519150601f19603f3d011682016040523d82523d6000602084013e6127c0565b606091505b50915050808060200190518101906127d891906140e0565b9392505050565b6000806127eb846133c4565b90506127f984333086613470565b80612803856133c4565b61280d9190613f8d565b949350505050565b82516001600160a01b03166000908152600d602052604081205460ff1661284e5760405162461bcd60e51b815260040161094590614027565b60a08401516128ab5760405162461bcd60e51b8152602060048201526024808201527f746172676574526563697069656e742063616e6e6f74206265206279746573336044820152633228302960e01b6064820152608401610945565b60006128bf85604001518660200151610e36565b9050600081116129115760405162461bcd60e51b815260206004820152601d60248201527f6e6f726d616c697a656420616d6f756e74206d757374206265203e20300000006044820152606401610945565b600061292586606001518760200151610e36565b905085606001516000148061293a5750600081115b6129865760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420746f4e6174697665546f6b656e416d6f756e7400000000006044820152606401610945565b608086015161ffff16600090815260096020526040902054806129e35760405162461bcd60e51b81526020600482015260156024820152741d185c99d95d081b9bdd081c9959da5cdd195c9959605a1b6044820152606401610945565b6000612a096129ff89608001518a600001518b60200151611647565b8960200151610e36565b9050612a158382613fbd565b8411612a595760405162461bcd60e51b81526020600482015260136024820152721a5b9cdd59999a58da595b9d08185b5bdd5b9d606a1b6044820152606401610945565b6000612a8c6040518060800160405280600160ff1681526020018481526020018681526020018b60a00151815250611fa5565b90506000612aa26006546001600160a01b031690565b9050612ab78a60000151828c604001516134a8565b806001600160a01b031663c5a5ebda898c600001518d604001518e60800151898f896040518863ffffffff1660e01b8152600401612afa969594939291906140fd565b60206040518083038185885af1158015612b18573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061112e9190614163565b6000612b4a826020613fbd565b83511015612b925760405162461bcd60e51b8152602060048201526015602482015274746f427974657333325f6f75744f66426f756e647360581b6044820152606401610945565b50016020015190565b6000612ba8826002613fbd565b83511015612bef5760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b6044820152606401610945565b50016002015190565b60006001600160a01b0319821615612c485760405162461bcd60e51b8152602060048201526013602482015272696e76616c69642045564d206164647265737360681b6044820152606401610945565b5090565b60606000806000612c656005546001600160a01b031690565b6001600160a01b031663a9e11893866040518263ffffffff1660e01b8152600401612c909190613d25565b600060405180830381865afa158015612cad573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612cd591908101906142a2565b90506000612ce68260e0015161113c565b9050612d0a816001600160a01b03166000908152600d602052604090205460ff1690565b612d4d5760405162461bcd60e51b81526020600482015260146024820152731d1bdad95b881b9bdd081c9959da5cdd195c995960621b6044820152606401610945565b6000612d58826133c4565b90506000612d6e6006546001600160a01b031690565b90506000816001600160a01b031663c3f511c18a6040518263ffffffff1660e01b8152600401612d9e9190613d25565b6000604051808303816000875af1158015612dbd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612de591908101906143c6565b9050600083612df3866133c4565b612dfd9190613f8d565b90506000836001600160a01b031663ea63738d846040518263ffffffff1660e01b8152600401612e2d9190613d25565b600060405180830381865afa158015612e4a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e7291908101906143fa565b9050612e92876060015161ffff1660009081526009602052604090205490565b8160c0015114612ee45760405162461bcd60e51b815260206004820152601760248201527f636f6e7472616374206e6f7420726567697374657265640000000000000000006044820152606401610945565b8660a001516001600160401b03168760800151886060015161ffff167fcaf280c8cfeba144da67230d9b009c8f868a75bac9a528fa0474be1ba317c16960405160405180910390a460e001519a9099509397509295505050505050565b3415612f9b5760405162461bcd60e51b815260206004820152602360248201527f726563697069656e742063616e6e6f742073776170206e61746976652061737360448201526265747360e81b6064820152608401610945565b6000546001600160a01b03600160201b909104811690851681148015612fbe5750815b1561305957604051632e1a7d4d60e01b8152600481018490526001600160a01b03821690632e1a7d4d90602401600060405180830381600087803b15801561300557600080fd5b505af1158015613019573d6000803e3d6000fd5b50506040516001600160a01b038716925085156108fc02915085906000818181858888f19350505050158015613053573d6000803e3d6000fd5b50613064565b6130648585856131e1565b5050505050565b34156130ae5760405162461bcd60e51b815260206004820152601260248201527176616c7565206d757374206265207a65726f60701b6044820152606401610945565b80156131a157600054604051632e1a7d4d60e01b815260048101869052600160201b9091046001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561310057600080fd5b505af1158015613114573d6000803e3d6000fd5b50505050826001600160a01b03166108fc83866131319190613f8d565b6040518115909202916000818181858888f19350505050158015613159573d6000803e3d6000fd5b50811561319c576003546040516001600160a01b039091169083156108fc029084906000818181858888f1935050505015801561319a573d6000803e3d6000fd5b505b612517565b600054600160201b90046001600160a01b03166131c381856116368689613f8d565b821561306457613064816131df6003546001600160a01b031690565b855b6040516001600160a01b0383166024820152604481018290526109d190849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526135bd565b6000613251826001613fbd565b835110156132975760405162461bcd60e51b8152602060048201526013602482015272746f55696e74385f6f75744f66426f756e647360681b6044820152606401610945565b50016001015190565b60006132ad826020613fbd565b83511015612b925760405162461bcd60e51b8152602060048201526015602482015274746f55696e743235365f6f75744f66426f756e647360581b6044820152606401610945565b6001600160a01b0381166000908152600d602052604090205460ff161561335e5760405162461bcd60e51b815260206004820152601860248201527f746f6b656e20616c7265616479207265676973746572656400000000000000006044820152606401610945565b6001600160a01b03166000818152600d60205260408120805460ff19166001908117909155600e805491820181559091527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd0180546001600160a01b0319169091179055565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b179052905160009182916001600160a01b03851691613418916140b4565b600060405180830381855afa9150503d8060008114613453576040519150601f19603f3d011682016040523d82523d6000602084013e613458565b606091505b50915050808060200190518101906127d89190613e19565b6040516001600160a01b03808516602483015283166044820152606481018290526125179085906323b872dd60e01b9060840161320d565b8015806135225750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156134fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135209190613e19565b155b61358d5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610945565b6040516001600160a01b0383166024820152604481018290526109d190849063095ea7b360e01b9060640161320d565b6000613612826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661368f9092919063ffffffff16565b8051909150156109d1578080602001905181019061363091906144c2565b6109d15760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610945565b606061280d848460008585600080866001600160a01b031685876040516136b691906140b4565b60006040518083038185875af1925050503d80600081146136f3576040519150601f19603f3d011682016040523d82523d6000602084013e6136f8565b606091505b509150915061370987838387613714565b979650505050505050565b6060831561378357825160000361377c576001600160a01b0385163b61377c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610945565b508161280d565b61280d83838151156137985781518083602001fd5b8060405162461bcd60e51b81526004016109459190613d25565b61ffff811681146137c257600080fd5b50565b6001600160a01b03811681146137c257600080fd5b600080604083850312156137ed57600080fd5b82356137f8816137b2565b91506020830135613808816137c5565b809150509250929050565b63ffffffff811681146137c257600080fd5b60008060008060008060c0878903121561383e57600080fd5b8635613849816137c5565b955060208701359450604087013593506060870135613867816137b2565b92506080870135915060a087013561387e81613813565b809150509295509295509295565b80151581146137c257600080fd5b600080604083850312156138ad57600080fd5b82356138b8816137b2565b915060208301356138088161388c565b60ff811681146137c257600080fd5b600080604083850312156138ea57600080fd5b823591506020830135613808816138c8565b6000806000806080858703121561391257600080fd5b843593506020850135613924816137b2565b925060408501359150606085013561393b81613813565b939692955090935050565b60006020828403121561395857600080fd5b81356127d8816137c5565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b038111828210171561399b5761399b613963565b60405290565b60405161016081016001600160401b038111828210171561399b5761399b613963565b60405161010081016001600160401b038111828210171561399b5761399b613963565b604051601f8201601f191681016001600160401b0381118282101715613a0f57613a0f613963565b604052919050565b60006001600160401b03821115613a3057613a30613963565b50601f01601f191660200190565b600060208284031215613a5057600080fd5b81356001600160401b03811115613a6657600080fd5b8201601f81018413613a7757600080fd5b8035613a8a613a8582613a17565b6139e7565b818152856020838501011115613a9f57600080fd5b81602084016020830137600091810160200191909152949350505050565b60008060408385031215613ad057600080fd5b8235613adb816137b2565b946020939093013593505050565b60008060208385031215613afc57600080fd5b82356001600160401b0380821115613b1357600080fd5b818501915085601f830112613b2757600080fd5b813581811115613b3657600080fd5b866020828501011115613b4857600080fd5b60209290920196919550909350505050565b600080600060608486031215613b6f57600080fd5b8335613b7a816137b2565b92506020840135613b8a816137c5565b91506040840135613b9a816138c8565b809150509250925092565b600060208284031215613bb757600080fd5b81356127d8816137b2565b600080600060408486031215613bd757600080fd5b8335613be2816137b2565b925060208401356001600160401b0380821115613bfe57600080fd5b818601915086601f830112613c1257600080fd5b813581811115613c2157600080fd5b8760208260061b8501011115613c3657600080fd5b6020830194508093505050509250925092565b60008060408385031215613c5c57600080fd5b8235613adb816137c5565b600060808284031215613c7957600080fd5b604051608081018181106001600160401b0382111715613c9b57613c9b613963565b6040528235613ca9816138c8565b808252506020830135602082015260408301356040820152606083013560608201528091505092915050565b60005b83811015613cf0578181015183820152602001613cd8565b50506000910152565b60008151808452613d11816020860160208601613cd5565b601f01601f19169290920160200192915050565b6020815260006127d86020830184613cf9565b6020808252825182820181905260009190848201906040850190845b81811015613d795783516001600160a01b031683529284019291840191600101613d54565b50909695505050505050565b600080600060608486031215613d9a57600080fd5b8335613da5816137b2565b92506020840135613db5816137c5565b929592945050506040919091013590565b60208082526014908201527331b0b63632b9103737ba103a34329037bbb732b960611b604082015260600190565b6020808252600b908201526a3bb937b7339031b430b4b760a91b604082015260600190565b600060208284031215613e2b57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b60ff8281168282160390811115610e6a57610e6a613e32565b600181815b80851115613e9c578160001904821115613e8257613e82613e32565b80851615613e8f57918102915b93841c9390800290613e66565b509250929050565b600082613eb357506001610e6a565b81613ec057506000610e6a565b8160018114613ed65760028114613ee057613efc565b6001915050610e6a565b60ff841115613ef157613ef1613e32565b50506001821b610e6a565b5060208310610133831016604e8410600b8410161715613f1f575081810a610e6a565b613f298383613e61565b8060001904821115613f3d57613f3d613e32565b029392505050565b60006127d860ff841683613ea4565b600082613f7157634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417610e6a57610e6a613e32565b81810381811115610e6a57610e6a613e32565b600060208284031215613fb257600080fd5b81516127d8816137c5565b80820180821115610e6a57610e6a613e32565b60208082526021908201527f63616c6c6572206e6f7420746865206f776e6572206f7220617373697374616e6040820152601d60fa1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b6020808252601290820152711d1bdad95b881b9bdd081858d8d95c1d195960721b604082015260600190565b60008184825b8581101561409357813561406c816137c5565b6001600160a01b031683526020828101359084015260409283019290910190600101614059565b509095945050505050565b634e487b7160e01b600052603160045260246000fd5b600082516140c6818460208701613cd5565b9190910192915050565b80516140db816138c8565b919050565b6000602082840312156140f257600080fd5b81516127d8816138c8565b60018060a01b038716815285602082015261ffff8516604082015283606082015263ffffffff8316608082015260c060a0820152600061414060c0830184613cf9565b98975050505050505050565b80516001600160401b03811681146140db57600080fd5b60006020828403121561417557600080fd5b6127d88261414c565b80516140db81613813565b80516140db816137b2565b600082601f8301126141a557600080fd5b81516141b3613a8582613a17565b8181528460208386010111156141c857600080fd5b61280d826020830160208701613cd5565b600082601f8301126141ea57600080fd5b815160206001600160401b0382111561420557614205613963565b614213818360051b016139e7565b82815260079290921b8401810191818101908684111561423257600080fd5b8286015b84811015614297576080818903121561424f5760008081fd5b614257613979565b815181528482015185820152604080830151614272816138c8565b90820152606082810151614285816138c8565b90820152835291830191608001614236565b509695505050505050565b6000602082840312156142b457600080fd5b81516001600160401b03808211156142cb57600080fd5b9083019061016082860312156142e057600080fd5b6142e86139a1565b6142f1836140d0565b81526142ff6020840161417e565b60208201526143106040840161417e565b604082015261432160608401614189565b60608201526080830151608082015261433c60a0840161414c565b60a082015261434d60c084016140d0565b60c082015260e08301518281111561436457600080fd5b61437087828601614194565b60e08301525061010061438481850161417e565b90820152610120838101518381111561439c57600080fd5b6143a8888287016141d9565b91830191909152506101409283015192810192909252509392505050565b6000602082840312156143d857600080fd5b81516001600160401b038111156143ee57600080fd5b61280d84828501614194565b60006020828403121561440c57600080fd5b81516001600160401b038082111561442357600080fd5b90830190610100828603121561443857600080fd5b6144406139c4565b614449836140d0565b8152602083015160208201526040830151604082015261446b60608401614189565b60608201526080830151608082015261448660a08401614189565b60a082015260c083015160c082015260e0830151828111156144a757600080fd5b6144b387828601614194565b60e08301525095945050505050565b6000602082840312156144d457600080fd5b81516127d88161388c56fea26469706673582212204380a2c16f3d3a94e16ceec8dd417389a415486e9286774f1ba51d1e17ea374064736f6c63430008110033000000000000000000000000796dff6d74f3e27060b71255fe517bfb23c93eed000000000000000000000000471ece3750da237f93b8e339c536989b8978a43800000000000000000000000053cd7442fee1ad9edfd43fe469efa26721b969ed000000000000000000000000f285bd23217ae02779e11b7e822e603f31bbe6690000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106102815760003560e01c80636805b84b1161014f5780639fe089ad116100c1578063cd601c781161007a578063cd601c781461083b578063df160d761461085b578063e30c39781461087d578063ea1d2e4a1461089b578063ffa1ad74146108bb578063fff982a8146108ec57600080fd5b80639fe089ad1461076b578063a2f32c8f14610798578063ad5c4648146107b8578063b5419523146107dd578063c6328a46146107fd578063c9c22f9f1461081b57600080fd5b80638da5cb5b116101135780638da5cb5b146106ac5780638e151dd1146106ca57806390a1afaa146106ea57806394cc743d1461070a5780639a8a05921461072a5780639cf278cd1461074d57600080fd5b80636805b84b146105db57806368aa9ef4146105fa5780637c9dec7a146106185780638335572f1461066e57806384acd1bb1461068e57600080fd5b80632def3e16116101f3578063415828bf116101ac578063415828bf14610517578063469048401461052c57806351e2d7b51461054a5780635b9cf0e11461056a578063640d946b1461058a57806366775a6b146105aa57600080fd5b80632def3e16146104145780632efe4f42146104345780632f25e25f1461046a57806339ba66111461047d5780633b6e750f1461049d5780633d62cca0146104e657600080fd5b8063203c509511610245578063203c50951461033357806327105ab91461035357806328ded8e31461037357806329ac8361146103935780632ca8008c146103a65780632d77e8fe146103dc57600080fd5b8063016aa2051461028d578063038c0b66146102af5780631019d654146102c45780631a282195146102f45780631acdab4b1461031457600080fd5b3661028857005b600080fd5b34801561029957600080fd5b506102ad6102a83660046137da565b61090c565b005b3480156102bb57600080fd5b506102ad6109d6565b6102d76102d2366004613825565b610ac3565b6040516001600160401b0390911681526020015b60405180910390f35b34801561030057600080fd5b506102ad61030f36600461389a565b610c63565b34801561032057600080fd5b506007545b6040519081526020016102eb565b34801561033f57600080fd5b506102ad61034e3660046137da565b610cec565b34801561035f57600080fd5b5061032561036e3660046138d7565b610e36565b34801561037f57600080fd5b5061032561038e3660046138d7565b610e70565b6102d76103a13660046138fc565b610e9e565b3480156103b257600080fd5b506103256103c1366004613946565b6001600160a01b03166000908152600a602052604090205490565b3480156103e857600080fd5b506103fc6103f7366004613a3e565b61113c565b6040516001600160a01b0390911681526020016102eb565b34801561042057600080fd5b506102ad61042f366004613abd565b61125c565b34801561044057600080fd5b5061032561044f366004613946565b6001600160a01b03166000908152600b602052604090205490565b6102ad610478366004613ae9565b61131a565b34801561048957600080fd5b50610325610498366004613b5a565b611647565b3480156104a957600080fd5b506104d66104b8366004613946565b6001600160a01b03166000908152600d602052604090205460ff1690565b60405190151581526020016102eb565b3480156104f257600080fd5b50610325610501366004613ba5565b61ffff1660009081526009602052604090205490565b34801561052357600080fd5b50600854610325565b34801561053857600080fd5b506003546001600160a01b03166103fc565b34801561055657600080fd5b506102ad610565366004613abd565b6116fa565b34801561057657600080fd5b506102ad610585366004613abd565b611824565b34801561059657600080fd5b506102ad6105a5366004613bc2565b61193f565b3480156105b657600080fd5b506103256105c5366004613ba5565b61ffff166000908152600c602052604090205490565b3480156105e757600080fd5b506000546301000000900460ff166104d6565b34801561060657600080fd5b506002546001600160a01b03166103fc565b34801561062457600080fd5b50610638610633366004613a3e565b611b83565b6040516102eb9190815160ff16815260208083015190820152604080830151908201526060918201519181019190915260800190565b34801561067a57600080fd5b506102ad61068936600461389a565b611cb4565b34801561069a57600080fd5b506005546001600160a01b03166103fc565b3480156106b857600080fd5b506001546001600160a01b03166103fc565b3480156106d657600080fd5b506103256106e5366004613c49565b611d3b565b3480156106f657600080fd5b506102ad610705366004613abd565b611e1b565b34801561071657600080fd5b506102ad6107253660046137da565b611ed9565b34801561073657600080fd5b5060005460405161ffff90911681526020016102eb565b34801561075957600080fd5b5060005462010000900460ff166104d6565b34801561077757600080fd5b5061078b610786366004613c67565b611fa5565b6040516102eb9190613d25565b3480156107a457600080fd5b506102ad6107b3366004613ba5565b612050565b3480156107c457600080fd5b50600054600160201b90046001600160a01b03166103fc565b3480156107e957600080fd5b506103256107f8366004613946565b6120c7565b34801561080957600080fd5b506006546001600160a01b03166103fc565b34801561082757600080fd5b506102ad6108363660046137da565b612161565b34801561084757600080fd5b50610325610856366004613946565b61221d565b34801561086757600080fd5b50610870612302565b6040516102eb9190613d38565b34801561088957600080fd5b506004546001600160a01b03166103fc565b3480156108a757600080fd5b506102ad6108b63660046137da565b612367565b3480156108c757600080fd5b5061078b604051806040016040528060058152602001640302e322e360dc1b81525081565b3480156108f857600080fd5b506102ad610907366004613d85565b612456565b3361091f6001546001600160a01b031690565b6001600160a01b03161461094e5760405162461bcd60e51b815260040161094590613dc6565b60405180910390fd5b818061ffff1661096160005461ffff1690565b61ffff16146109825760405162461bcd60e51b815260040161094590613df4565b6001600160a01b0382166109c85760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b2103a37b5b2b760991b6044820152606401610945565b6109d18261251d565b505050565b60006109ea6004546001600160a01b031690565b9050336001600160a01b03821614610a445760405162461bcd60e51b815260206004820152601b60248201527f63616c6c6572206d7573742062652070656e64696e674f776e657200000000006044820152606401610945565b6000610a586001546001600160a01b031690565b600180546001600160a01b0319166001600160a01b0385161790559050610a7f60006126c2565b816001600160a01b0316816001600160a01b03167f0d18b5fd22306e373229b9439188228edca81207d1667f604daf6cef8aa3ee6760405160405180910390a35050565b6000610acd6126e4565b6000546301000000900460ff1615610b1b5760405162461bcd60e51b81526020600482015260116024820152701c995b185e595c881a5cc81c185d5cd959607a1b6044820152606401610945565b6000610b2f6005546001600160a01b031690565b6001600160a01b0316631a90a2196040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b6c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b909190613e19565b9050803414610bd65760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742076616c756560701b6044820152606401610945565b6000610be18961273d565b9050610bf6610bf08983610e36565b82610e70565b9750610c0289896127df565b9750610c4b6040518060c001604052808b6001600160a01b031681526020018360ff1681526020018a81526020018981526020018861ffff168152602001878152508584612815565b92505050610c596001600f55565b9695505050505050565b33610c766001546001600160a01b031690565b6001600160a01b031614610c9c5760405162461bcd60e51b815260040161094590613dc6565b818061ffff16610caf60005461ffff1690565b61ffff1614610cd05760405162461bcd60e51b815260040161094590613df4565b6000805463ff0000001916630100000084151502179055505050565b33610cff6001546001600160a01b031690565b6001600160a01b031614610d255760405162461bcd60e51b815260040161094590613dc6565b818061ffff16610d3860005461ffff1690565b61ffff1614610d595760405162461bcd60e51b815260040161094590613df4565b6001600160a01b038216610dbf5760405162461bcd60e51b815260206004820152602760248201527f6e6577466565526563697069656e742063616e6e6f7420657175616c206164646044820152667265737328302960c81b6064820152608401610945565b6000610dd36003546001600160a01b031690565b600380546001600160a01b0319166001600160a01b0386161790559050826001600160a01b0316816001600160a01b03167faaebcf1bfa00580e41d966056b48521fa9f202645c86d4ddf28113e617c1b1d360405160405180910390a350505050565b600060088260ff161115610e6757610e4f600883613e48565b610e5a90600a613f45565b610e649084613f54565b92505b50815b92915050565b600060088260ff161115610e6757610e89600883613e48565b610e9490600a613f45565b610e649084613f76565b600080546301000000900460ff1615610eed5760405162461bcd60e51b81526020600482015260116024820152701c995b185e595c881a5cc81c185d5cd959607a1b6044820152606401610945565b60005462010000900460ff16610f455760405162461bcd60e51b815260206004820181905260248201527f574554482066756e6374696f6e616c697479206e6f7420737570706f727465646044820152606401610945565b6000610f596005546001600160a01b031690565b6001600160a01b0316631a90a2196040518163ffffffff1660e01b8152600401602060405180830381865afa158015610f96573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fba9190613e19565b90508034116110005760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742076616c756560701b6044820152606401610945565b600061100c8234613f8d565b9050600061102561101e836012610e36565b6012610e70565b61102f9083613f8d565b9050801561106657604051339082156108fc029083906000818181858888f19350505050158015611064573d6000803e3d6000fd5b505b60006110728284613f8d565b905060006110906000546001600160a01b03600160201b9091041690565b9050806001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b1580156110cd57600080fd5b505af11580156110e1573d6000803e3d6000fd5b505050505061112e6040518060c00160405280836001600160a01b03168152602001601260ff1681526020018481526020018c81526020018b61ffff1681526020018a8152508887612815565b9a9950505050505050505050565b60008061114a836021612b3d565b90506000611159846041612b9b565b905061116860005461ffff1690565b61ffff168161ffff1614611249576006546001600160a01b0316604051630ff8f14360e11b815261ffff83166004820152602481018490526001600160a01b039190911690631ff1e28690604401602060405180830381865afa1580156111d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111f79190613fa0565b92506001600160a01b0383166112445760405162461bcd60e51b81526020600482015260126024820152711d1bdad95b881b9bdd08185d1d195cdd195960721b6044820152606401610945565b611255565b61125282612bf8565b92505b5050919050565b3361126f6001546001600160a01b031690565b6001600160a01b0316146112955760405162461bcd60e51b815260040161094590613dc6565b818061ffff166112a860005461ffff1690565b61ffff16146112c95760405162461bcd60e51b815260040161094590613df4565b600082116113115760405162461bcd60e51b81526020600482015260156024820152740707265636973696f6e206d757374206265203e203605c1b6044820152606401610945565b6109d182600755565b600080600061135e85858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612c4c92505050565b925092509250600061136f84611b83565b905060006113808260600151612bf8565b9050600061139760005460ff620100009091041690565b90506001600160a01b03821633036113bf576113b584838784612f41565b5050505050505050565b60006113ca8561273d565b90506113da846020015182610e70565b6020850152600054600160201b90046001600160a01b03166001600160a01b0316856001600160a01b0316036114255761141a868486602001518561306b565b505050505050505050565b6040840151156115ed5761143d846040015182610e70565b6040850152600061144d8661221d565b9050808560400151111561146357604085018190525b6000611473878760400151611d3b565b905080156115af57803410156114cb5760405162461bcd60e51b815260206004820181905260248201527f696e73756666696369656e74206e617469766520617373657420616d6f756e746044820152606401610945565b60006114d78234613f8d565b9050801561150e57604051339082156108fc029083906000818181858888f1935050505015801561150c573d6000803e3d6000fd5b505b6040516001600160a01b0387169083156108fc029084906000818181858888f19350505050158015611544573d6000803e3d6000fd5b50876001600160a01b0316336001600160a01b0316876001600160a01b03167f764f0dc063c06f32d89a3f3af80c0db4be8a090901f589a478b447e0a51f09f18a60400151866040516115a1929190918252602082015260400190565b60405180910390a4506115ea565b6000604087015234156115ea5760405133903480156108fc02916000818181858888f193505050501580156115e8573d6000803e3d6000fd5b505b50505b6000846040015185602001516116039190613fbd565b9050801561162757611627866116216003546001600160a01b031690565b836131e1565b61163b8685611636848b613f8d565b6131e1565b50505050505050505050565b6001600160a01b0382166000908152600a6020526040812054806000036116a45760405162461bcd60e51b81526020600482015260116024820152701cddd85c081c985d19481b9bdd081cd95d607a1b6044820152606401610945565b6008546116b19082613f76565b60075461ffff87166000908152600c60205260409020546116d386600a613f45565b6116dd9190613f76565b6116e79190613f76565b6116f19190613f54565b95945050505050565b3361170d6001546001600160a01b031690565b6001600160a01b0316146117335760405162461bcd60e51b815260040161094590613dc6565b806117905760405162461bcd60e51b815260206004820152602760248201527f636f6e7472616374416464726573732063616e6e6f7420657175616c206279746044820152666573333228302960c81b6064820152608401610945565b61ffff8216158015906117ac575060005461ffff838116911614155b6118085760405162461bcd60e51b815260206004820152602760248201527f636861696e49645f2063616e6e6f7420657175616c2030206f7220746869732060448201526618da185a5b925960ca1b6064820152608401610945565b61ffff91909116600090815260096020526040902055565b5050565b336118376001546001600160a01b031690565b6001600160a01b0316148061186557503361185a6002546001600160a01b031690565b6001600160a01b0316145b6118815760405162461bcd60e51b815260040161094590613fd0565b60005461ffff1661ffff168261ffff16036118ce5760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b21031b430b4b760991b6044820152606401610945565b61ffff82166000908152600960205260409020546119275760405162461bcd60e51b815260206004820152601660248201527518dbdb9d1c9858dd08191bd95cdb89dd08195e1a5cdd60521b6044820152606401610945565b61ffff919091166000908152600c6020526040902055565b336119526001546001600160a01b031690565b6001600160a01b031614806119805750336119756002546001600160a01b031690565b6001600160a01b0316145b61199c5760405162461bcd60e51b815260040161094590613fd0565b828061ffff166119af60005461ffff1690565b61ffff16146119d05760405162461bcd60e51b815260040161094590613df4565b8180611a135760405162461bcd60e51b8152602060048201526012602482015271696e76616c69642061727261792073697a6560701b6044820152606401610945565b60005b81811015611b3b57611a49858583818110611a3357611a33614011565b6104b89260206040909202019081019150613946565b611a655760405162461bcd60e51b815260040161094590614027565b6000858583818110611a7957611a79614011565b9050604002016020013511611ad05760405162461bcd60e51b815260206004820152601960248201527f737761702072617465206d757374206265206e6f6e7a65726f000000000000006044820152606401610945565b611b33858583818110611ae557611ae5614011565b611afb9260206040909202019081019150613946565b868684818110611b0d57611b0d614011565b905060400201602001356001600160a01b039091166000908152600a6020526040902055565b600101611a16565b508383604051611b4c929190614053565b604051908190038120907f7abf49a6ebb116bc314846377cd82a3d2c8c1ea48149a652356009fc37100dd790600090a25050505050565b604080516080810182526000808252602082018190529181018290526060810182905290611bb18382613244565b60ff168252611bc1600182613fbd565b9050816000015160ff16600114611c0e5760405162461bcd60e51b81526020600482015260116024820152701a5b9d985b1a59081c185e5b1bd8591259607a1b6044820152606401610945565b611c1883826132a0565b602080840191909152611c2b9082613fbd565b9050611c3783826132a0565b6040830152611c47602082613fbd565b9050611c538382612b3d565b6060830152611c63602082613fbd565b905082518114611cae5760405162461bcd60e51b81526020600482015260166024820152750d2dcecc2d8d2c840dacae6e6c2ceca40d8cadccee8d60531b6044820152606401610945565b50919050565b33611cc76001546001600160a01b031690565b6001600160a01b031614611ced5760405162461bcd60e51b815260040161094590613dc6565b818061ffff16611d0060005461ffff1690565b61ffff1614611d215760405162461bcd60e51b815260040161094590613df4565b6000805462ff000019166201000084151502179055505050565b600080611d478461273d565b90506000611d6d611d686000546001600160a01b03600160201b9091041690565b61273d565b90508060ff168260ff161115611dca57611d878183613e48565b611d9290600a613f45565b611d9b866120c7565b611da59190613f76565b84611daf60075490565b611db99190613f76565b611dc39190613f54565b9250611e13565b611dd3856120c7565b611ddd8383613e48565b611de890600a613f45565b85611df260075490565b611dfc9190613f76565b611e069190613f76565b611e109190613f54565b92505b505092915050565b33611e2e6001546001600160a01b031690565b6001600160a01b031614611e545760405162461bcd60e51b815260040161094590613dc6565b818061ffff16611e6760005461ffff1690565b61ffff1614611e885760405162461bcd60e51b815260040161094590613df4565b60008211611ed05760405162461bcd60e51b81526020600482015260156024820152740707265636973696f6e206d757374206265203e203605c1b6044820152606401610945565b6109d182600855565b33611eec6001546001600160a01b031690565b6001600160a01b031614611f125760405162461bcd60e51b815260040161094590613dc6565b818061ffff16611f2560005461ffff1690565b61ffff1614611f465760405162461bcd60e51b815260040161094590613df4565b6001600160a01b038216611f9c5760405162461bcd60e51b815260206004820181905260248201527f6e65774f776e65722063616e6e6f7420657175616c20616464726573732830296044820152606401610945565b6109d1826126c2565b6060816000015160ff16600114611ff25760405162461bcd60e51b81526020600482015260116024820152701a5b9d985b1a59081c185e5b1bd8591259607a1b6044820152606401610945565b81516020808401516040808601516060870151915161203a95949192910160f89490941b6001600160f81b031916845260018401929092526021830152604182015260610190565b6040516020818303038152906040529050919050565b336120636001546001600160a01b031690565b6001600160a01b0316146120895760405162461bcd60e51b815260040161094590613dc6565b808061ffff1661209c60005461ffff1690565b61ffff16146120bd5760405162461bcd60e51b815260040161094590613df4565b61182060006126c2565b600080546001600160a01b03600160201b90910481168252600a60205260408083205491841683528220546000821180156121025750600081115b6121425760405162461bcd60e51b81526020600482015260116024820152701cddd85c081c985d19481b9bdd081cd95d607a1b6044820152606401610945565b808261214d60075490565b6121579190613f76565b6112529190613f54565b336121746001546001600160a01b031690565b6001600160a01b03161461219a5760405162461bcd60e51b815260040161094590613dc6565b818061ffff166121ad60005461ffff1690565b61ffff16146121ce5760405162461bcd60e51b815260040161094590613df4565b6001600160a01b0382166122145760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b2103a37b5b2b760991b6044820152606401610945565b6109d1826132f5565b6000806122298361273d565b9050600061224a611d686000546001600160a01b03600160201b9091041690565b90508060ff168260ff1611156122b9576007546122678284613e48565b61227290600a613f45565b61227b866120c7565b6001600160a01b0387166000908152600b602052604090205461229e9190613f76565b6122a89190613f76565b6122b29190613f54565b9250611255565b6007546122c68383613e48565b6122d190600a613f45565b6122db9190613f76565b6122e4856120c7565b6001600160a01b0386166000908152600b602052604090205461214d565b60606000600e0180548060200260200160405190810160405280929190818152602001828054801561235d57602002820191906000526020600020905b81546001600160a01b0316815260019091019060200180831161233f575b5050505050905090565b3361237a6001546001600160a01b031690565b6001600160a01b0316146123a05760405162461bcd60e51b815260040161094590613dc6565b818061ffff166123b360005461ffff1690565b61ffff16146123d45760405162461bcd60e51b815260040161094590613df4565b6001600160a01b0382166124365760405162461bcd60e51b8152602060048201526024808201527f6e6577417373697374616e742063616e6e6f7420657175616c206164647265736044820152637328302960e01b6064820152608401610945565b600280546001600160a01b0319166001600160a01b038416179055505050565b336124696001546001600160a01b031690565b6001600160a01b03161461248f5760405162461bcd60e51b815260040161094590613dc6565b828061ffff166124a260005461ffff1690565b61ffff16146124c35760405162461bcd60e51b815260040161094590613df4565b6001600160a01b0383166000908152600d602052604090205460ff166124fb5760405162461bcd60e51b815260040161094590614027565b6001600160a01b0383166000908152600b602052604090208290555b50505050565b6001600160a01b0381166000908152600d602052604090205460ff1661257c5760405162461bcd60e51b81526020600482015260146024820152731d1bdad95b881b9bdd081c9959da5cdd195c995960621b6044820152606401610945565b6001600160a01b0381166000908152600d60209081526040808320805460ff19169055600a8252808320839055600b9091528120819055600e54905b8181101561260257826001600160a01b03166000600e0182815481106125e0576125e0614011565b6000918252602090912001546001600160a01b031614612602576001016125b8565b8181146109d157600182111561268a57600e61261f600184613f8d565b8154811061262f5761262f614011565b600091825260209091200154600e80546001600160a01b03909216918390811061265b5761265b614011565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b600e80548061269b5761269b61409e565b600082815260209020810160001990810180546001600160a01b0319169055019055505050565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b6002600f54036127365760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610945565b6002600f55565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b179052905160009182916001600160a01b03851691612780916140b4565b600060405180830381855afa9150503d80600081146127bb576040519150601f19603f3d011682016040523d82523d6000602084013e6127c0565b606091505b50915050808060200190518101906127d891906140e0565b9392505050565b6000806127eb846133c4565b90506127f984333086613470565b80612803856133c4565b61280d9190613f8d565b949350505050565b82516001600160a01b03166000908152600d602052604081205460ff1661284e5760405162461bcd60e51b815260040161094590614027565b60a08401516128ab5760405162461bcd60e51b8152602060048201526024808201527f746172676574526563697069656e742063616e6e6f74206265206279746573336044820152633228302960e01b6064820152608401610945565b60006128bf85604001518660200151610e36565b9050600081116129115760405162461bcd60e51b815260206004820152601d60248201527f6e6f726d616c697a656420616d6f756e74206d757374206265203e20300000006044820152606401610945565b600061292586606001518760200151610e36565b905085606001516000148061293a5750600081115b6129865760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420746f4e6174697665546f6b656e416d6f756e7400000000006044820152606401610945565b608086015161ffff16600090815260096020526040902054806129e35760405162461bcd60e51b81526020600482015260156024820152741d185c99d95d081b9bdd081c9959da5cdd195c9959605a1b6044820152606401610945565b6000612a096129ff89608001518a600001518b60200151611647565b8960200151610e36565b9050612a158382613fbd565b8411612a595760405162461bcd60e51b81526020600482015260136024820152721a5b9cdd59999a58da595b9d08185b5bdd5b9d606a1b6044820152606401610945565b6000612a8c6040518060800160405280600160ff1681526020018481526020018681526020018b60a00151815250611fa5565b90506000612aa26006546001600160a01b031690565b9050612ab78a60000151828c604001516134a8565b806001600160a01b031663c5a5ebda898c600001518d604001518e60800151898f896040518863ffffffff1660e01b8152600401612afa969594939291906140fd565b60206040518083038185885af1158015612b18573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061112e9190614163565b6000612b4a826020613fbd565b83511015612b925760405162461bcd60e51b8152602060048201526015602482015274746f427974657333325f6f75744f66426f756e647360581b6044820152606401610945565b50016020015190565b6000612ba8826002613fbd565b83511015612bef5760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b6044820152606401610945565b50016002015190565b60006001600160a01b0319821615612c485760405162461bcd60e51b8152602060048201526013602482015272696e76616c69642045564d206164647265737360681b6044820152606401610945565b5090565b60606000806000612c656005546001600160a01b031690565b6001600160a01b031663a9e11893866040518263ffffffff1660e01b8152600401612c909190613d25565b600060405180830381865afa158015612cad573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612cd591908101906142a2565b90506000612ce68260e0015161113c565b9050612d0a816001600160a01b03166000908152600d602052604090205460ff1690565b612d4d5760405162461bcd60e51b81526020600482015260146024820152731d1bdad95b881b9bdd081c9959da5cdd195c995960621b6044820152606401610945565b6000612d58826133c4565b90506000612d6e6006546001600160a01b031690565b90506000816001600160a01b031663c3f511c18a6040518263ffffffff1660e01b8152600401612d9e9190613d25565b6000604051808303816000875af1158015612dbd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612de591908101906143c6565b9050600083612df3866133c4565b612dfd9190613f8d565b90506000836001600160a01b031663ea63738d846040518263ffffffff1660e01b8152600401612e2d9190613d25565b600060405180830381865afa158015612e4a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612e7291908101906143fa565b9050612e92876060015161ffff1660009081526009602052604090205490565b8160c0015114612ee45760405162461bcd60e51b815260206004820152601760248201527f636f6e7472616374206e6f7420726567697374657265640000000000000000006044820152606401610945565b8660a001516001600160401b03168760800151886060015161ffff167fcaf280c8cfeba144da67230d9b009c8f868a75bac9a528fa0474be1ba317c16960405160405180910390a460e001519a9099509397509295505050505050565b3415612f9b5760405162461bcd60e51b815260206004820152602360248201527f726563697069656e742063616e6e6f742073776170206e61746976652061737360448201526265747360e81b6064820152608401610945565b6000546001600160a01b03600160201b909104811690851681148015612fbe5750815b1561305957604051632e1a7d4d60e01b8152600481018490526001600160a01b03821690632e1a7d4d90602401600060405180830381600087803b15801561300557600080fd5b505af1158015613019573d6000803e3d6000fd5b50506040516001600160a01b038716925085156108fc02915085906000818181858888f19350505050158015613053573d6000803e3d6000fd5b50613064565b6130648585856131e1565b5050505050565b34156130ae5760405162461bcd60e51b815260206004820152601260248201527176616c7565206d757374206265207a65726f60701b6044820152606401610945565b80156131a157600054604051632e1a7d4d60e01b815260048101869052600160201b9091046001600160a01b031690632e1a7d4d90602401600060405180830381600087803b15801561310057600080fd5b505af1158015613114573d6000803e3d6000fd5b50505050826001600160a01b03166108fc83866131319190613f8d565b6040518115909202916000818181858888f19350505050158015613159573d6000803e3d6000fd5b50811561319c576003546040516001600160a01b039091169083156108fc029084906000818181858888f1935050505015801561319a573d6000803e3d6000fd5b505b612517565b600054600160201b90046001600160a01b03166131c381856116368689613f8d565b821561306457613064816131df6003546001600160a01b031690565b855b6040516001600160a01b0383166024820152604481018290526109d190849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526135bd565b6000613251826001613fbd565b835110156132975760405162461bcd60e51b8152602060048201526013602482015272746f55696e74385f6f75744f66426f756e647360681b6044820152606401610945565b50016001015190565b60006132ad826020613fbd565b83511015612b925760405162461bcd60e51b8152602060048201526015602482015274746f55696e743235365f6f75744f66426f756e647360581b6044820152606401610945565b6001600160a01b0381166000908152600d602052604090205460ff161561335e5760405162461bcd60e51b815260206004820152601860248201527f746f6b656e20616c7265616479207265676973746572656400000000000000006044820152606401610945565b6001600160a01b03166000818152600d60205260408120805460ff19166001908117909155600e805491820181559091527fbb7b4a454dc3493923482f07822329ed19e8244eff582cc204f8554c3620c3fd0180546001600160a01b0319169091179055565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b179052905160009182916001600160a01b03851691613418916140b4565b600060405180830381855afa9150503d8060008114613453576040519150601f19603f3d011682016040523d82523d6000602084013e613458565b606091505b50915050808060200190518101906127d89190613e19565b6040516001600160a01b03808516602483015283166044820152606481018290526125179085906323b872dd60e01b9060840161320d565b8015806135225750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa1580156134fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135209190613e19565b155b61358d5760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608401610945565b6040516001600160a01b0383166024820152604481018290526109d190849063095ea7b360e01b9060640161320d565b6000613612826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661368f9092919063ffffffff16565b8051909150156109d1578080602001905181019061363091906144c2565b6109d15760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610945565b606061280d848460008585600080866001600160a01b031685876040516136b691906140b4565b60006040518083038185875af1925050503d80600081146136f3576040519150601f19603f3d011682016040523d82523d6000602084013e6136f8565b606091505b509150915061370987838387613714565b979650505050505050565b6060831561378357825160000361377c576001600160a01b0385163b61377c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610945565b508161280d565b61280d83838151156137985781518083602001fd5b8060405162461bcd60e51b81526004016109459190613d25565b61ffff811681146137c257600080fd5b50565b6001600160a01b03811681146137c257600080fd5b600080604083850312156137ed57600080fd5b82356137f8816137b2565b91506020830135613808816137c5565b809150509250929050565b63ffffffff811681146137c257600080fd5b60008060008060008060c0878903121561383e57600080fd5b8635613849816137c5565b955060208701359450604087013593506060870135613867816137b2565b92506080870135915060a087013561387e81613813565b809150509295509295509295565b80151581146137c257600080fd5b600080604083850312156138ad57600080fd5b82356138b8816137b2565b915060208301356138088161388c565b60ff811681146137c257600080fd5b600080604083850312156138ea57600080fd5b823591506020830135613808816138c8565b6000806000806080858703121561391257600080fd5b843593506020850135613924816137b2565b925060408501359150606085013561393b81613813565b939692955090935050565b60006020828403121561395857600080fd5b81356127d8816137c5565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b038111828210171561399b5761399b613963565b60405290565b60405161016081016001600160401b038111828210171561399b5761399b613963565b60405161010081016001600160401b038111828210171561399b5761399b613963565b604051601f8201601f191681016001600160401b0381118282101715613a0f57613a0f613963565b604052919050565b60006001600160401b03821115613a3057613a30613963565b50601f01601f191660200190565b600060208284031215613a5057600080fd5b81356001600160401b03811115613a6657600080fd5b8201601f81018413613a7757600080fd5b8035613a8a613a8582613a17565b6139e7565b818152856020838501011115613a9f57600080fd5b81602084016020830137600091810160200191909152949350505050565b60008060408385031215613ad057600080fd5b8235613adb816137b2565b946020939093013593505050565b60008060208385031215613afc57600080fd5b82356001600160401b0380821115613b1357600080fd5b818501915085601f830112613b2757600080fd5b813581811115613b3657600080fd5b866020828501011115613b4857600080fd5b60209290920196919550909350505050565b600080600060608486031215613b6f57600080fd5b8335613b7a816137b2565b92506020840135613b8a816137c5565b91506040840135613b9a816138c8565b809150509250925092565b600060208284031215613bb757600080fd5b81356127d8816137b2565b600080600060408486031215613bd757600080fd5b8335613be2816137b2565b925060208401356001600160401b0380821115613bfe57600080fd5b818601915086601f830112613c1257600080fd5b813581811115613c2157600080fd5b8760208260061b8501011115613c3657600080fd5b6020830194508093505050509250925092565b60008060408385031215613c5c57600080fd5b8235613adb816137c5565b600060808284031215613c7957600080fd5b604051608081018181106001600160401b0382111715613c9b57613c9b613963565b6040528235613ca9816138c8565b808252506020830135602082015260408301356040820152606083013560608201528091505092915050565b60005b83811015613cf0578181015183820152602001613cd8565b50506000910152565b60008151808452613d11816020860160208601613cd5565b601f01601f19169290920160200192915050565b6020815260006127d86020830184613cf9565b6020808252825182820181905260009190848201906040850190845b81811015613d795783516001600160a01b031683529284019291840191600101613d54565b50909695505050505050565b600080600060608486031215613d9a57600080fd5b8335613da5816137b2565b92506020840135613db5816137c5565b929592945050506040919091013590565b60208082526014908201527331b0b63632b9103737ba103a34329037bbb732b960611b604082015260600190565b6020808252600b908201526a3bb937b7339031b430b4b760a91b604082015260600190565b600060208284031215613e2b57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b60ff8281168282160390811115610e6a57610e6a613e32565b600181815b80851115613e9c578160001904821115613e8257613e82613e32565b80851615613e8f57918102915b93841c9390800290613e66565b509250929050565b600082613eb357506001610e6a565b81613ec057506000610e6a565b8160018114613ed65760028114613ee057613efc565b6001915050610e6a565b60ff841115613ef157613ef1613e32565b50506001821b610e6a565b5060208310610133831016604e8410600b8410161715613f1f575081810a610e6a565b613f298383613e61565b8060001904821115613f3d57613f3d613e32565b029392505050565b60006127d860ff841683613ea4565b600082613f7157634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417610e6a57610e6a613e32565b81810381811115610e6a57610e6a613e32565b600060208284031215613fb257600080fd5b81516127d8816137c5565b80820180821115610e6a57610e6a613e32565b60208082526021908201527f63616c6c6572206e6f7420746865206f776e6572206f7220617373697374616e6040820152601d60fa1b606082015260800190565b634e487b7160e01b600052603260045260246000fd5b6020808252601290820152711d1bdad95b881b9bdd081858d8d95c1d195960721b604082015260600190565b60008184825b8581101561409357813561406c816137c5565b6001600160a01b031683526020828101359084015260409283019290910190600101614059565b509095945050505050565b634e487b7160e01b600052603160045260246000fd5b600082516140c6818460208701613cd5565b9190910192915050565b80516140db816138c8565b919050565b6000602082840312156140f257600080fd5b81516127d8816138c8565b60018060a01b038716815285602082015261ffff8516604082015283606082015263ffffffff8316608082015260c060a0820152600061414060c0830184613cf9565b98975050505050505050565b80516001600160401b03811681146140db57600080fd5b60006020828403121561417557600080fd5b6127d88261414c565b80516140db81613813565b80516140db816137b2565b600082601f8301126141a557600080fd5b81516141b3613a8582613a17565b8181528460208386010111156141c857600080fd5b61280d826020830160208701613cd5565b600082601f8301126141ea57600080fd5b815160206001600160401b0382111561420557614205613963565b614213818360051b016139e7565b82815260079290921b8401810191818101908684111561423257600080fd5b8286015b84811015614297576080818903121561424f5760008081fd5b614257613979565b815181528482015185820152604080830151614272816138c8565b90820152606082810151614285816138c8565b90820152835291830191608001614236565b509695505050505050565b6000602082840312156142b457600080fd5b81516001600160401b03808211156142cb57600080fd5b9083019061016082860312156142e057600080fd5b6142e86139a1565b6142f1836140d0565b81526142ff6020840161417e565b60208201526143106040840161417e565b604082015261432160608401614189565b60608201526080830151608082015261433c60a0840161414c565b60a082015261434d60c084016140d0565b60c082015260e08301518281111561436457600080fd5b61437087828601614194565b60e08301525061010061438481850161417e565b90820152610120838101518381111561439c57600080fd5b6143a8888287016141d9565b91830191909152506101409283015192810192909252509392505050565b6000602082840312156143d857600080fd5b81516001600160401b038111156143ee57600080fd5b61280d84828501614194565b60006020828403121561440c57600080fd5b81516001600160401b038082111561442357600080fd5b90830190610100828603121561443857600080fd5b6144406139c4565b614449836140d0565b8152602083015160208201526040830151604082015261446b60608401614189565b60608201526080830151608082015261448660a08401614189565b60a082015260c083015160c082015260e0830151828111156144a757600080fd5b6144b387828601614194565b60e08301525095945050505050565b6000602082840312156144d457600080fd5b81516127d88161388c56fea26469706673582212204380a2c16f3d3a94e16ceec8dd417389a415486e9286774f1ba51d1e17ea374064736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000796dff6d74f3e27060b71255fe517bfb23c93eed000000000000000000000000471ece3750da237f93b8e339c536989b8978a43800000000000000000000000053cd7442fee1ad9edfd43fe469efa26721b969ed000000000000000000000000f285bd23217ae02779e11b7e822e603f31bbe6690000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : tokenBridge_ (address): 0x796Dff6D74F3E27060B71255Fe517BFb23C93eed
Arg [1] : wethAddress (address): 0x471EcE3750Da237f93B8E339c536989b8978a438
Arg [2] : feeRecipient_ (address): 0x53cD7442fEe1ad9eDFD43FE469EfA26721b969Ed
Arg [3] : ownerAssistant_ (address): 0xf285BD23217ae02779E11b7E822e603F31BBe669
Arg [4] : unwrapWeth_ (bool): False
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000796dff6d74f3e27060b71255fe517bfb23c93eed
Arg [1] : 000000000000000000000000471ece3750da237f93b8e339c536989b8978a438
Arg [2] : 00000000000000000000000053cd7442fee1ad9edfd43fe469efa26721b969ed
Arg [3] : 000000000000000000000000f285bd23217ae02779e11b7e822e603f31bbe669
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode Sourcemap
693:27057:9:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5734:222:11;;;;;;;;;;-1:-1:-1;5734:222:11;;;;;:::i;:::-;;:::i;:::-;;1758:496;;;;;;;;;;;;;:::i;3946:1510:9:-;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;1688:31:16;;;1670:50;;1658:2;1643:18;3946:1510:9;;;;;;;;10069:160:11;;;;;;;;;;-1:-1:-1;10069:160:11;;;;;:::i;:::-;;:::i;1580:107:10:-;;;;;;;;;;-1:-1:-1;1656:24:10;;1580:107;;;2385:25:16;;;2373:2;2358:18;1580:107:10;2239:177:16;3078:514:11;;;;;;;;;;-1:-1:-1;3078:514:11;;;;;:::i;:::-;;:::i;2821:221:10:-;;;;;;;;;;-1:-1:-1;2821:221:10;;;;;:::i;:::-;;:::i;3048:223::-;;;;;;;;;;-1:-1:-1;3048:223:10;;;;;:::i;:::-;;:::i;6254:1573:9:-;;;;;;:::i;:::-;;:::i;2324:110:10:-;;;;;;;;;;-1:-1:-1;2324:110:10;;;;;:::i;:::-;-1:-1:-1;;;;;2404:23:10;2378:7;2404:23;;;:16;:23;;;;;;;2324:110;23003:811:9;;;;;;;;;;-1:-1:-1;23003:811:9;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;5855:32:16;;;5837:51;;5825:2;5810:18;23003:811:9;5691:203:16;8830:268:11;;;;;;;;;;-1:-1:-1;8830:268:11;;;;;:::i;:::-;;:::i;2187:131:10:-;;;;;;;;;;-1:-1:-1;2187:131:10;;;;;:::i;:::-;-1:-1:-1;;;;;2278:33:10;2252:7;2278:33;;;:26;:33;;;;;;;2187:131;12606:5064:9;;;;;;:::i;:::-;;:::i;26511:471::-;;;;;;;;;;-1:-1:-1;26511:471:9;;;;;:::i;:::-;;:::i;1693:119:10:-;;;;;;;;;;-1:-1:-1;1693:119:10;;;;;:::i;:::-;-1:-1:-1;;;;;1777:28:10;1754:4;1777:28;;;:21;:28;;;;;;;;;1693:119;;;;7506:14:16;;7499:22;7481:41;;7469:2;7454:18;1693:119:10;7341:187:16;1424:150:10;;;;;;;;;;-1:-1:-1;1424:150:10;;;;;:::i;:::-;1525:42;;1499:7;1525:42;;;:26;:42;;;;;;;1424:150;1945:111;;;;;;;;;;-1:-1:-1;2023:26:10;;1945:111;;706:97;;;;;;;;;;-1:-1:-1;777:19:10;;-1:-1:-1;;;;;777:19:10;706:97;;4559:530:11;;;;;;;;;;-1:-1:-1;4559:530:11;;;;;:::i;:::-;;:::i;6366:339::-;;;;;;;;;;-1:-1:-1;6366:339:11;;;;;:::i;:::-;;:::i;7793:861::-;;;;;;;;;;-1:-1:-1;7793:861:11;;;;;:::i;:::-;;:::i;2062:119:10:-;;;;;;;;;;-1:-1:-1;2062:119:10;;;;;:::i;:::-;2146:28;;2120:7;2146:28;;;:18;:28;;;;;;;2062:119;1333:85;;;;;;;;;;-1:-1:-1;1375:4:10;1398:13;;;;;;1333:85;;599:101;;;;;;;;;;-1:-1:-1;672:21:10;;-1:-1:-1;;;;;672:21:10;599:101;;1174:801:12;;;;;;;;;;-1:-1:-1;1174:801:12;;;;;:::i;:::-;;:::i;:::-;;;;;;9309:13:16;;9324:4;9305:24;9287:43;;9386:4;9374:17;;;9368:24;9346:20;;;9339:54;9449:4;9437:17;;;9431:24;9409:20;;;9402:54;9512:4;9500:17;;;9494:24;9472:20;;;9465:54;;;;9274:3;9259:19;;9070:455;4113:178:11;;;;;;;;;;-1:-1:-1;4113:178:11;;;;;:::i;:::-;;:::i;809:102:10:-;;;;;;;;;;-1:-1:-1;888:15:10;;-1:-1:-1;;;;;888:15:10;809:102;;407:83;;;;;;;;;;-1:-1:-1;471:12:10;;-1:-1:-1;;;;;471:12:10;407:83;;25383:737:9;;;;;;;;;;-1:-1:-1;25383:737:9;;;;;:::i;:::-;;:::i;6887:278:11:-;;;;;;;;;;-1:-1:-1;6887:278:11;;;;;:::i;:::-;;:::i;920:261::-;;;;;;;;;;-1:-1:-1;920:261:11;;;;;:::i;:::-;;:::i;1241:86:10:-;;;;;;;;;;-1:-1:-1;1281:6:10;1306:14;1241:86;;1306:14;;;;10220:38:16;;10208:2;10193:18;1241:86:10;10076:188:16;1145:90:10;;;;;;;;;;-1:-1:-1;1188:4:10;1211:17;;;;;;1145:90;;451:391:12;;;;;;;;;;-1:-1:-1;451:391:12;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;1329:159:11:-;;;;;;;;;;-1:-1:-1;1329:159:11;;;;;:::i;:::-;;:::i;1046:93:10:-;;;;;;;;;;-1:-1:-1;1083:5:10;1113:18;-1:-1:-1;;;1113:18:10;;-1:-1:-1;;;;;1113:18:10;1046:93;;2440:375;;;;;;;;;;-1:-1:-1;2440:375:10;;;;;:::i;:::-;;:::i;917:123::-;;;;;;;;;;-1:-1:-1;1013:18:10;;-1:-1:-1;;;;;1013:18:10;917:123;;5253:217:11;;;;;;;;;;-1:-1:-1;5253:217:11;;;;;:::i;:::-;;:::i;24257:705:9:-;;;;;;;;;;-1:-1:-1;24257:705:9;;;;;:::i;:::-;;:::i;1818:121:10:-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;496:97::-;;;;;;;;;;-1:-1:-1;567:19:10;;-1:-1:-1;;;;;567:19:10;496:97;;2496:341:11;;;;;;;;;;-1:-1:-1;2496:341:11;;;;;:::i;:::-;;:::i;859:40:9:-;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;859:40:9;;;;;9407:281:11;;;;;;;;;;-1:-1:-1;9407:281:11;;;;;:::i;:::-;;:::i;5734:222::-;10285:10;10274:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;10274:7:11;-1:-1:-1;;;;;10274:21:11;;10266:54;;;;-1:-1:-1;;;10266:54:11;;;;;;;:::i;:::-;;;;;;;;;5847:8:::1;10631;10618:21;;:9;1281:6:10::0;1306:14;;;;1241:86;10618:9:11::1;:21;;;10610:45;;;;-1:-1:-1::0;;;10610:45:11::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;5875:19:11;::::2;5867:45;;;::::0;-1:-1:-1;;;5867:45:11;;14427:2:16;5867:45:11::2;::::0;::::2;14409:21:16::0;14466:2;14446:18;;;14439:30;-1:-1:-1;;;14485:18:16;;;14478:43;14538:18;;5867:45:11::2;14225:337:16::0;5867:45:11::2;5923:26;5943:5;5923:19;:26::i;:::-;10330:1:::1;5734:222:::0;;:::o;1758:496::-;1857:16;1876:14;567:19:10;;-1:-1:-1;;;;;567:19:10;;496:97;1876:14:11;1857:33;-1:-1:-1;1909:10:11;-1:-1:-1;;;;;1909:22:11;;;1901:62;;;;-1:-1:-1;;;1901:62:11;;14769:2:16;1901:62:11;;;14751:21:16;14808:2;14788:18;;;14781:30;14847:29;14827:18;;;14820:57;14894:18;;1901:62:11;14567:351:16;1901:62:11;2014:20;2037:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;2037:7:11;234:12:13;:21;;-1:-1:-1;;;;;;234:21:13;-1:-1:-1;;;;;234:21:13;;;;;2014:30:11;-1:-1:-1;2161:27:11;2185:1;2161:15;:27::i;:::-;2238:8;-1:-1:-1;;;;;2204:43:11;2224:12;-1:-1:-1;;;;;2204:43:11;;;;;;;;;;;1808:446;;1758:496::o;3946:1510:9:-;4201:22;2261:21:0;:19;:21::i;:::-;1375:4:10;1398:13;;;;;;10718:12:11::1;10710:42;;;::::0;-1:-1:-1;;;10710:42:11;;15125:2:16;10710:42:11::1;::::0;::::1;15107:21:16::0;15164:2;15144:18;;;15137:30;-1:-1:-1;;;15183:18:16;;;15176:47;15240:18;;10710:42:11::1;14923:341:16::0;10710:42:11::1;4362:19:9::2;4384:10;888:15:10::0;;-1:-1:-1;;;;;888:15:10;;809:102;4384:10:9::2;-1:-1:-1::0;;;;;4384:21:9::2;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::2;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;4362:45;;4438:11;4425:9;:24;4417:55;;;::::0;-1:-1:-1;;;4417:55:9;;15660:2:16;4417:55:9::2;::::0;::::2;15642:21:16::0;15699:2;15679:18;;;15672:30;-1:-1:-1;;;15718:18:16;;;15711:48;15776:18;;4417:55:9::2;15458:342:16::0;4417:55:9::2;4635:19;4657:18;4669:5;4657:11;:18::i;:::-;4635:40;;4694:106;4725:38;4741:6;4749:13;4725:15;:38::i;:::-;4777:13;4694:17;:106::i;:::-;4685:115;;4939:28;4953:5;4960:6;4939:13;:28::i;:::-;4930:37;;5059:390;5097:296;;;;;;;;5145:5;-1:-1:-1::0;;;;;5097:296:9::2;;;;;5215:13;5097:296;;;;;;5176:6;5097:296;;;;5267:19;5097:296;;;;5317:11;5097:296;;;;;;5363:15;5097:296;;::::0;5407:7:::2;5428:11;5059:24;:390::i;:::-;5041:408;;4225:1231;;2303:20:0::0;1716:1;2809:7;:22;2629:209;2303:20;3946:1510:9;;;;;;;;:::o;10069:160:11:-;10285:10;10274:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;10274:7:11;-1:-1:-1;;;;;10274:21:11;;10266:54;;;;-1:-1:-1;;;10266:54:11;;;;;;;:::i;:::-;10185:8:::1;10631;10618:21;;:9;1281:6:10::0;1306:14;;;;1241:86;10618:9:11::1;:21;;;10610:45;;;;-1:-1:-1::0;;;10610:45:11::1;;;;;;;:::i;:::-;1199:6:13::0;:22;;-1:-1:-1;;1199:22:13;;;;;;;;;10330:1:11::1;5734:222:::0;;:::o;3078:514::-;10285:10;10274:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;10274:7:11;-1:-1:-1;;;;;10274:21:11;;10266:54;;;;-1:-1:-1;;;10266:54:11;;;;;;;:::i;:::-;3204:8:::1;10631;10618:21;;:9;1281:6:10::0;1306:14;;;;1241:86;10618:9:11::1;:21;;;10610:45;;;;-1:-1:-1::0;;;10610:45:11::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;3245:29:11;::::2;3224:115;;;::::0;-1:-1:-1;;;3224:115:11;;16007:2:16;3224:115:11::2;::::0;::::2;15989:21:16::0;16046:2;16026:18;;;16019:30;16085:34;16065:18;;;16058:62;-1:-1:-1;;;16136:18:16;;;16129:37;16183:19;;3224:115:11::2;15805:403:16::0;3224:115:11::2;3389:27;3419:14;777:19:10::0;;-1:-1:-1;;;;;777:19:10;;706:97;3419:14:11::2;573:19:13::0;:35;;-1:-1:-1;;;;;;573:35:13;-1:-1:-1;;;;;573:35:13;;;;;3389:44:11;-1:-1:-1;3569:15:11::2;-1:-1:-1::0;;;;;3528:57:11::2;3548:19;-1:-1:-1::0;;;;;3528:57:11::2;;;;;;;;;;;3214:378;10330:1:::1;3078:514:::0;;:::o;2821:221:10:-;2921:7;2955:1;2944:8;:12;;;2940:73;;;2989:12;3000:1;2989:8;:12;:::i;:::-;2982:20;;:2;:20;:::i;:::-;2972:30;;;;:::i;:::-;;;2940:73;-1:-1:-1;3029:6:10;2821:221;;;;;:::o;3048:223::-;3150:7;3184:1;3173:8;:12;;;3169:73;;;3218:12;3229:1;3218:8;:12;:::i;:::-;3211:20;;:2;:20;:::i;:::-;3201:30;;;;:::i;6254:1573:9:-;6453:22;1398:13:10;;;;;;;10718:12:11;10710:42;;;;-1:-1:-1;;;10710:42:11;;15125:2:16;10710:42:11;;;15107:21:16;15164:2;15144:18;;;15137:30;-1:-1:-1;;;15183:18:16;;;15176:47;15240:18;;10710:42:11;14923:341:16;10710:42:11;1188:4:10;1211:17;;;;;;6487:57:9::1;;;::::0;-1:-1:-1;;;6487:57:9;;18481:2:16;6487:57:9::1;::::0;::::1;18463:21:16::0;;;18500:18;;;18493:30;18559:34;18539:18;;;18532:62;18611:18;;6487:57:9::1;18279:356:16::0;6487:57:9::1;6682:19;6704:10;888:15:10::0;;-1:-1:-1;;;;;888:15:10;;809:102;6704:10:9::1;-1:-1:-1::0;;;;;6704:21:9::1;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6682:45;;6757:11;6745:9;:23;6737:54;;;::::0;-1:-1:-1;;;6737:54:9;;15660:2:16;6737:54:9::1;::::0;::::1;15642:21:16::0;15699:2;15679:18;;;15672:30;-1:-1:-1;;;15718:18:16;;;15711:48;15776:18;;6737:54:9::1;15458:342:16::0;6737:54:9::1;6862:14;6879:23;6891:11:::0;6879:9:::1;:23;:::i;:::-;6862:40;;6936:12;6960:50;6978:27;6994:6;7002:2;6978:15;:27::i;:::-;7007:2;6960:17;:50::i;:::-;6951:59;::::0;:6;:59:::1;:::i;:::-;6936:74:::0;-1:-1:-1;7024:8:9;;7020:73:::1;;7048:34;::::0;7056:10:::1;::::0;7048:34;::::1;;;::::0;7077:4;;7048:34:::1;::::0;;;7077:4;7056:10;7048:34;::::1;;;;;;;;;;;;;::::0;::::1;;;;;;7020:73;7153:22;7178:13;7187:4:::0;7178:6;:13:::1;:::i;:::-;7153:38;;7201:10;7214:6;1083:5:10::0;1113:18;-1:-1:-1;;;;;;;;1113:18:10;;;;;1046:93;7214:6:9::1;7201:19;;7273:4;-1:-1:-1::0;;;;;7273:12:9::1;;7307:14;7273:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;;7425:395;7463:301;;;;;;;;7519:4;-1:-1:-1::0;;;;;7463:301:9::1;;;;;7557:2;7463:301;;;;;;7585:14;7463:301;;;;7638:19;7463:301;;;;7688:11;7463:301;;;;;;7734:15;7463:301;;::::0;7778:7:::1;7799:11;7425:24;:395::i;:::-;7407:413:::0;6254:1573;-1:-1:-1;;;;;;;;;;6254:1573:9:o;23003:811::-;23106:20;;23216:21;:7;23234:2;23216:17;:21::i;:::-;23192:45;-1:-1:-1;23247:17:9;23267:20;:7;23284:2;23267:16;:20::i;:::-;23247:40;;23423:9;1281:6:10;1306:14;;;;1241:86;23423:9:9;23409:23;;:10;:23;;;23405:403;;1013:18:10;;-1:-1:-1;;;;;1013:18:10;23517:53:9;;-1:-1:-1;;;23517:53:9;;18975:6:16;18963:19;;23517:53:9;;;18945:38:16;18999:18;;;18992:34;;;-1:-1:-1;;;;;23517:26:9;;;;;;;18918:18:16;;23517:53:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;23502:68;-1:-1:-1;;;;;;23592:26:9;;23584:57;;;;-1:-1:-1;;;23584:57:9;;19495:2:16;23584:57:9;;;19477:21:16;19534:2;19514:18;;;19507:30;-1:-1:-1;;;19553:18:16;;;19546:48;19611:18;;23584:57:9;19293:342:16;23584:57:9;23405:403;;;23766:31;23783:13;23766:16;:31::i;:::-;23751:46;;23405:403;23128:686;;23003:811;;;:::o;8830:268:11:-;10285:10;10274:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;10274:7:11;-1:-1:-1;;;;;10274:21:11;;10266:54;;;;-1:-1:-1;;;10266:54:11;;;;;;;:::i;:::-;8964:8:::1;10631;10618:21;;:9;1281:6:10::0;1306:14;;;;1241:86;10618:9:11::1;:21;;;10610:45;;;;-1:-1:-1::0;;;10610:45:11::1;;;;;;;:::i;:::-;9013:1:::2;8992:18;:22;8984:56;;;::::0;-1:-1:-1;;;8984:56:11;;19842:2:16;8984:56:11::2;::::0;::::2;19824:21:16::0;19881:2;19861:18;;;19854:30;-1:-1:-1;;;19900:18:16;;;19893:51;19961:18;;8984:56:11::2;19640:345:16::0;8984:56:11::2;9051:40;9072:18;1445:24:13::0;:36;1377:111;12606:5064:9;12767:20;12789:14;12805:13;12835:41;12853:22;;12835:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;12835:17:9;;-1:-1:-1;;;12835:41:9:i;:::-;12766:110;;;;;;12952:42;12997:54;13034:7;12997:23;:54::i;:::-;12952:99;;13122:17;13142:51;13159:17;:33;;;13142:16;:51::i;:::-;13122:71;;13203:15;13221:12;1188:4:10;1211:17;;;;;;;;1145:90;13221:12:9;13203:30;-1:-1:-1;;;;;;13283:23:9;;:10;:23;13279:238;;13322:139;13363:5;13386:9;13413:6;13437:10;13322:23;:139::i;:::-;13500:7;;;;;;12606:5064;;:::o;13279:238::-;13559:19;13581:18;13593:5;13581:11;:18::i;:::-;13559:40;;13693:102;13724:17;:34;;;13772:13;13693:17;:102::i;:::-;13656:34;;;:139;1083:5:10;1113:18;-1:-1:-1;;;1113:18:10;;-1:-1:-1;;;;;1113:18:10;-1:-1:-1;;;;;13845:24:9;:5;-1:-1:-1;;;;;13845:24:9;;13841:266;;13885:166;13924:6;13948:9;13975:17;:34;;;14027:10;13885:21;:166::i;:::-;14090:7;;;;;;;12606:5064;;:::o;13841:266::-;14173:37;;;;:41;14169:2875;;14321:117;14356:17;:37;;;14411:13;14321:17;:117::i;:::-;14281:37;;;:157;14859:26;14888:31;14913:5;14888:24;:31::i;:::-;14859:60;;14977:18;14937:17;:37;;;:58;14933:155;;;15015:37;;;:58;;;14933:155;15168:32;15203:120;15249:5;15272:17;:37;;;15203:28;:120::i;:::-;15168:155;-1:-1:-1;15722:28:9;;15718:1316;;15877:24;15864:9;:37;;15835:140;;;;-1:-1:-1;;;15835:140:9;;20192:2:16;15835:140:9;;;20174:21:16;;;20211:18;;;20204:30;20270:34;20250:18;;;20243:62;20322:18;;15835:140:9;19990:356:16;15835:140:9;16065:21;16089:36;16101:24;16089:9;:36;:::i;:::-;16065:60;-1:-1:-1;16147:17:9;;16143:107;;16188:43;;16196:10;;16188:43;;;;;16217:13;;16188:43;;;;16217:13;16196:10;16188:43;;;;;;;;;;;;;;;;;;;;;16143:107;16335:53;;-1:-1:-1;;;;;16335:27:9;;;:53;;;;;16363:24;;16335:53;;;;16363:24;16335:27;:53;;;;;;;;;;;;;;;;;;;;;16544:5;-1:-1:-1;;;;;16447:225:9;16512:10;-1:-1:-1;;;;;16447:225:9;16481:9;-1:-1:-1;;;;;16447:225:9;;16571:17;:37;;;16630:24;16447:225;;;;;;20525:25:16;;;20581:2;20566:18;;20559:34;20513:2;20498:18;;20351:248;16447:225:9;;;;;;;;15752:935;15718:1316;;;16824:1;16784:37;;;:41;16925:9;:13;16921:99;;16962:39;;16970:10;;16991:9;16962:39;;;;;;;;;16991:9;16970:10;16962:39;;;;;;;;;;;;;;;;;;;;;16921:99;14216:2828;;14169:2875;17110:24;17186:17;:37;;;17149:17;:34;;;:74;;;;:::i;:::-;17110:113;-1:-1:-1;17295:20:9;;17291:184;;17331:133;17378:5;17402:14;777:19:10;;-1:-1:-1;;;;;777:19:10;;706:97;17402:14:9;17434:16;17331:22;:133::i;:::-;17542:121;17585:5;17605:9;17628:25;17637:16;17628:6;:25;:::i;:::-;17542:22;:121::i;:::-;12695:4975;;;;;;;;12606:5064;;:::o;26511:471::-;-1:-1:-1;;;;;2404:23:10;;26644:30:9;2404:23:10;;;:16;:23;;;;;;26770:13:9;26787:1;26770:18;26762:48;;;;-1:-1:-1;;;26762:48:9;;20936:2:16;26762:48:9;;;20918:21:16;20975:2;20955:18;;;20948:30;-1:-1:-1;;;20994:18:16;;;20987:47;21051:18;;26762:48:9;20734:341:16;26762:48:9;2023:26:10;;26937:37:9;;:13;:37;:::i;:::-;1656:24:10;;2146:28;;;2120:7;2146:28;;;:18;:28;;;;;;26857:14:9;26863:8;26857:2;:14;:::i;:::-;:42;;;;:::i;:::-;:64;;;;:::i;:::-;:118;;;;:::i;:::-;26820:155;26511:471;-1:-1:-1;;;;;26511:471:9:o;4559:530:11:-;10285:10;10274:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;10274:7:11;-1:-1:-1;;;;;10274:21:11;;10266:54;;;;-1:-1:-1;;;10266:54:11;;;;;;;:::i;:::-;4742:15;4721:115:::1;;;::::0;-1:-1:-1;;;4721:115:11;;21282:2:16;4721:115:11::1;::::0;::::1;21264:21:16::0;21321:2;21301:18;;;21294:30;21360:34;21340:18;;;21333:62;-1:-1:-1;;;21411:18:16;;;21404:37;21458:19;;4721:115:11::1;21080:403:16::0;4721:115:11::1;4867:13;::::0;::::1;::::0;;::::1;::::0;:38:::1;;-1:-1:-1::0;1281:6:10;1306:14;;4884:21:11;;::::1;1306:14:10::0;;4884:21:11::1;;4867:38;4846:124;;;::::0;-1:-1:-1;;;4846:124:11;;21690:2:16;4846:124:11::1;::::0;::::1;21672:21:16::0;21729:2;21709:18;;;21702:30;21768:34;21748:18;;;21741:62;-1:-1:-1;;;21819:18:16;;;21812:37;21866:19;;4846:124:11::1;21488:403:16::0;4846:124:11::1;1316:36:13::0;;;;;:6;:36;;;:26;:36;;;;;:48;4559:530:11:o;5038:44::-:1;4559:530:::0;;:::o;6366:339::-;10418:10;10407:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;10407:7:11;-1:-1:-1;;;;;10407:21:11;;:67;;;-1:-1:-1;10464:10:11;10444:16;672:21:10;;-1:-1:-1;;;;;672:21:10;;599:101;10444:16:11;-1:-1:-1;;;;;10444:30:11;;10407:67;10386:147;;;;-1:-1:-1;;;10386:147:11;;;;;;;:::i;:::-;1281:6:10;1306:14;;;6493:21:11::1;;:8;:21;;::::0;6485:47:::1;;;::::0;-1:-1:-1;;;6485:47:11;;22500:2:16;6485:47:11::1;::::0;::::1;22482:21:16::0;22539:2;22519:18;;;22512:30;-1:-1:-1;;;22558:18:16;;;22551:43;22611:18;;6485:47:11::1;22298:337:16::0;6485:47:11::1;1525:42:10::0;;;6606:1:11::1;1525:42:10::0;;;:26;:42;;;;;;6542:114:11::1;;;::::0;-1:-1:-1;;;6542:114:11;;22842:2:16;6542:114:11::1;::::0;::::1;22824:21:16::0;22881:2;22861:18;;;22854:30;-1:-1:-1;;;22900:18:16;;;22893:52;22962:18;;6542:114:11::1;22640:346:16::0;6542:114:11::1;3009:28:13::0;;;;;:6;:28;;;:18;:28;;;;;:34;4559:530:11:o;7793:861::-;10418:10;10407:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;10407:7:11;-1:-1:-1;;;;;10407:21:11;;:67;;;-1:-1:-1;10464:10:11;10444:16;672:21:10;;-1:-1:-1;;;;;672:21:10;;599:101;10444:16:11;-1:-1:-1;;;;;10444:30:11;;10407:67;10386:147;;;;-1:-1:-1;;;10386:147:11;;;;;;;:::i;:::-;7969:8:::1;10631;10618:21;;:9;1281:6:10::0;1306:14;;;;1241:86;10618:9:11::1;:21;;;10610:45;;;;-1:-1:-1::0;;;10610:45:11::1;;;;;;;:::i;:::-;8057:14:::0;8096:13;8088:44:::2;;;::::0;-1:-1:-1;;;8088:44:11;;23193:2:16;8088:44:11::2;::::0;::::2;23175:21:16::0;23232:2;23212:18;;;23205:30;-1:-1:-1;;;23251:18:16;;;23244:48;23309:18;;8088:44:11::2;22991:342:16::0;8088:44:11::2;8192:9;8187:414;8211:9;8207:1;:13;8187:414;;;8262:40;8278:14;;8293:1;8278:17;;;;;;;:::i;:::-;:23;::::0;::::2;:17;::::0;;::::2;;:23:::0;;::::2;::::0;-1:-1:-1;8278:23:11::2;:::i;8262:40::-;8237:117;;;;-1:-1:-1::0;;;8237:117:11::2;;;;;;;:::i;:::-;8419:1;8393:14;;8408:1;8393:17;;;;;;;:::i;:::-;;;;;;:23;;;:27;8368:111;;;::::0;-1:-1:-1;;;8368:111:11;;24019:2:16;8368:111:11::2;::::0;::::2;24001:21:16::0;24058:2;24038:18;;;24031:30;24097:27;24077:18;;;24070:55;24142:18;;8368:111:11::2;23817:349:16::0;8368:111:11::2;8494:61;8506:14;;8521:1;8506:17;;;;;;;:::i;:::-;:23;::::0;::::2;:17;::::0;;::::2;;:23:::0;;::::2;::::0;-1:-1:-1;8506:23:11::2;:::i;:::-;8531:14;;8546:1;8531:17;;;;;;;:::i;:::-;;;;;;:23;;;-1:-1:-1::0;;;;;3129:23:13;;;:6;:23;;;:16;:23;;;;;:34;3056:114;8494:61:11::2;8587:1;8582:6;8187:414;;;;8632:14;;8616:31;;;;;;;:::i;:::-;;::::0;;;;::::2;::::0;;;::::2;::::0;;;::::2;7979:675;10543:1:::1;7793:861:::0;;;:::o;1174:801:12:-;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1389:22:12;:7;-1:-1:-1;1389:15:12;:22::i;:::-;1368:43;;;;1421:10;1430:1;1421:10;;:::i;:::-;;;1450:8;:18;;;:23;;1472:1;1450:23;1442:53;;;;-1:-1:-1;;;1442:53:12;;25157:2:16;1442:53:12;;;25139:21:16;25196:2;25176:18;;;25169:30;-1:-1:-1;;;25215:18:16;;;25208:47;25272:18;;1442:53:12;24955:341:16;1442:53:12;1564:24;:7;1582:5;1564:17;:24::i;:::-;1536:25;;;;:52;;;;1598:11;;;;:::i;:::-;;-1:-1:-1;1707:24:12;:7;1598:11;1707:17;:24::i;:::-;1676:28;;;:55;1741:11;1750:2;1741:11;;:::i;:::-;;-1:-1:-1;1854:24:12;:7;1741:11;1854:17;:24::i;:::-;1827;;;:51;1888:11;1897:2;1888:11;;:::i;:::-;;;1927:7;:14;1918:5;:23;1910:58;;;;-1:-1:-1;;;1910:58:12;;25503:2:16;1910:58:12;;;25485:21:16;25542:2;25522:18;;;25515:30;-1:-1:-1;;;25561:18:16;;;25554:52;25623:18;;1910:58:12;25301:346:16;1910:58:12;1299:676;1174:801;;;:::o;4113:178:11:-;10285:10;10274:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;10274:7:11;-1:-1:-1;;;;;10274:21:11;;10266:54;;;;-1:-1:-1;;;10266:54:11;;;;;;;:::i;:::-;4234:8:::1;10631;10618:21;;:9;1281:6:10::0;1306:14;;;;1241:86;10618:9:11::1;:21;;;10610:45;;;;-1:-1:-1::0;;;10610:45:11::1;;;;;;;:::i;:::-;913:6:13::0;:31;;-1:-1:-1;;913:31:13;;;;;;;;;10330:1:11::1;5734:222:::0;;:::o;25383:737:9:-;25503:20;25596:19;25618:18;25630:5;25618:11;:18::i;:::-;25596:40;;25646:20;25669:28;25689:6;1083:5:10;1113:18;-1:-1:-1;;;;;;;;1113:18:10;;;;;1046:93;25689:6:9;25669:11;:28::i;:::-;25646:51;;25728:14;25712:30;;:13;:30;;;25708:406;;;25876:30;25892:14;25876:13;:30;:::i;:::-;25869:38;;:2;:38;:::i;:::-;25845:21;25860:5;25845:14;:21::i;:::-;:62;;;;:::i;:::-;25811:14;25789:19;1656:24:10;;;1580:107;25789:19:9;:36;;;;:::i;:::-;:119;;;;:::i;:::-;25758:150;;25708:406;;;26082:21;26097:5;26082:14;:21::i;:::-;26032:30;26049:13;26032:14;:30;:::i;:::-;26025:38;;:2;:38;:::i;:::-;25992:14;25970:19;1656:24:10;;;1580:107;25970:19:9;:36;;;;:::i;:::-;:93;;;;:::i;:::-;:133;;;;:::i;:::-;25939:164;;25708:406;25525:595;;25383:737;;;;:::o;6887:278:11:-;10285:10;10274:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;10274:7:11;-1:-1:-1;;;;;10274:21:11;;10266:54;;;;-1:-1:-1;;;10266:54:11;;;;;;;:::i;:::-;7025:8:::1;10631;10618:21;;:9;1281:6:10::0;1306:14;;;;1241:86;10618:9:11::1;:21;;;10610:45;;;;-1:-1:-1::0;;;10610:45:11::1;;;;;;;:::i;:::-;7076:1:::2;7053:20;:24;7045:58;;;::::0;-1:-1:-1;;;7045:58:11;;19842:2:16;7045:58:11::2;::::0;::::2;19824:21:16::0;19881:2;19861:18;;;19854:30;-1:-1:-1;;;19900:18:16;;;19893:51;19961:18;;7045:58:11::2;19640:345:16::0;7045:58:11::2;7114:44;7137:20;1564:26:13::0;:38;1494:115;920:261:11;10285:10;10274:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;10274:7:11;-1:-1:-1;;;;;10274:21:11;;10266:54;;;;-1:-1:-1;;;10266:54:11;;;;;;;:::i;:::-;1051:8:::1;10631;10618:21;;:9;1281:6:10::0;1306:14;;;;1241:86;10618:9:11::1;:21;;;10610:45;;;;-1:-1:-1::0;;;10610:45:11::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;1079:22:11;::::2;1071:67;;;::::0;-1:-1:-1;;;1071:67:11;;25854:2:16;1071:67:11::2;::::0;::::2;25836:21:16::0;;;25873:18;;;25866:30;25932:34;25912:18;;;25905:62;25984:18;;1071:67:11::2;25652:356:16::0;1071:67:11::2;1149:25;1165:8;1149:15;:25::i;451:391:12:-:0;554:20;593:8;:18;;;:23;;615:1;593:23;585:53;;;;-1:-1:-1;;;585:53:12;;25157:2:16;585:53:12;;;25139:21:16;25196:2;25176:18;;;25169:30;-1:-1:-1;;;25215:18:16;;;25208:47;25272:18;;585:53:12;24955:341:16;585:53:12;688:18;;720:25;;;;;759:28;;;;;801:24;;;;658:177;;;;688:18;759:28;;801:24;658:177;26260:3:16;26238:16;;;;-1:-1:-1;;;;;;26234:36:16;26222:49;;26296:1;26287:11;;26280:27;;;;26332:2;26323:12;;26316:28;26369:2;26360:12;;26353:28;26406:2;26397:12;;26013:402;658:177:12;;;;;;;;;;;;;648:187;;451:391;;;:::o;1329:159:11:-;10285:10;10274:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;10274:7:11;-1:-1:-1;;;;;10274:21:11;;10266:54;;;;-1:-1:-1;;;10266:54:11;;;;;;;:::i;:::-;1434:8:::1;10631;10618:21;;:9;1281:6:10::0;1306:14;;;;1241:86;10618:9:11::1;:21;;;10610:45;;;;-1:-1:-1::0;;;10610:45:11::1;;;;;;;:::i;:::-;1454:27:::2;1478:1;1454:15;:27::i;2440:375:10:-:0;2500:7;2554:18;;-1:-1:-1;;;;;;;;2554:18:10;;;;;2404:23;;:16;:23;;;;;;;;;;;;;;;2672:1;2654:15;:19;:40;;;;;2693:1;2677:13;:17;2654:40;2633:104;;;;-1:-1:-1;;;2633:104:10;;20936:2:16;2633:104:10;;;20918:21:16;20975:2;20955:18;;;20948:30;-1:-1:-1;;;20994:18:16;;;20987:47;21051:18;;2633:104:10;20734:341:16;2633:104:10;2795:13;2777:15;2755:19;1656:24;;;1580:107;2755:19;:37;;;;:::i;:::-;:53;;;;:::i;5253:217:11:-;10285:10;10274:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;10274:7:11;-1:-1:-1;;;;;10274:21:11;;10266:54;;;;-1:-1:-1;;;10266:54:11;;;;;;;:::i;:::-;5364:8:::1;10631;10618:21;;:9;1281:6:10::0;1306:14;;;;1241:86;10618:9:11::1;:21;;;10610:45;;;;-1:-1:-1::0;;;10610:45:11::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;5392:19:11;::::2;5384:45;;;::::0;-1:-1:-1;;;5384:45:11;;14427:2:16;5384:45:11::2;::::0;::::2;14409:21:16::0;14466:2;14446:18;;;14439:30;-1:-1:-1;;;14485:18:16;;;14478:43;14538:18;;5384:45:11::2;14225:337:16::0;5384:45:11::2;5440:23;5457:5;5440:16;:23::i;24257:705:9:-:0;24341:18;24432:19;24454:18;24466:5;24454:11;:18::i;:::-;24432:40;;24482:20;24505:28;24525:6;1083:5:10;1113:18;-1:-1:-1;;;;;;;;1113:18:10;;;;;1046:93;24505:28:9;24482:51;;24564:14;24548:30;;:13;:30;;;24544:412;;;1656:24:10;;24699:30:9;24715:14;24699:13;:30;:::i;:::-;24692:38;;:2;:38;:::i;:::-;24652:21;24667:5;24652:14;:21::i;:::-;-1:-1:-1;;;;;2278:33:10;;2252:7;2278:33;;;:26;:33;;;;;;24623:50:9;;;;:::i;:::-;:107;;;;:::i;:::-;:129;;;;:::i;:::-;24594:158;;24544:412;;;1656:24:10;;24891:30:9;24908:13;24891:14;:30;:::i;:::-;24884:38;;:2;:38;:::i;:::-;:60;;;;:::i;:::-;24842:21;24857:5;24842:14;:21::i;:::-;-1:-1:-1;;;;;2278:33:10;;2252:7;2278:33;;;:26;:33;;;;;;24813:26:9;2187:131:10;1818:121;1872:16;1907:6;:25;;1900:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1900:32:10;;;;;;;;;;;;;;;;;;;;;;;1818:121;:::o;2496:341:11:-;10285:10;10274:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;10274:7:11;-1:-1:-1;;;;;10274:21:11;;10266:54;;;;-1:-1:-1;;;10266:54:11;;;;;;;:::i;:::-;2621:8:::1;10631;10618:21;;:9;1281:6:10::0;1306:14;;;;1241:86;10618:9:11::1;:21;;;10610:45;;;;-1:-1:-1::0;;;10610:45:11::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;2662:26:11;::::2;2641:109;;;::::0;-1:-1:-1;;;2641:109:11;;26622:2:16;2641:109:11::2;::::0;::::2;26604:21:16::0;26661:2;26641:18;;;26634:30;26700:34;26680:18;;;26673:62;-1:-1:-1;;;26751:18:16;;;26744:34;26795:19;;2641:109:11::2;26420:400:16::0;2641:109:11::2;454:21:13::0;:39;;-1:-1:-1;;;;;;454:39:13;-1:-1:-1;;;;;454:39:13;;;;;10330:1:11::1;5734:222:::0;;:::o;9407:281::-;10285:10;10274:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;10274:7:11;-1:-1:-1;;;;;10274:21:11;;10266:54;;;;-1:-1:-1;;;10266:54:11;;;;;;;:::i;:::-;9557:8:::1;10631;10618:21;;:9;1281:6:10::0;1306:14;;;;1241:86;10618:9:11::1;:21;;;10610:45;;;;-1:-1:-1::0;;;10610:45:11::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;1777:28:10;;1754:4;1777:28;;;:21;:28;;;;;;;;9577:53:11::2;;;;-1:-1:-1::0;;;9577:53:11::2;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;3259:33:13;;:6;:33;;;:26;:33;;;;;:43;;;9641:40:11::2;10330:1:::1;9407:281:::0;;;:::o;1888:1043:13:-;-1:-1:-1;;;;;1972:28:13;;:6;:28;;;:21;:28;;;;;;;;1951:95;;;;-1:-1:-1;;;1951:95:13;;27027:2:16;1951:95:13;;;27009:21:16;27066:2;27046:18;;;27039:30;-1:-1:-1;;;27085:18:16;;;27078:50;27145:18;;1951:95:13;26825:344:16;1951:95:13;-1:-1:-1;;;;;2185:28:13;;2216:5;2185:28;;;:21;:28;;;;;;;;:36;;-1:-1:-1;;2185:36:13;;;2231:16;:23;;;;;:27;;;2268:26;:33;;;;;:37;;;2364:25;:32;;2549:160;2560:7;2556:1;:11;2549:160;;;2620:5;-1:-1:-1;;;;;2588:37:13;:6;:25;;2614:1;2588:28;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;2588:28:13;2584:81;2645:5;2584:81;2695:1;2690:6;2549:160;;;2728:7;2723:1;:12;2719:206;;2765:1;2755:7;:11;2751:119;;;2817:25;2843:11;2853:1;2843:7;:11;:::i;:::-;2817:38;;;;;;;;:::i;:::-;;;;;;;;;;;2786:25;:28;;-1:-1:-1;;;;;2817:38:13;;;;2812:1;;2786:28;;;;;;:::i;:::-;;;;;;;;;:69;;;;;-1:-1:-1;;;;;2786:69:13;;;;;-1:-1:-1;;;;;2786:69:13;;;;;;2751:119;2883:25;:31;;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;;2883:31:13;;;;;-1:-1:-1;;;;;;2883:31:13;;;;;;1941:990;;1888:1043;:::o;268:109::-;335:19;:35;;-1:-1:-1;;;;;;335:35:13;-1:-1:-1;;;;;335:35:13;;;;;;;;;;268:109::o;2336:287:0:-;1759:1;2468:7;;:19;2460:63;;;;-1:-1:-1;;;2460:63:0;;27508:2:16;2460:63:0;;;27490:21:16;27547:2;27527:18;;;27520:30;27586:33;27566:18;;;27559:61;27637:18;;2460:63:0;27306:355:16;2460:63:0;1759:1;2598:7;:18;2336:287::o;3277:247:10:-;3417:37;;;;;;;;;;;;;;;;-1:-1:-1;;;;;3417:37:10;-1:-1:-1;;;3417:37:10;;;3387:77;;3336:5;;;;-1:-1:-1;;;;;3387:16:10;;;:77;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3353:111;;;3492:15;3481:36;;;;;;;;;;;;:::i;:::-;3474:43;3277:247;-1:-1:-1;;;3277:247:10:o;26988:475:9:-;27082:7;27152:21;27176:17;27187:5;27176:10;:17::i;:::-;27152:41;;27230:134;27277:5;27297:10;27329:4;27348:6;27230:26;:134::i;:::-;27443:13;27423:17;27434:5;27423:10;:17::i;:::-;:33;;;;:::i;:::-;27416:40;26988:475;-1:-1:-1;;;;26988:475:9:o;7833:3667::-;8091:12;;-1:-1:-1;;;;;1777:28:10;7990:22:9;1777:28:10;;;:21;:28;;;;;;;;8067:60:9;;;;-1:-1:-1;;;8067:60:9;;;;;;;:::i;:::-;8158:22;;;;8137:119;;;;-1:-1:-1;;;8137:119:9;;28551:2:16;8137:119:9;;;28533:21:16;28590:2;28570:18;;;28563:30;28629:34;28609:18;;;28602:62;-1:-1:-1;;;28680:18:16;;;28673:34;28724:19;;8137:119:9;28349:400:16;8137:119:9;8491:24;8518:86;8547:6;:13;;;8574:6;:20;;;8518:15;:86::i;:::-;8491:113;;8641:1;8622:16;:20;8614:62;;;;-1:-1:-1;;;8614:62:9;;28956:2:16;8614:62:9;;;28938:21:16;28995:2;28975:18;;;28968:30;29034:31;29014:18;;;29007:59;29083:18;;8614:62:9;28754:353:16;8614:62:9;8747:37;8787:99;8816:6;:26;;;8856:6;:20;;;8787:15;:99::i;:::-;8747:139;;8917:6;:26;;;8947:1;8917:31;:68;;;;8984:1;8952:29;:33;8917:68;8896:142;;;;-1:-1:-1;;;8896:142:9;;29314:2:16;8896:142:9;;;29296:21:16;29353:2;29333:18;;;29326:30;29392:29;29372:18;;;29365:57;29439:18;;8896:142:9;29112:351:16;8896:142:9;9230:18;;;;1525:42:10;;9183:22:9;1525:42:10;;;:26;:42;;;;;;;9259:62:9;;;;-1:-1:-1;;;9259:62:9;;29670:2:16;9259:62:9;;;29652:21:16;29709:2;29689:18;;;29682:30;-1:-1:-1;;;29728:18:16;;;29721:51;29789:18;;9259:62:9;29468:345:16;9259:62:9;9472:28;9503:210;9532:137;9569:6;:18;;;9605:6;:12;;;9635:6;:20;;;9532:19;:137::i;:::-;9683:6;:20;;;9503:15;:210::i;:::-;9472:241;-1:-1:-1;9763:52:9;9786:29;9472:241;9763:52;:::i;:::-;9744:16;:71;9723:137;;;;-1:-1:-1;;;9723:137:9;;30020:2:16;9723:137:9;;;30002:21:16;30059:2;30039:18;;;30032:30;-1:-1:-1;;;30078:18:16;;;30071:49;30137:18;;9723:137:9;29818:343:16;9723:137:9;10328:27;10358:291;10395:244;;;;;;;;10442:1;10395:244;;;;;;10479:20;10395:244;;;;10538:29;10395:244;;;;10602:6;:22;;;10395:244;;;10358:23;:291::i;:::-;10328:321;;10698:19;10720:13;1013:18:10;;-1:-1:-1;;;;;1013:18:10;;917:123;10720:13:9;10698:35;;10810:121;10852:6;:12;;;10887:6;10908;:13;;;10810:21;:121::i;:::-;11269:6;-1:-1:-1;;;;;11269:32:9;;11309:11;11335:6;:12;;;11361:6;:13;;;11388:6;:18;;;11420:14;11448:7;11469:14;11269:224;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;14814:320:8:-;14893:7;14937:11;:6;14946:2;14937:11;:::i;:::-;14920:6;:13;:28;;14912:62;;;;-1:-1:-1;;;14912:62:8;;31392:2:16;14912:62:8;;;31374:21:16;31431:2;31411:18;;;31404:30;-1:-1:-1;;;31450:18:16;;;31443:51;31511:18;;14912:62:8;31190:345:16;14912:62:8;-1:-1:-1;15058:30:8;15074:4;15058:30;15052:37;;14814:320::o;12935:305::-;13013:6;13056:10;:6;13065:1;13056:10;:::i;:::-;13039:6;:13;:27;;13031:60;;;;-1:-1:-1;;;13031:60:8;;31742:2:16;13031:60:8;;;31724:21:16;31781:2;31761:18;;;31754:30;-1:-1:-1;;;31800:18:16;;;31793:50;31860:18;;13031:60:8;31540:344:16;13031:60:8;-1:-1:-1;13168:29:8;13184:3;13168:29;13162:36;;12935:305::o;27469:199:9:-;27536:7;-1:-1:-1;;;;;;27563:22:9;;;27555:54;;;;-1:-1:-1;;;27555:54:9;;32091:2:16;27555:54:9;;;32073:21:16;32130:2;32110:18;;;32103:30;-1:-1:-1;;;32149:18:16;;;32142:49;32208:18;;27555:54:9;31889:343:16;27555:54:9;-1:-1:-1;27650:8:9;27469:199::o;17676:2765::-;17772:12;17786:7;17795;18223:33;18259:10;888:15:10;;-1:-1:-1;;;;;888:15:10;;809:102;18259:10:9;-1:-1:-1;;;;;18259:18:9;;18291:22;18259:64;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;18259:64:9;;;;;;;;;;;;:::i;:::-;18223:100;;18728:25;18756:81;18806:13;:21;;;18756:36;:81::i;:::-;18728:109;;18855:34;18871:17;-1:-1:-1;;;;;1777:28:10;1754:4;1777:28;;;:21;:28;;;;;;;;;1693:119;18855:34:9;18847:67;;;;-1:-1:-1;;;18847:67:9;;27027:2:16;18847:67:9;;;27009:21:16;27066:2;27046:18;;;27039:30;-1:-1:-1;;;27085:18:16;;;27078:50;27145:18;;18847:67:9;26825:344:16;18847:67:9;18981:21;19005:29;19016:17;19005:10;:29::i;:::-;18981:53;;19088:19;19110:13;1013:18:10;;-1:-1:-1;;;;;1013:18:10;;917:123;19110:13:9;19088:35;;19356:28;19387:6;-1:-1:-1;;;;;19387:34:9;;19435:22;19387:80;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;19387:80:9;;;;;;;;;;;;:::i;:::-;19356:111;;19559:22;19616:13;19584:29;19595:17;19584:10;:29::i;:::-;:45;;;;:::i;:::-;19559:70;;19724:48;19787:6;-1:-1:-1;;;;;19787:31:9;;19819:15;19787:48;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;19787:48:9;;;;;;;;;;;;:::i;:::-;19724:111;;19978:51;20000:13;:28;;;1525:42:10;;1499:7;1525:42;;;:26;:42;;;;;;;1424:150;19978:51:9;19954:8;:20;;;:75;19933:145;;;;-1:-1:-1;;;19933:145:9;;37377:2:16;19933:145:9;;;37359:21:16;37416:2;37396:18;;;37389:30;37455:25;37435:18;;;37428:53;37498:18;;19933:145:9;37175:347:16;19933:145:9;20285:13;:22;;;-1:-1:-1;;;;;20171:146:9;20243:13;:28;;;20201:13;:28;;;20171:146;;;;;;;;;;;;20349:16;;;;20379:14;;-1:-1:-1;20407:17:9;;-1:-1:-1;17676:2765:9;;-1:-1:-1;;;;;;17676:2765:9:o;20447:752::-;20673:9;:14;20665:62;;;;-1:-1:-1;;;20665:62:9;;37729:2:16;20665:62:9;;;37711:21:16;37768:2;37748:18;;;37741:30;37807:34;37787:18;;;37780:62;-1:-1:-1;;;37858:18:16;;;37851:33;37901:19;;20665:62:9;37527:399:16;20665:62:9;20769:10;1113:18:10;-1:-1:-1;;;;;;;;1113:18:10;;;;;;20856:22:9;;;;:36;;;;;20882:10;20856:36;20852:341;;;20963:21;;-1:-1:-1;;;20963:21:9;;;;;2385:25:16;;;-1:-1:-1;;;;;20963:13:9;;;;;2358:18:16;;20963:21:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;20998:35:9;;-1:-1:-1;;;;;20998:27:9;;;-1:-1:-1;20998:35:9;;;;;-1:-1:-1;21026:6:9;;20998:35;;;;21026:6;20998:27;:35;;;;;;;;;;;;;;;;;;;;;20852:341;;;21064:118;21111:5;21135:9;21162:6;21064:22;:118::i;:::-;20594:605;20447:752;;;;:::o;21205:1416::-;21435:9;:14;21427:45;;;;-1:-1:-1;;;21427:45:9;;38133:2:16;21427:45:9;;;38115:21:16;38172:2;38152:18;;;38145:30;-1:-1:-1;;;38191:18:16;;;38184:48;38249:18;;21427:45:9;37931:342:16;21427:45:9;21686:10;21682:933;;;1083:5:10;1113:18;21740:23:9;;-1:-1:-1;;;21740:23:9;;;;;2385:25:16;;;-1:-1:-1;;;1113:18:10;;;-1:-1:-1;;;;;1113:18:10;;21740:15:9;;2358:18:16;;21740:23:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21827:9;-1:-1:-1;;;;;21819:27:9;:48;21856:10;21847:6;:19;;;;:::i;:::-;21819:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;21943:14:9;;21939:97;;777:19:10;;21977:44:9;;-1:-1:-1;;;;;777:19:10;;;;21977:44:9;;;;;22010:10;;21977:44;;;;22010:10;777:19:10;21977:44:9;;;;;;;;;;;;;;;;;;;;;21939:97;21682:933;;;22101:10;1113:18:10;-1:-1:-1;;;1113:18:10;;-1:-1:-1;;;;;1113:18:10;22190:139:9;1113:18:10;22269:9:9;22296:19;22305:10;22296:6;:19;:::i;22190:139::-;22405:14;;22401:204;;22439:151;22498:4;22526:14;777:19:10;;-1:-1:-1;;;;;777:19:10;;706:97;22526:14:9;22562:10;763:205:3;902:58;;-1:-1:-1;;;;;38470:32:16;;902:58:3;;;38452:51:16;38519:18;;;38512:34;;;875:86:3;;895:5;;-1:-1:-1;;;925:23:3;38425:18:16;;902:58:3;;;;-1:-1:-1;;902:58:3;;;;;;;;;;;;;;-1:-1:-1;;;;;902:58:3;-1:-1:-1;;;;;;902:58:3;;;;;;;;;;875:19;:86::i;12627:302:8:-;12704:5;12746:10;:6;12755:1;12746:10;:::i;:::-;12729:6;:13;:27;;12721:60;;;;-1:-1:-1;;;12721:60:8;;38759:2:16;12721:60:8;;;38741:21:16;38798:2;38778:18;;;38771:30;-1:-1:-1;;;38817:18:16;;;38810:49;38876:18;;12721:60:8;38557:343:16;12721:60:8;-1:-1:-1;12857:29:8;12873:3;12857:29;12851:36;;12627:302::o;14497:311::-;14576:7;14620:11;:6;14629:2;14620:11;:::i;:::-;14603:6;:13;:28;;14595:62;;;;-1:-1:-1;;;14595:62:8;;39107:2:16;14595:62:8;;;39089:21:16;39146:2;39126:18;;;39119:30;-1:-1:-1;;;39165:18:16;;;39158:51;39226:18;;14595:62:8;38905:345:16;1615:267:13;-1:-1:-1;;;;;1696:28:13;;:6;:28;;;:21;:28;;;;;;;;:37;1675:108;;;;-1:-1:-1;;;1675:108:13;;39457:2:16;1675:108:13;;;39439:21:16;39496:2;39476:18;;;39469:30;39535:26;39515:18;;;39508:54;39579:18;;1675:108:13;39255:348:16;1675:108:13;-1:-1:-1;;;;;1793:28:13;:6;:28;;;:21;:28;;;;;:35;;-1:-1:-1;;1793:35:13;1824:4;1793:35;;;;;;1838:25;:37;;;;;;;;;;;;;;-1:-1:-1;;;;;;1838:37:13;;;;;;1615:267::o;3530:370:10:-;3758:64;;;3816:4;3758:64;;;;5837:51:16;;;;3758:64:10;;;;;;;;;;5810:18:16;;;;3758:64:10;;;;;;;-1:-1:-1;;;;;3758:64:10;-1:-1:-1;;;3758:64:10;;;3724:112;;3588:15;;;;-1:-1:-1;;;;;3724:16:10;;;:112;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3678:158;;;3867:14;3856:37;;;;;;;;;;;;:::i;974:241:3:-;1139:68;;-1:-1:-1;;;;;39866:15:16;;;1139:68:3;;;39848:34:16;39918:15;;39898:18;;;39891:43;39950:18;;;39943:34;;;1112:96:3;;1132:5;;-1:-1:-1;;;1162:27:3;39783:18:16;;1139:68:3;39608:375:16;1475:603:3;1830:10;;;1829:62;;-1:-1:-1;1846:39:3;;-1:-1:-1;;;1846:39:3;;1870:4;1846:39;;;40200:34:16;-1:-1:-1;;;;;40270:15:16;;;40250:18;;;40243:43;1846:15:3;;;;;40135:18:16;;1846:39:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;1829:62;1808:163;;;;-1:-1:-1;;;1808:163:3;;40499:2:16;1808:163:3;;;40481:21:16;40538:2;40518:18;;;40511:30;40577:34;40557:18;;;40550:62;-1:-1:-1;;;40628:18:16;;;40621:52;40690:19;;1808:163:3;40297:418:16;1808:163:3;2008:62;;-1:-1:-1;;;;;38470:32:16;;2008:62:3;;;38452:51:16;38519:18;;;38512:34;;;1981:90:3;;2001:5;;-1:-1:-1;;;2031:22:3;38425:18:16;;2008:62:3;38278:274:16;3747:706:3;4166:23;4192:69;4220:4;4192:69;;;;;;;;;;;;;;;;;4200:5;-1:-1:-1;;;;;4192:27:3;;;:69;;;;;:::i;:::-;4275:17;;4166:95;;-1:-1:-1;4275:21:3;4271:176;;4370:10;4359:30;;;;;;;;;;;;:::i;:::-;4351:85;;;;-1:-1:-1;;;4351:85:3;;41172:2:16;4351:85:3;;;41154:21:16;41211:2;41191:18;;;41184:30;41250:34;41230:18;;;41223:62;-1:-1:-1;;;41301:18:16;;;41294:40;41351:19;;4351:85:3;40970:406:16;3873:223:4;4006:12;4037:52;4059:6;4067:4;4073:1;4076:12;4006;5241;5255:23;5282:6;-1:-1:-1;;;;;5282:11:4;5301:5;5308:4;5282:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5240:73;;;;5330:69;5357:6;5365:7;5374:10;5386:12;5330:26;:69::i;:::-;5323:76;4960:446;-1:-1:-1;;;;;;;4960:446:4:o;7466:628::-;7646:12;7674:7;7670:418;;;7701:10;:17;7722:1;7701:22;7697:286;;-1:-1:-1;;;;;1465:19:4;;;7908:60;;;;-1:-1:-1;;;7908:60:4;;41990:2:16;7908:60:4;;;41972:21:16;42029:2;42009:18;;;42002:30;42068:31;42048:18;;;42041:59;42117:18;;7908:60:4;41788:353:16;7908:60:4;-1:-1:-1;8003:10:4;7996:17;;7670:418;8044:33;8052:10;8064:12;8775:17;;:21;8771:379;;9003:10;8997:17;9059:15;9046:10;9042:2;9038:19;9031:44;8771:379;9126:12;9119:20;;-1:-1:-1;;;9119:20:4;;;;;;;;:::i;14:117:16:-;99:6;92:5;88:18;81:5;78:29;68:57;;121:1;118;111:12;68:57;14:117;:::o;136:131::-;-1:-1:-1;;;;;211:31:16;;201:42;;191:70;;257:1;254;247:12;272:386;339:6;347;400:2;388:9;379:7;375:23;371:32;368:52;;;416:1;413;406:12;368:52;455:9;442:23;474:30;498:5;474:30;:::i;:::-;523:5;-1:-1:-1;580:2:16;565:18;;552:32;593:33;552:32;593:33;:::i;:::-;645:7;635:17;;;272:386;;;;;:::o;663:121::-;748:10;741:5;737:22;730:5;727:33;717:61;;774:1;771;764:12;789:732;891:6;899;907;915;923;931;984:3;972:9;963:7;959:23;955:33;952:53;;;1001:1;998;991:12;952:53;1040:9;1027:23;1059:31;1084:5;1059:31;:::i;:::-;1109:5;-1:-1:-1;1161:2:16;1146:18;;1133:32;;-1:-1:-1;1212:2:16;1197:18;;1184:32;;-1:-1:-1;1268:2:16;1253:18;;1240:32;1281;1240;1281;:::i;:::-;1332:7;-1:-1:-1;1386:3:16;1371:19;;1358:33;;-1:-1:-1;1443:3:16;1428:19;;1415:33;1457:32;1415:33;1457:32;:::i;:::-;1508:7;1498:17;;;789:732;;;;;;;;:::o;1731:118::-;1817:5;1810:13;1803:21;1796:5;1793:32;1783:60;;1839:1;1836;1829:12;1854:380;1918:6;1926;1979:2;1967:9;1958:7;1954:23;1950:32;1947:52;;;1995:1;1992;1985:12;1947:52;2034:9;2021:23;2053:30;2077:5;2053:30;:::i;:::-;2102:5;-1:-1:-1;2159:2:16;2144:18;;2131:32;2172:30;2131:32;2172:30;:::i;2421:114::-;2505:4;2498:5;2494:16;2487:5;2484:27;2474:55;;2525:1;2522;2515:12;2540:311;2606:6;2614;2667:2;2655:9;2646:7;2642:23;2638:32;2635:52;;;2683:1;2680;2673:12;2635:52;2719:9;2706:23;2696:33;;2779:2;2768:9;2764:18;2751:32;2792:29;2815:5;2792:29;:::i;2856:521::-;2940:6;2948;2956;2964;3017:3;3005:9;2996:7;2992:23;2988:33;2985:53;;;3034:1;3031;3024:12;2985:53;3070:9;3057:23;3047:33;;3130:2;3119:9;3115:18;3102:32;3143:30;3167:5;3143:30;:::i;:::-;3192:5;-1:-1:-1;3244:2:16;3229:18;;3216:32;;-1:-1:-1;3300:2:16;3285:18;;3272:32;3313;3272;3313;:::i;:::-;2856:521;;;;-1:-1:-1;2856:521:16;;-1:-1:-1;;2856:521:16:o;3382:247::-;3441:6;3494:2;3482:9;3473:7;3469:23;3465:32;3462:52;;;3510:1;3507;3500:12;3462:52;3549:9;3536:23;3568:31;3593:5;3568:31;:::i;3634:127::-;3695:10;3690:3;3686:20;3683:1;3676:31;3726:4;3723:1;3716:15;3750:4;3747:1;3740:15;3766:253;3838:2;3832:9;3880:4;3868:17;;-1:-1:-1;;;;;3900:34:16;;3936:22;;;3897:62;3894:88;;;3962:18;;:::i;:::-;3998:2;3991:22;3766:253;:::o;4024:255::-;4096:2;4090:9;4138:6;4126:19;;-1:-1:-1;;;;;4160:34:16;;4196:22;;;4157:62;4154:88;;;4222:18;;:::i;4284:255::-;4356:2;4350:9;4398:6;4386:19;;-1:-1:-1;;;;;4420:34:16;;4456:22;;;4417:62;4414:88;;;4482:18;;:::i;4544:275::-;4615:2;4609:9;4680:2;4661:13;;-1:-1:-1;;4657:27:16;4645:40;;-1:-1:-1;;;;;4700:34:16;;4736:22;;;4697:62;4694:88;;;4762:18;;:::i;:::-;4798:2;4791:22;4544:275;;-1:-1:-1;4544:275:16:o;4824:186::-;4872:4;-1:-1:-1;;;;;4897:6:16;4894:30;4891:56;;;4927:18;;:::i;:::-;-1:-1:-1;4993:2:16;4972:15;-1:-1:-1;;4968:29:16;4999:4;4964:40;;4824:186::o;5015:671::-;5083:6;5136:2;5124:9;5115:7;5111:23;5107:32;5104:52;;;5152:1;5149;5142:12;5104:52;5192:9;5179:23;-1:-1:-1;;;;;5217:6:16;5214:30;5211:50;;;5257:1;5254;5247:12;5211:50;5280:22;;5333:4;5325:13;;5321:27;-1:-1:-1;5311:55:16;;5362:1;5359;5352:12;5311:55;5398:2;5385:16;5423:48;5439:31;5467:2;5439:31;:::i;:::-;5423:48;:::i;:::-;5494:2;5487:5;5480:17;5534:7;5529:2;5524;5520;5516:11;5512:20;5509:33;5506:53;;;5555:1;5552;5545:12;5506:53;5610:2;5605;5601;5597:11;5592:2;5585:5;5581:14;5568:45;5654:1;5633:14;;;5649:2;5629:23;5622:34;;;;5637:5;5015:671;-1:-1:-1;;;;5015:671:16:o;5899:313::-;5966:6;5974;6027:2;6015:9;6006:7;6002:23;5998:32;5995:52;;;6043:1;6040;6033:12;5995:52;6082:9;6069:23;6101:30;6125:5;6101:30;:::i;:::-;6150:5;6202:2;6187:18;;;;6174:32;;-1:-1:-1;;;5899:313:16:o;6217:591::-;6287:6;6295;6348:2;6336:9;6327:7;6323:23;6319:32;6316:52;;;6364:1;6361;6354:12;6316:52;6404:9;6391:23;-1:-1:-1;;;;;6474:2:16;6466:6;6463:14;6460:34;;;6490:1;6487;6480:12;6460:34;6528:6;6517:9;6513:22;6503:32;;6573:7;6566:4;6562:2;6558:13;6554:27;6544:55;;6595:1;6592;6585:12;6544:55;6635:2;6622:16;6661:2;6653:6;6650:14;6647:34;;;6677:1;6674;6667:12;6647:34;6722:7;6717:2;6708:6;6704:2;6700:15;6696:24;6693:37;6690:57;;;6743:1;6740;6733:12;6690:57;6774:2;6766:11;;;;;6796:6;;-1:-1:-1;6217:591:16;;-1:-1:-1;;;;6217:591:16:o;6813:523::-;6887:6;6895;6903;6956:2;6944:9;6935:7;6931:23;6927:32;6924:52;;;6972:1;6969;6962:12;6924:52;7011:9;6998:23;7030:30;7054:5;7030:30;:::i;:::-;7079:5;-1:-1:-1;7136:2:16;7121:18;;7108:32;7149:33;7108:32;7149:33;:::i;:::-;7201:7;-1:-1:-1;7260:2:16;7245:18;;7232:32;7273:31;7232:32;7273:31;:::i;:::-;7323:7;7313:17;;;6813:523;;;;;:::o;7533:245::-;7591:6;7644:2;7632:9;7623:7;7619:23;7615:32;7612:52;;;7660:1;7657;7650:12;7612:52;7699:9;7686:23;7718:30;7742:5;7718:30;:::i;8283:782::-;8411:6;8419;8427;8480:2;8468:9;8459:7;8455:23;8451:32;8448:52;;;8496:1;8493;8486:12;8448:52;8535:9;8522:23;8554:30;8578:5;8554:30;:::i;:::-;8603:5;-1:-1:-1;8659:2:16;8644:18;;8631:32;-1:-1:-1;;;;;8712:14:16;;;8709:34;;;8739:1;8736;8729:12;8709:34;8777:6;8766:9;8762:22;8752:32;;8822:7;8815:4;8811:2;8807:13;8803:27;8793:55;;8844:1;8841;8834:12;8793:55;8884:2;8871:16;8910:2;8902:6;8899:14;8896:34;;;8926:1;8923;8916:12;8896:34;8979:7;8974:2;8964:6;8961:1;8957:14;8953:2;8949:23;8945:32;8942:45;8939:65;;;9000:1;8997;8990:12;8939:65;9031:2;9027;9023:11;9013:21;;9053:6;9043:16;;;;;8283:782;;;;;:::o;9756:315::-;9824:6;9832;9885:2;9873:9;9864:7;9860:23;9856:32;9853:52;;;9901:1;9898;9891:12;9853:52;9940:9;9927:23;9959:31;9984:5;9959:31;:::i;10269:713::-;10363:6;10416:3;10404:9;10395:7;10391:23;10387:33;10384:53;;;10433:1;10430;10423:12;10384:53;10466:2;10460:9;10508:3;10500:6;10496:16;10578:6;10566:10;10563:22;-1:-1:-1;;;;;10530:10:16;10527:34;10524:62;10521:88;;;10589:18;;:::i;:::-;10625:2;10618:22;10662:23;;10694:29;10662:23;10694:29;:::i;:::-;10747:5;10739:6;10732:21;;10814:2;10803:9;10799:18;10786:32;10781:2;10773:6;10769:15;10762:57;10880:2;10869:9;10865:18;10852:32;10847:2;10839:6;10835:15;10828:57;10946:2;10935:9;10931:18;10918:32;10913:2;10905:6;10901:15;10894:57;10970:6;10960:16;;;10269:713;;;;:::o;10987:250::-;11072:1;11082:113;11096:6;11093:1;11090:13;11082:113;;;11172:11;;;11166:18;11153:11;;;11146:39;11118:2;11111:10;11082:113;;;-1:-1:-1;;11229:1:16;11211:16;;11204:27;10987:250::o;11242:270::-;11283:3;11321:5;11315:12;11348:6;11343:3;11336:19;11364:76;11433:6;11426:4;11421:3;11417:14;11410:4;11403:5;11399:16;11364:76;:::i;:::-;11494:2;11473:15;-1:-1:-1;;11469:29:16;11460:39;;;;11501:4;11456:50;;11242:270;-1:-1:-1;;11242:270:16:o;11517:217::-;11664:2;11653:9;11646:21;11627:4;11684:44;11724:2;11713:9;11709:18;11701:6;11684:44;:::i;12190:658::-;12361:2;12413:21;;;12483:13;;12386:18;;;12505:22;;;12332:4;;12361:2;12584:15;;;;12558:2;12543:18;;;12332:4;12627:195;12641:6;12638:1;12635:13;12627:195;;;12706:13;;-1:-1:-1;;;;;12702:39:16;12690:52;;12797:15;;;;12762:12;;;;12738:1;12656:9;12627:195;;;-1:-1:-1;12839:3:16;;12190:658;-1:-1:-1;;;;;;12190:658:16:o;13077:454::-;13153:6;13161;13169;13222:2;13210:9;13201:7;13197:23;13193:32;13190:52;;;13238:1;13235;13228:12;13190:52;13277:9;13264:23;13296:30;13320:5;13296:30;:::i;:::-;13345:5;-1:-1:-1;13402:2:16;13387:18;;13374:32;13415:33;13374:32;13415:33;:::i;:::-;13077:454;;13467:7;;-1:-1:-1;;;13521:2:16;13506:18;;;;13493:32;;13077:454::o;13536:344::-;13738:2;13720:21;;;13777:2;13757:18;;;13750:30;-1:-1:-1;;;13811:2:16;13796:18;;13789:50;13871:2;13856:18;;13536:344::o;13885:335::-;14087:2;14069:21;;;14126:2;14106:18;;;14099:30;-1:-1:-1;;;14160:2:16;14145:18;;14138:41;14211:2;14196:18;;13885:335::o;15269:184::-;15339:6;15392:2;15380:9;15371:7;15367:23;15363:32;15360:52;;;15408:1;15405;15398:12;15360:52;-1:-1:-1;15431:16:16;;15269:184;-1:-1:-1;15269:184:16:o;16213:127::-;16274:10;16269:3;16265:20;16262:1;16255:31;16305:4;16302:1;16295:15;16329:4;16326:1;16319:15;16345:151;16435:4;16428:12;;;16414;;;16410:31;;16453:14;;16450:40;;;16470:18;;:::i;16501:422::-;16590:1;16633:5;16590:1;16647:270;16668:7;16658:8;16655:21;16647:270;;;16727:4;16723:1;16719:6;16715:17;16709:4;16706:27;16703:53;;;16736:18;;:::i;:::-;16786:7;16776:8;16772:22;16769:55;;;16806:16;;;;16769:55;16885:22;;;;16845:15;;;;16647:270;;;16651:3;16501:422;;;;;:::o;16928:806::-;16977:5;17007:8;16997:80;;-1:-1:-1;17048:1:16;17062:5;;16997:80;17096:4;17086:76;;-1:-1:-1;17133:1:16;17147:5;;17086:76;17178:4;17196:1;17191:59;;;;17264:1;17259:130;;;;17171:218;;17191:59;17221:1;17212:10;;17235:5;;;17259:130;17296:3;17286:8;17283:17;17280:43;;;17303:18;;:::i;:::-;-1:-1:-1;;17359:1:16;17345:16;;17374:5;;17171:218;;17473:2;17463:8;17460:16;17454:3;17448:4;17445:13;17441:36;17435:2;17425:8;17422:16;17417:2;17411:4;17408:12;17404:35;17401:77;17398:159;;;-1:-1:-1;17510:19:16;;;17542:5;;17398:159;17589:34;17614:8;17608:4;17589:34;:::i;:::-;17659:6;17655:1;17651:6;17647:19;17638:7;17635:32;17632:58;;;17670:18;;:::i;:::-;17708:20;;16928:806;-1:-1:-1;;;16928:806:16:o;17739:140::-;17797:5;17826:47;17867:4;17857:8;17853:19;17847:4;17826:47;:::i;17884:217::-;17924:1;17950;17940:132;;17994:10;17989:3;17985:20;17982:1;17975:31;18029:4;18026:1;18019:15;18057:4;18054:1;18047:15;17940:132;-1:-1:-1;18086:9:16;;17884:217::o;18106:168::-;18179:9;;;18210;;18227:15;;;18221:22;;18207:37;18197:71;;18248:18;;:::i;18640:128::-;18707:9;;;18728:11;;;18725:37;;;18742:18;;:::i;19037:251::-;19107:6;19160:2;19148:9;19139:7;19135:23;19131:32;19128:52;;;19176:1;19173;19166:12;19128:52;19208:9;19202:16;19227:31;19252:5;19227:31;:::i;20604:125::-;20669:9;;;20690:10;;;20687:36;;;20703:18;;:::i;21896:397::-;22098:2;22080:21;;;22137:2;22117:18;;;22110:30;22176:34;22171:2;22156:18;;22149:62;-1:-1:-1;;;22242:2:16;22227:18;;22220:31;22283:3;22268:19;;21896:397::o;23338:127::-;23399:10;23394:3;23390:20;23387:1;23380:31;23430:4;23427:1;23420:15;23454:4;23451:1;23444:15;23470:342;23672:2;23654:21;;;23711:2;23691:18;;;23684:30;-1:-1:-1;;;23745:2:16;23730:18;;23723:48;23803:2;23788:18;;23470:342::o;24171:779::-;24408:3;24439;24486:6;24408:3;24520:403;24534:6;24531:1;24528:13;24520:403;;;24609:6;24596:20;24629:31;24654:5;24629:31;:::i;:::-;-1:-1:-1;;;;;24687:31:16;24673:46;;24742:4;24795:15;;;24782:29;24766:14;;;24759:53;24835:4;24861:14;;;;24898:15;;;;24715:1;24549:9;24520:403;;;-1:-1:-1;24939:5:16;;24171:779;-1:-1:-1;;;;;24171:779:16:o;27174:127::-;27235:10;27230:3;27226:20;27223:1;27216:31;27266:4;27263:1;27256:15;27290:4;27287:1;27280:15;27666:287;27795:3;27833:6;27827:13;27849:66;27908:6;27903:3;27896:4;27888:6;27884:17;27849:66;:::i;:::-;27931:16;;;;;27666:287;-1:-1:-1;;27666:287:16:o;27958:134::-;28035:13;;28057:29;28035:13;28057:29;:::i;:::-;27958:134;;;:::o;28097:247::-;28165:6;28218:2;28206:9;28197:7;28193:23;28189:32;28186:52;;;28234:1;28231;28224:12;28186:52;28266:9;28260:16;28285:29;28308:5;28285:29;:::i;30166:628::-;30478:1;30474;30469:3;30465:11;30461:19;30453:6;30449:32;30438:9;30431:51;30518:6;30513:2;30502:9;30498:18;30491:34;30573:6;30565;30561:19;30556:2;30545:9;30541:18;30534:47;30617:6;30612:2;30601:9;30597:18;30590:34;30673:10;30665:6;30661:23;30655:3;30644:9;30640:19;30633:52;30722:3;30716;30705:9;30701:19;30694:32;30412:4;30743:45;30783:3;30772:9;30768:19;30760:6;30743:45;:::i;:::-;30735:53;30166:628;-1:-1:-1;;;;;;;;30166:628:16:o;30799:175::-;30877:13;;-1:-1:-1;;;;;30919:30:16;;30909:41;;30899:69;;30964:1;30961;30954:12;30979:206;31048:6;31101:2;31089:9;31080:7;31076:23;31072:32;31069:52;;;31117:1;31114;31107:12;31069:52;31140:39;31169:9;31140:39;:::i;32237:136::-;32315:13;;32337:30;32315:13;32337:30;:::i;32378:136::-;32456:13;;32478:30;32456:13;32478:30;:::i;32519:441::-;32572:5;32625:3;32618:4;32610:6;32606:17;32602:27;32592:55;;32643:1;32640;32633:12;32592:55;32672:6;32666:13;32703:48;32719:31;32747:2;32719:31;:::i;32703:48::-;32776:2;32767:7;32760:19;32822:3;32815:4;32810:2;32802:6;32798:15;32794:26;32791:35;32788:55;;;32839:1;32836;32829:12;32788:55;32852:77;32926:2;32919:4;32910:7;32906:18;32899:4;32891:6;32887:17;32852:77;:::i;32965:1291::-;33039:5;33092:3;33085:4;33077:6;33073:17;33069:27;33059:55;;33110:1;33107;33100:12;33059:55;33139:6;33133:13;33165:4;-1:-1:-1;;;;;33184:2:16;33181:26;33178:52;;;33210:18;;:::i;:::-;33250:36;33282:2;33277;33274:1;33270:10;33266:19;33250:36;:::i;:::-;33320:15;;;33406:1;33402:10;;;;33390:23;;33386:32;;;33351:12;;;;33430:15;;;33427:35;;;33458:1;33455;33448:12;33427:35;33494:2;33486:6;33482:15;33506:721;33522:6;33517:3;33514:15;33506:721;;;33600:4;33594:3;33589;33585:13;33581:24;33578:114;;;33646:1;33675:2;33671;33664:14;33578:114;33718:22;;:::i;:::-;33773:3;33767:10;33760:5;33753:25;33829:2;33824:3;33820:12;33814:19;33809:2;33802:5;33798:14;33791:43;33857:2;33902;33897:3;33893:12;33887:19;33919:31;33942:7;33919:31;:::i;:::-;33970:14;;;33963:31;34017:2;34053:12;;;34047:19;34079:31;34047:19;34079:31;:::i;:::-;34130:14;;;34123:31;34167:18;;34205:12;;;;33548:4;33539:14;33506:721;;;-1:-1:-1;34245:5:16;32965:1291;-1:-1:-1;;;;;;32965:1291:16:o;34261:1502::-;34351:6;34404:2;34392:9;34383:7;34379:23;34375:32;34372:52;;;34420:1;34417;34410:12;34372:52;34453:9;34447:16;-1:-1:-1;;;;;34523:2:16;34515:6;34512:14;34509:34;;;34539:1;34536;34529:12;34509:34;34562:22;;;;34618:6;34600:16;;;34596:29;34593:49;;;34638:1;34635;34628:12;34593:49;34664:22;;:::i;:::-;34709:31;34737:2;34709:31;:::i;:::-;34702:5;34695:46;34773:41;34810:2;34806;34802:11;34773:41;:::i;:::-;34768:2;34761:5;34757:14;34750:65;34847:41;34884:2;34880;34876:11;34847:41;:::i;:::-;34842:2;34835:5;34831:14;34824:65;34921:41;34958:2;34954;34950:11;34921:41;:::i;:::-;34916:2;34909:5;34905:14;34898:65;35010:3;35006:2;35002:12;34996:19;34990:3;34983:5;34979:15;34972:44;35049:42;35086:3;35082:2;35078:12;35049:42;:::i;:::-;35043:3;35036:5;35032:15;35025:67;35125:41;35161:3;35157:2;35153:12;35125:41;:::i;:::-;35119:3;35112:5;35108:15;35101:66;35206:3;35202:2;35198:12;35192:19;35236:2;35226:8;35223:16;35220:36;;;35252:1;35249;35242:12;35220:36;35289:55;35336:7;35325:8;35321:2;35317:17;35289:55;:::i;:::-;35283:3;35276:5;35272:15;35265:80;;35364:3;35399:41;35436:2;35432;35428:11;35399:41;:::i;:::-;35383:14;;;35376:65;35460:3;35494:11;;;35488:18;35518:16;;;35515:36;;;35547:1;35544;35537:12;35515:36;35583:76;35651:7;35640:8;35636:2;35632:17;35583:76;:::i;:::-;35567:14;;;35560:100;;;;-1:-1:-1;35679:3:16;35720:11;;;35714:18;35698:14;;;35691:42;;;;-1:-1:-1;35571:5:16;34261:1502;-1:-1:-1;;;34261:1502:16:o;35768:335::-;35847:6;35900:2;35888:9;35879:7;35875:23;35871:32;35868:52;;;35916:1;35913;35906:12;35868:52;35949:9;35943:16;-1:-1:-1;;;;;35974:6:16;35971:30;35968:50;;;36014:1;36011;36004:12;35968:50;36037:60;36089:7;36080:6;36069:9;36065:22;36037:60;:::i;36108:1062::-;36214:6;36267:2;36255:9;36246:7;36242:23;36238:32;36235:52;;;36283:1;36280;36273:12;36235:52;36316:9;36310:16;-1:-1:-1;;;;;36386:2:16;36378:6;36375:14;36372:34;;;36402:1;36399;36392:12;36372:34;36425:22;;;;36481:6;36463:16;;;36459:29;36456:49;;;36501:1;36498;36491:12;36456:49;36527:22;;:::i;:::-;36572:31;36600:2;36572:31;:::i;:::-;36565:5;36558:46;36650:2;36646;36642:11;36636:18;36631:2;36624:5;36620:14;36613:42;36701:2;36697;36693:11;36687:18;36682:2;36675:5;36671:14;36664:42;36738:41;36775:2;36771;36767:11;36738:41;:::i;:::-;36733:2;36726:5;36722:14;36715:65;36827:3;36823:2;36819:12;36813:19;36807:3;36800:5;36796:15;36789:44;36866:42;36903:3;36899:2;36895:12;36866:42;:::i;:::-;36860:3;36853:5;36849:15;36842:67;36956:3;36952:2;36948:12;36942:19;36936:3;36929:5;36925:15;36918:44;37001:3;36997:2;36993:12;36987:19;37031:2;37021:8;37018:16;37015:36;;;37047:1;37044;37037:12;37015:36;37084:55;37131:7;37120:8;37116:2;37112:17;37084:55;:::i;:::-;37078:3;37067:15;;37060:80;-1:-1:-1;37071:5:16;36108:1062;-1:-1:-1;;;;;36108:1062:16:o;40720:245::-;40787:6;40840:2;40828:9;40819:7;40815:23;40811:32;40808:52;;;40856:1;40853;40846:12;40808:52;40888:9;40882:16;40907:28;40929:5;40907:28;:::i
Swarm Source
ipfs://4380a2c16f3d3a94e16ceec8dd417389a415486e9286774f1ba51d1e17ea3740
Loading...
Loading
Loading...
Loading
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.