Contract Overview
Balance:
0 CELO
CELO Value:
$0.00
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
Latest 3 internal transactions
Parent Txn Hash | Block | From | To | Value | |||
---|---|---|---|---|---|---|---|
0x269f35b635ff064baea266ff2d1b58d57e79180586107412ab040a19471fc575 | 17985689 | 27 days 8 hrs ago | 0x461a8878060aa45fa685732bff654ca1fdef2830 | 0x49887a216375fded17dc1aaad4920c3777265614 | 0.05 CELO | ||
0x5490a06128ba86f42ae495178eba81d0a9fe5ed3a36e696a2c523d36466c52ce | 17985665 | 27 days 8 hrs ago | 0x461a8878060aa45fa685732bff654ca1fdef2830 | 0x49887a216375fded17dc1aaad4920c3777265614 | 0.05 CELO | ||
0x156318ddd3d1e2760cab65cd580abc5e313de5cdd90a72faca7ddc99fea8d2c2 | 17985644 | 27 days 8 hrs ago | 0x461a8878060aa45fa685732bff654ca1fdef2830 | 0x49887a216375fded17dc1aaad4920c3777265614 | 0.05 CELO |
[ Download CSV Export ]
Contract Source Code Verified (Exact Match)
Contract Name:
TokenBridgeRelayer
Compiler Version
v0.8.17+commit.8df45f5f
Contract Source Code (Solidity Standard Json-Input format)
// 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 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) (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: 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.0; 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); }
// contracts/Bridge.sol // SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; 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); }
// contracts/Messages.sol // SPDX-License-Identifier: Apache 2 pragma solidity ^0.8.0; 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: 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: Apache 2 pragma solidity ^0.8.17; import {IWormhole} from "../interfaces/IWormhole.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; constructor( uint16 chainId, address wormhole, address tokenBridge_, address wethAddress, bool unwrapWeth_ ) { require(chainId > 0, "invalid chainId"); require(wormhole != address(0), "invalid wormhole address"); require(tokenBridge_ != address(0), "invalid token bridge address"); require(wethAddress != address(0), "invalid weth address"); // set initial state setOwner(msg.sender); setChainId(chainId); setWormhole(wormhole); setTokenBridge(tokenBridge_); setWethAddress(wethAddress); setUnwrapWethFlag(unwrapWeth_); // 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 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 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 relayer 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 relayer 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 nativeAmountForRecipient; uint256 maxToNativeAllowed = calculateMaxSwapAmountIn(token); if (transferWithRelay.toNativeTokenAmount > maxToNativeAllowed) { transferWithRelay.toNativeTokenAmount = maxToNativeAllowed; } // compute amount of native asset to pay the recipient 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 relayer if amountForRelayer > 0 if (amountForRelayer > 0) { SafeERC20.safeTransfer( IERC20(token), msg.sender, 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 caller if (relayerFee > 0) { payable(msg.sender).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 caller if (relayerFee > 0) { SafeERC20.safeTransfer( IERC20(address(weth)), msg.sender, 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 {} }
// 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 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 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; import {IWormhole} from "../interfaces/IWormhole.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "./TokenBridgeRelayerGetters.sol"; abstract contract TokenBridgeRelayerGovernance is TokenBridgeRelayerGetters { event OwnershipTransfered(address indexed oldOwner, address indexed newOwner); event SwapRateUpdated(address indexed token, uint256 indexed swapRate); /** * @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 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 onlyOwner { 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 rate for specified token in USD. * @param chainId_ Wormhole chain ID. * @param token Address of the token to update the conversion rate for. * @param swapRate The token -> USD conversion rate. * @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. */ function updateSwapRate( uint16 chainId_, address token, uint256 swapRate ) public onlyOwner onlyCurrentChain(chainId_) { require(isAcceptedToken(token), "token not accepted"); require(swapRate > 0, "swap rate must be nonzero"); setSwapRate(token, swapRate); emit SwapRateUpdated(token, swapRate); } /** * @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); } modifier onlyOwner() { require(owner() == msg.sender, "caller not the owner"); _; } modifier onlyCurrentChain(uint16 chainId_) { require(chainId() == chainId_, "wrong chain"); _; } }
// 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"); } }
// 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 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 _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; // address of WETH on this chain address wethAddress; // owner of this contract address owner; // 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; }
// 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; } }
{ "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": {} }
[{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"wormhole","type":"address"},{"internalType":"address","name":"tokenBridge_","type":"address"},{"internalType":"address","name":"wethAddress","type":"address"},{"internalType":"bool","name":"unwrapWeth_","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"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":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"uint256","name":"swapRate","type":"uint256"}],"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":"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":[{"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":[{"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":"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":"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":"token","type":"address"},{"internalType":"uint256","name":"maxAmount","type":"uint256"}],"name":"updateMaxNativeSwapAmount","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"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"swapRate","type":"uint256"}],"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
60806040523480156200001157600080fd5b50604051620040b9380380620040b9833981016040819052620000349162000260565b6001600d5561ffff8516620000825760405162461bcd60e51b815260206004820152600f60248201526e1a5b9d985b1a590818da185a5b9259608a1b60448201526064015b60405180910390fd5b6001600160a01b038416620000da5760405162461bcd60e51b815260206004820152601860248201527f696e76616c696420776f726d686f6c6520616464726573730000000000000000604482015260640162000079565b6001600160a01b038316620001325760405162461bcd60e51b815260206004820152601c60248201527f696e76616c696420746f6b656e20627269646765206164647265737300000000604482015260640162000079565b6001600160a01b0382166200018a5760405162461bcd60e51b815260206004820152601460248201527f696e76616c696420776574682061646472657373000000000000000000000000604482015260640162000079565b600180546001600160a01b031916331790556000805461ffff191661ffff8716179055600380546001600160a01b0319166001600160a01b038616179055600480546001600160a01b0319166001600160a01b038516179055600080546301000000600160b81b03191663010000006001600160a01b038516021790556000805462ff0000191662010000831515021790556200022a6305f5e100600555565b620002386305f5e100600655565b5050505050620002e0565b80516001600160a01b03811681146200025b57600080fd5b919050565b600080600080600060a086880312156200027957600080fd5b855161ffff811681146200028c57600080fd5b94506200029c6020870162000243565b9350620002ac6040870162000243565b9250620002bc6060870162000243565b915060808601518015158114620002d257600080fd5b809150509295509295909350565b613dc980620002f06000396000f3fe6080604052600436106102345760003560e01c80637c9dec7a1161012e578063a2f32c8f116100ab578063cd601c781161006f578063cd601c781461071a578063df160d761461073a578063e30c39781461075c578063f23f82ef1461077a578063fff982a81461079a57600080fd5b8063a2f32c8f14610677578063ad5c464814610697578063b5419523146106bc578063c6328a46146106dc578063c9c22f9f146106fa57600080fd5b806390a1afaa116100f257806390a1afaa146105c957806394cc743d146105e95780639a8a0592146106095780639cf278cd1461062c5780639fe089ad1461064a57600080fd5b80637c9dec7a146104f75780638335572f1461054d57806384acd1bb1461056d5780638da5cb5b1461058b5780638e151dd1146105a957600080fd5b80632def3e16116101bc5780633d62cca0116101805780633d62cca014610440578063415828bf1461047157806351e2d7b5146104865780635b9cf0e1146104a657806366775a6b146104c657600080fd5b80632def3e16146103875780632efe4f42146103a75780632f25e25f146103dd57806339ba6611146103f05780633b6e750f1461041057600080fd5b806327105ab91161020357806327105ab9146102c657806328ded8e3146102e657806329ac8361146103065780632ca8008c146103195780632d77e8fe1461034f57600080fd5b8063016aa20514610240578063038c0b66146102625780631019d654146102775780631acdab4b146102a757600080fd5b3661023b57005b600080fd5b34801561024c57600080fd5b5061026061025b3660046131a1565b6107ba565b005b34801561026e57600080fd5b50610260610884565b61028a6102853660046131ec565b610971565b6040516001600160401b0390911681526020015b60405180910390f35b3480156102b357600080fd5b506005545b60405190815260200161029e565b3480156102d257600080fd5b506102b86102e1366004613262565b610ac3565b3480156102f257600080fd5b506102b8610301366004613262565b610afd565b61028a610314366004613287565b610b2b565b34801561032557600080fd5b506102b86103343660046132d1565b6001600160a01b031660009081526008602052604090205490565b34801561035b57600080fd5b5061036f61036a3660046133c9565b610d7b565b6040516001600160a01b03909116815260200161029e565b34801561039357600080fd5b506102606103a2366004613448565b610e9b565b3480156103b357600080fd5b506102b86103c23660046132d1565b6001600160a01b031660009081526009602052604090205490565b6102606103eb366004613474565b610f59565b3480156103fc57600080fd5b506102b861040b3660046134e5565b611274565b34801561041c57600080fd5b5061043061042b3660046132d1565b611327565b604051901515815260200161029e565b34801561044c57600080fd5b506102b861045b366004613530565b61ffff1660009081526007602052604090205490565b34801561047d57600080fd5b506006546102b8565b34801561049257600080fd5b506102606104a1366004613448565b611345565b3480156104b257600080fd5b506102606104c1366004613448565b61146f565b3480156104d257600080fd5b506102b86104e1366004613530565b61ffff166000908152600a602052604090205490565b34801561050357600080fd5b506105176105123660046133c9565b611566565b60405161029e9190815160ff16815260208083015190820152604080830151908201526060918201519181019190915260800190565b34801561055957600080fd5b5061026061056836600461355b565b611697565b34801561057957600080fd5b506003546001600160a01b031661036f565b34801561059757600080fd5b506001546001600160a01b031661036f565b3480156105b557600080fd5b506102b86105c4366004613589565b61171e565b3480156105d557600080fd5b506102606105e4366004613448565b6117fe565b3480156105f557600080fd5b506102606106043660046131a1565b6118bc565b34801561061557600080fd5b5060005460405161ffff909116815260200161029e565b34801561063857600080fd5b5060005462010000900460ff16610430565b34801561065657600080fd5b5061066a6106653660046135a7565b611988565b60405161029e9190613665565b34801561068357600080fd5b50610260610692366004613530565b611a33565b3480156106a357600080fd5b50600054630100000090046001600160a01b031661036f565b3480156106c857600080fd5b506102b86106d73660046132d1565b611aaa565b3480156106e857600080fd5b506004546001600160a01b031661036f565b34801561070657600080fd5b506102606107153660046131a1565b611b44565b34801561072657600080fd5b506102b86107353660046132d1565b611c00565b34801561074657600080fd5b5061074f611ce5565b60405161029e9190613678565b34801561076857600080fd5b506002546001600160a01b031661036f565b34801561078657600080fd5b506102606107953660046136c5565b611d4a565b3480156107a657600080fd5b506102606107b53660046136c5565b611e75565b336107cd6001546001600160a01b031690565b6001600160a01b0316146107fc5760405162461bcd60e51b81526004016107f390613706565b60405180910390fd5b818061ffff1661080f60005461ffff1690565b61ffff16146108305760405162461bcd60e51b81526004016107f390613734565b6001600160a01b0382166108765760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b2103a37b5b2b760991b60448201526064016107f3565b61087f82611f29565b505050565b60006108986002546001600160a01b031690565b9050336001600160a01b038216146108f25760405162461bcd60e51b815260206004820152601b60248201527f63616c6c6572206d7573742062652070656e64696e674f776e6572000000000060448201526064016107f3565b60006109066001546001600160a01b031690565b600180546001600160a01b0319166001600160a01b038516179055905061092d60006120ce565b816001600160a01b0316816001600160a01b03167f0d18b5fd22306e373229b9439188228edca81207d1667f604daf6cef8aa3ee6760405160405180910390a35050565b600061097b6120f0565b600061098f6003546001600160a01b031690565b6001600160a01b0316631a90a2196040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f09190613759565b9050803414610a365760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742076616c756560701b60448201526064016107f3565b6000610a4189612149565b9050610a56610a508983610ac3565b82610afd565b9750610a6289896121eb565b9750610aab6040518060c001604052808b6001600160a01b031681526020018360ff1681526020018a81526020018981526020018861ffff168152602001878152508584612221565b92505050610ab96001600d55565b9695505050505050565b600060088260ff161115610af457610adc600883613788565b610ae790600a613885565b610af19084613894565b92505b50815b92915050565b600060088260ff161115610af457610b16600883613788565b610b2190600a613885565b610af190846138b6565b6000805462010000900460ff16610b845760405162461bcd60e51b815260206004820181905260248201527f574554482066756e6374696f6e616c697479206e6f7420737570706f7274656460448201526064016107f3565b6000610b986003546001600160a01b031690565b6001600160a01b0316631a90a2196040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bd5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bf99190613759565b9050803411610c3f5760405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742076616c756560701b60448201526064016107f3565b6000610c4b82346138cd565b90506000610c64610c5d836012610ac3565b6012610afd565b610c6e90836138cd565b90508015610ca557604051339082156108fc029083906000818181858888f19350505050158015610ca3573d6000803e3d6000fd5b505b6000610cb182846138cd565b90506000610ccf6000546001600160a01b0363010000009091041690565b9050806001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610d0c57600080fd5b505af1158015610d20573d6000803e3d6000fd5b5050505050610d6d6040518060c00160405280836001600160a01b03168152602001601260ff1681526020018481526020018c81526020018b61ffff1681526020018a8152508887612221565b9a9950505050505050505050565b600080610d8983602161253b565b90506000610d98846041612599565b9050610da760005461ffff1690565b61ffff168161ffff1614610e88576004546001600160a01b0316604051630ff8f14360e11b815261ffff83166004820152602481018490526001600160a01b039190911690631ff1e28690604401602060405180830381865afa158015610e12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3691906138e0565b92506001600160a01b038316610e835760405162461bcd60e51b81526020600482015260126024820152711d1bdad95b881b9bdd08185d1d195cdd195960721b60448201526064016107f3565b610e94565b610e91826125f6565b92505b5050919050565b33610eae6001546001600160a01b031690565b6001600160a01b031614610ed45760405162461bcd60e51b81526004016107f390613706565b818061ffff16610ee760005461ffff1690565b61ffff1614610f085760405162461bcd60e51b81526004016107f390613734565b60008211610f505760405162461bcd60e51b81526020600482015260156024820152740707265636973696f6e206d757374206265203e203605c1b60448201526064016107f3565b61087f82600555565b6000806000610f9d85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061264a92505050565b9250925092506000610fae84611566565b90506000610fbf82606001516125f6565b90506000610fd660005460ff620100009091041690565b90506001600160a01b0382163303610ffe57610ff484838784612926565b5050505050505050565b600061100985612149565b9050611019846020015182610afd565b6020850152600054630100000090046001600160a01b03166001600160a01b0316856001600160a01b031603611064576110598684866020015185612a50565b505050505050505050565b60408401511561122b5761107c846040015182610afd565b604085015260008061108d87611c00565b905080866040015111156110a357604086018190525b6110b187876040015161171e565b915081156111ed57813410156111095760405162461bcd60e51b815260206004820181905260248201527f696e73756666696369656e74206e617469766520617373657420616d6f756e7460448201526064016107f3565b600061111583346138cd565b9050801561114c57604051339082156108fc029083906000818181858888f1935050505015801561114a573d6000803e3d6000fd5b505b6040516001600160a01b0387169084156108fc029085906000818181858888f19350505050158015611182573d6000803e3d6000fd5b50876001600160a01b0316336001600160a01b0316876001600160a01b03167f764f0dc063c06f32d89a3f3af80c0db4be8a090901f589a478b447e0a51f09f18a60400151876040516111df929190918252602082015260400190565b60405180910390a450611228565b6000604087015234156112285760405133903480156108fc02916000818181858888f19350505050158015611226573d6000803e3d6000fd5b505b50505b60008460400151856020015161124191906138fd565b9050801561125457611254863383612ba8565b6112688685611263848b6138cd565b612ba8565b50505050505050505050565b6001600160a01b038216600090815260086020526040812054806000036112d15760405162461bcd60e51b81526020600482015260116024820152701cddd85c081c985d19481b9bdd081cd95d607a1b60448201526064016107f3565b6006546112de90826138b6565b60055461ffff87166000908152600a602052604090205461130086600a613885565b61130a91906138b6565b61131491906138b6565b61131e9190613894565b95945050505050565b6001600160a01b03166000908152600b602052604090205460ff1690565b336113586001546001600160a01b031690565b6001600160a01b03161461137e5760405162461bcd60e51b81526004016107f390613706565b806113db5760405162461bcd60e51b815260206004820152602760248201527f636f6e7472616374416464726573732063616e6e6f7420657175616c206279746044820152666573333228302960c81b60648201526084016107f3565b61ffff8216158015906113f7575060005461ffff838116911614155b6114535760405162461bcd60e51b815260206004820152602760248201527f636861696e49645f2063616e6e6f7420657175616c2030206f7220746869732060448201526618da185a5b925960ca1b60648201526084016107f3565b61ffff91909116600090815260076020526040902055565b5050565b336114826001546001600160a01b031690565b6001600160a01b0316146114a85760405162461bcd60e51b81526004016107f390613706565b60005461ffff1661ffff168261ffff16036114f55760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b21031b430b4b760991b60448201526064016107f3565b61ffff821660009081526007602052604090205461154e5760405162461bcd60e51b815260206004820152601660248201527518dbdb9d1c9858dd08191bd95cdb89dd08195e1a5cdd60521b60448201526064016107f3565b61ffff919091166000908152600a6020526040902055565b6040805160808101825260008082526020820181905291810182905260608101829052906115948382612c0b565b60ff1682526115a46001826138fd565b9050816000015160ff166001146115f15760405162461bcd60e51b81526020600482015260116024820152701a5b9d985b1a59081c185e5b1bd8591259607a1b60448201526064016107f3565b6115fb8382612c67565b60208084019190915261160e90826138fd565b905061161a8382612c67565b604083015261162a6020826138fd565b9050611636838261253b565b60608301526116466020826138fd565b9050825181146116915760405162461bcd60e51b81526020600482015260166024820152750d2dcecc2d8d2c840dacae6e6c2ceca40d8cadccee8d60531b60448201526064016107f3565b50919050565b336116aa6001546001600160a01b031690565b6001600160a01b0316146116d05760405162461bcd60e51b81526004016107f390613706565b818061ffff166116e360005461ffff1690565b61ffff16146117045760405162461bcd60e51b81526004016107f390613734565b6000805462ff000019166201000084151502179055505050565b60008061172a84612149565b9050600061175061174b6000546001600160a01b0363010000009091041690565b612149565b90508060ff168260ff1611156117ad5761176a8183613788565b61177590600a613885565b61177e86611aaa565b61178891906138b6565b8461179260055490565b61179c91906138b6565b6117a69190613894565b92506117f6565b6117b685611aaa565b6117c08383613788565b6117cb90600a613885565b856117d560055490565b6117df91906138b6565b6117e991906138b6565b6117f39190613894565b92505b505092915050565b336118116001546001600160a01b031690565b6001600160a01b0316146118375760405162461bcd60e51b81526004016107f390613706565b818061ffff1661184a60005461ffff1690565b61ffff161461186b5760405162461bcd60e51b81526004016107f390613734565b600082116118b35760405162461bcd60e51b81526020600482015260156024820152740707265636973696f6e206d757374206265203e203605c1b60448201526064016107f3565b61087f82600655565b336118cf6001546001600160a01b031690565b6001600160a01b0316146118f55760405162461bcd60e51b81526004016107f390613706565b818061ffff1661190860005461ffff1690565b61ffff16146119295760405162461bcd60e51b81526004016107f390613734565b6001600160a01b03821661197f5760405162461bcd60e51b815260206004820181905260248201527f6e65774f776e65722063616e6e6f7420657175616c206164647265737328302960448201526064016107f3565b61087f826120ce565b6060816000015160ff166001146119d55760405162461bcd60e51b81526020600482015260116024820152701a5b9d985b1a59081c185e5b1bd8591259607a1b60448201526064016107f3565b815160208084015160408086015160608701519151611a1d95949192910160f89490941b6001600160f81b031916845260018401929092526021830152604182015260610190565b6040516020818303038152906040529050919050565b33611a466001546001600160a01b031690565b6001600160a01b031614611a6c5760405162461bcd60e51b81526004016107f390613706565b808061ffff16611a7f60005461ffff1690565b61ffff1614611aa05760405162461bcd60e51b81526004016107f390613734565b61146b60006120ce565b600080546001600160a01b0363010000009091048116825260086020526040808320549184168352822054600082118015611ae55750600081115b611b255760405162461bcd60e51b81526020600482015260116024820152701cddd85c081c985d19481b9bdd081cd95d607a1b60448201526064016107f3565b8082611b3060055490565b611b3a91906138b6565b610e919190613894565b33611b576001546001600160a01b031690565b6001600160a01b031614611b7d5760405162461bcd60e51b81526004016107f390613706565b818061ffff16611b9060005461ffff1690565b61ffff1614611bb15760405162461bcd60e51b81526004016107f390613734565b6001600160a01b038216611bf75760405162461bcd60e51b815260206004820152600d60248201526c34b73b30b634b2103a37b5b2b760991b60448201526064016107f3565b61087f82612cbc565b600080611c0c83612149565b90506000611c2d61174b6000546001600160a01b0363010000009091041690565b90508060ff168260ff161115611c9c57600554611c4a8284613788565b611c5590600a613885565b611c5e86611aaa565b6001600160a01b038716600090815260096020526040902054611c8191906138b6565b611c8b91906138b6565b611c959190613894565b9250610e94565b600554611ca98383613788565b611cb490600a613885565b611cbe91906138b6565b611cc785611aaa565b6001600160a01b038616600090815260096020526040902054611b30565b60606000600c01805480602002602001604051908101604052809291908181526020018280548015611d4057602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611d22575b5050505050905090565b33611d5d6001546001600160a01b031690565b6001600160a01b031614611d835760405162461bcd60e51b81526004016107f390613706565b828061ffff16611d9660005461ffff1690565b61ffff1614611db75760405162461bcd60e51b81526004016107f390613734565b611dc083611327565b611ddc5760405162461bcd60e51b81526004016107f390613910565b60008211611e2c5760405162461bcd60e51b815260206004820152601960248201527f737761702072617465206d757374206265206e6f6e7a65726f0000000000000060448201526064016107f3565b6001600160a01b038316600081815260086020526040808220859055518492917fc6eb9fb936b61b402d503deeffc822f46492e15c2c8f079815cc4850ad7b02b091a350505050565b33611e886001546001600160a01b031690565b6001600160a01b031614611eae5760405162461bcd60e51b81526004016107f390613706565b828061ffff16611ec160005461ffff1690565b61ffff1614611ee25760405162461bcd60e51b81526004016107f390613734565b611eeb83611327565b611f075760405162461bcd60e51b81526004016107f390613910565b6001600160a01b03831660009081526009602052604090208290555b50505050565b6001600160a01b0381166000908152600b602052604090205460ff16611f885760405162461bcd60e51b81526020600482015260146024820152731d1bdad95b881b9bdd081c9959da5cdd195c995960621b60448201526064016107f3565b6001600160a01b0381166000908152600b60209081526040808320805460ff191690556008825280832083905560099091528120819055600c54905b8181101561200e57826001600160a01b03166000600c018281548110611fec57611fec61393c565b6000918252602090912001546001600160a01b03161461200e57600101611fc4565b81811461087f57600182111561209657600c61202b6001846138cd565b8154811061203b5761203b61393c565b600091825260209091200154600c80546001600160a01b0390921691839081106120675761206761393c565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b600c8054806120a7576120a7613952565b600082815260209020810160001990810180546001600160a01b0319169055019055505050565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b6002600d54036121425760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016107f3565b6002600d55565b60408051600481526024810182526020810180516001600160e01b031663313ce56760e01b179052905160009182916001600160a01b0385169161218c91613968565b600060405180830381855afa9150503d80600081146121c7576040519150601f19603f3d011682016040523d82523d6000602084013e6121cc565b606091505b50915050808060200190518101906121e49190613994565b9392505050565b6000806121f784612d8b565b905061220584333086612e37565b8061220f85612d8b565b61221991906138cd565b949350505050565b60006122308460000151611327565b61224c5760405162461bcd60e51b81526004016107f390613910565b60a08401516122a95760405162461bcd60e51b8152602060048201526024808201527f746172676574526563697069656e742063616e6e6f74206265206279746573336044820152633228302960e01b60648201526084016107f3565b60006122bd85604001518660200151610ac3565b90506000811161230f5760405162461bcd60e51b815260206004820152601d60248201527f6e6f726d616c697a656420616d6f756e74206d757374206265203e203000000060448201526064016107f3565b600061232386606001518760200151610ac3565b90508560600151600014806123385750600081115b6123845760405162461bcd60e51b815260206004820152601b60248201527f696e76616c696420746f4e6174697665546f6b656e416d6f756e74000000000060448201526064016107f3565b608086015161ffff16600090815260076020526040902054806123e15760405162461bcd60e51b81526020600482015260156024820152741d185c99d95d081b9bdd081c9959da5cdd195c9959605a1b60448201526064016107f3565b60006124076123fd89608001518a600001518b60200151611274565b8960200151610ac3565b905061241383826138fd565b84116124575760405162461bcd60e51b81526020600482015260136024820152721a5b9cdd59999a58da595b9d08185b5bdd5b9d606a1b60448201526064016107f3565b600061248a6040518060800160405280600160ff1681526020018481526020018681526020018b60a00151815250611988565b905060006124a06004546001600160a01b031690565b90506124b58a60000151828c60400151612e6f565b806001600160a01b031663c5a5ebda898c600001518d604001518e60800151898f896040518863ffffffff1660e01b81526004016124f8969594939291906139b1565b60206040518083038185885af1158015612516573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610d6d9190613a17565b60006125488260206138fd565b835110156125905760405162461bcd60e51b8152602060048201526015602482015274746f427974657333325f6f75744f66426f756e647360581b60448201526064016107f3565b50016020015190565b60006125a68260026138fd565b835110156125ed5760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b60448201526064016107f3565b50016002015190565b60006001600160a01b03198216156126465760405162461bcd60e51b8152602060048201526013602482015272696e76616c69642045564d206164647265737360681b60448201526064016107f3565b5090565b606060008060006126636003546001600160a01b031690565b6001600160a01b031663a9e11893866040518263ffffffff1660e01b815260040161268e9190613665565b600060405180830381865afa1580156126ab573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526126d39190810190613b56565b905060006126e48260e00151610d7b565b90506126ef81611327565b6127325760405162461bcd60e51b81526020600482015260146024820152731d1bdad95b881b9bdd081c9959da5cdd195c995960621b60448201526064016107f3565b600061273d82612d8b565b905060006127536004546001600160a01b031690565b90506000816001600160a01b031663c3f511c18a6040518263ffffffff1660e01b81526004016127839190613665565b6000604051808303816000875af11580156127a2573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526127ca9190810190613c7a565b90506000836127d886612d8b565b6127e291906138cd565b90506000836001600160a01b031663ea63738d846040518263ffffffff1660e01b81526004016128129190613665565b600060405180830381865afa15801561282f573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526128579190810190613cae565b9050612877876060015161ffff1660009081526007602052604090205490565b8160c00151146128c95760405162461bcd60e51b815260206004820152601760248201527f636f6e7472616374206e6f74207265676973746572656400000000000000000060448201526064016107f3565b8660a001516001600160401b03168760800151886060015161ffff167fcaf280c8cfeba144da67230d9b009c8f868a75bac9a528fa0474be1ba317c16960405160405180910390a460e001519a9099509397509295505050505050565b34156129805760405162461bcd60e51b815260206004820152602360248201527f726563697069656e742063616e6e6f742073776170206e61746976652061737360448201526265747360e81b60648201526084016107f3565b6000546001600160a01b0363010000009091048116908516811480156129a35750815b15612a3e57604051632e1a7d4d60e01b8152600481018490526001600160a01b03821690632e1a7d4d90602401600060405180830381600087803b1580156129ea57600080fd5b505af11580156129fe573d6000803e3d6000fd5b50506040516001600160a01b038716925085156108fc02915085906000818181858888f19350505050158015612a38573d6000803e3d6000fd5b50612a49565b612a49858585612ba8565b5050505050565b3415612a935760405162461bcd60e51b815260206004820152601260248201527176616c7565206d757374206265207a65726f60701b60448201526064016107f3565b8015612b7957600054604051632e1a7d4d60e01b81526004810186905263010000009091046001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015612ae557600080fd5b505af1158015612af9573d6000803e3d6000fd5b50505050826001600160a01b03166108fc8386612b1691906138cd565b6040518115909202916000818181858888f19350505050158015612b3e573d6000803e3d6000fd5b508115612b7457604051339083156108fc029084906000818181858888f19350505050158015612b72573d6000803e3d6000fd5b505b611f23565b600054630100000090046001600160a01b0316612b9b818561126386896138cd565b8215612a4957612a498133855b6040516001600160a01b03831660248201526044810182905261087f90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152612f84565b6000612c188260016138fd565b83511015612c5e5760405162461bcd60e51b8152602060048201526013602482015272746f55696e74385f6f75744f66426f756e647360681b60448201526064016107f3565b50016001015190565b6000612c748260206138fd565b835110156125905760405162461bcd60e51b8152602060048201526015602482015274746f55696e743235365f6f75744f66426f756e647360581b60448201526064016107f3565b6001600160a01b0381166000908152600b602052604090205460ff1615612d255760405162461bcd60e51b815260206004820152601860248201527f746f6b656e20616c72656164792072656769737465726564000000000000000060448201526064016107f3565b6001600160a01b03166000818152600b60205260408120805460ff19166001908117909155600c805491820181559091527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c70180546001600160a01b0319169091179055565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b179052905160009182916001600160a01b03851691612ddf91613968565b600060405180830381855afa9150503d8060008114612e1a576040519150601f19603f3d011682016040523d82523d6000602084013e612e1f565b606091505b50915050808060200190518101906121e49190613759565b6040516001600160a01b0380851660248301528316604482015260648101829052611f239085906323b872dd60e01b90608401612bd4565b801580612ee95750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e90604401602060405180830381865afa158015612ec3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ee79190613759565b155b612f545760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016107f3565b6040516001600160a01b03831660248201526044810182905261087f90849063095ea7b360e01b90606401612bd4565b6000612fd9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166130569092919063ffffffff16565b80519091501561087f5780806020019051810190612ff79190613d76565b61087f5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016107f3565b6060612219848460008585600080866001600160a01b0316858760405161307d9190613968565b60006040518083038185875af1925050503d80600081146130ba576040519150601f19603f3d011682016040523d82523d6000602084013e6130bf565b606091505b50915091506130d0878383876130db565b979650505050505050565b6060831561314a578251600003613143576001600160a01b0385163b6131435760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016107f3565b5081612219565b612219838381511561315f5781518083602001fd5b8060405162461bcd60e51b81526004016107f39190613665565b61ffff8116811461318957600080fd5b50565b6001600160a01b038116811461318957600080fd5b600080604083850312156131b457600080fd5b82356131bf81613179565b915060208301356131cf8161318c565b809150509250929050565b63ffffffff8116811461318957600080fd5b60008060008060008060c0878903121561320557600080fd5b86356132108161318c565b95506020870135945060408701359350606087013561322e81613179565b92506080870135915060a0870135613245816131da565b809150509295509295509295565b60ff8116811461318957600080fd5b6000806040838503121561327557600080fd5b8235915060208301356131cf81613253565b6000806000806080858703121561329d57600080fd5b8435935060208501356132af81613179565b92506040850135915060608501356132c6816131da565b939692955090935050565b6000602082840312156132e357600080fd5b81356121e48161318c565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b0381118282101715613326576133266132ee565b60405290565b60405161016081016001600160401b0381118282101715613326576133266132ee565b60405161010081016001600160401b0381118282101715613326576133266132ee565b604051601f8201601f191681016001600160401b038111828210171561339a5761339a6132ee565b604052919050565b60006001600160401b038211156133bb576133bb6132ee565b50601f01601f191660200190565b6000602082840312156133db57600080fd5b81356001600160401b038111156133f157600080fd5b8201601f8101841361340257600080fd5b8035613415613410826133a2565b613372565b81815285602083850101111561342a57600080fd5b81602084016020830137600091810160200191909152949350505050565b6000806040838503121561345b57600080fd5b823561346681613179565b946020939093013593505050565b6000806020838503121561348757600080fd5b82356001600160401b038082111561349e57600080fd5b818501915085601f8301126134b257600080fd5b8135818111156134c157600080fd5b8660208285010111156134d357600080fd5b60209290920196919550909350505050565b6000806000606084860312156134fa57600080fd5b833561350581613179565b925060208401356135158161318c565b9150604084013561352581613253565b809150509250925092565b60006020828403121561354257600080fd5b81356121e481613179565b801515811461318957600080fd5b6000806040838503121561356e57600080fd5b823561357981613179565b915060208301356131cf8161354d565b6000806040838503121561359c57600080fd5b82356134668161318c565b6000608082840312156135b957600080fd5b604051608081018181106001600160401b03821117156135db576135db6132ee565b60405282356135e981613253565b808252506020830135602082015260408301356040820152606083013560608201528091505092915050565b60005b83811015613630578181015183820152602001613618565b50506000910152565b60008151808452613651816020860160208601613615565b601f01601f19169290920160200192915050565b6020815260006121e46020830184613639565b6020808252825182820181905260009190848201906040850190845b818110156136b95783516001600160a01b031683529284019291840191600101613694565b50909695505050505050565b6000806000606084860312156136da57600080fd5b83356136e581613179565b925060208401356136f58161318c565b929592945050506040919091013590565b60208082526014908201527331b0b63632b9103737ba103a34329037bbb732b960611b604082015260600190565b6020808252600b908201526a3bb937b7339031b430b4b760a91b604082015260600190565b60006020828403121561376b57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b60ff8281168282160390811115610af757610af7613772565b600181815b808511156137dc5781600019048211156137c2576137c2613772565b808516156137cf57918102915b93841c93908002906137a6565b509250929050565b6000826137f357506001610af7565b8161380057506000610af7565b816001811461381657600281146138205761383c565b6001915050610af7565b60ff84111561383157613831613772565b50506001821b610af7565b5060208310610133831016604e8410600b841016171561385f575081810a610af7565b61386983836137a1565b806000190482111561387d5761387d613772565b029392505050565b60006121e460ff8416836137e4565b6000826138b157634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417610af757610af7613772565b81810381811115610af757610af7613772565b6000602082840312156138f257600080fd5b81516121e48161318c565b80820180821115610af757610af7613772565b6020808252601290820152711d1bdad95b881b9bdd081858d8d95c1d195960721b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b6000825161397a818460208701613615565b9190910192915050565b805161398f81613253565b919050565b6000602082840312156139a657600080fd5b81516121e481613253565b60018060a01b038716815285602082015261ffff8516604082015283606082015263ffffffff8316608082015260c060a082015260006139f460c0830184613639565b98975050505050505050565b80516001600160401b038116811461398f57600080fd5b600060208284031215613a2957600080fd5b6121e482613a00565b805161398f816131da565b805161398f81613179565b600082601f830112613a5957600080fd5b8151613a67613410826133a2565b818152846020838601011115613a7c57600080fd5b612219826020830160208701613615565b600082601f830112613a9e57600080fd5b815160206001600160401b03821115613ab957613ab96132ee565b613ac7818360051b01613372565b82815260079290921b84018101918181019086841115613ae657600080fd5b8286015b84811015613b4b5760808189031215613b035760008081fd5b613b0b613304565b815181528482015185820152604080830151613b2681613253565b90820152606082810151613b3981613253565b90820152835291830191608001613aea565b509695505050505050565b600060208284031215613b6857600080fd5b81516001600160401b0380821115613b7f57600080fd5b908301906101608286031215613b9457600080fd5b613b9c61332c565b613ba583613984565b8152613bb360208401613a32565b6020820152613bc460408401613a32565b6040820152613bd560608401613a3d565b606082015260808301516080820152613bf060a08401613a00565b60a0820152613c0160c08401613984565b60c082015260e083015182811115613c1857600080fd5b613c2487828601613a48565b60e083015250610100613c38818501613a32565b908201526101208381015183811115613c5057600080fd5b613c5c88828701613a8d565b91830191909152506101409283015192810192909252509392505050565b600060208284031215613c8c57600080fd5b81516001600160401b03811115613ca257600080fd5b61221984828501613a48565b600060208284031215613cc057600080fd5b81516001600160401b0380821115613cd757600080fd5b908301906101008286031215613cec57600080fd5b613cf461334f565b613cfd83613984565b81526020830151602082015260408301516040820152613d1f60608401613a3d565b606082015260808301516080820152613d3a60a08401613a3d565b60a082015260c083015160c082015260e083015182811115613d5b57600080fd5b613d6787828601613a48565b60e08301525095945050505050565b600060208284031215613d8857600080fd5b81516121e48161354d56fea2646970667358221220043ecf0d1429bfc7866a5607e98ae2b1cca0eeef46c7279047c0211efe0f076764736f6c63430008110033000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000a321448d90d4e5b0a732867c18ea198e75cac48e000000000000000000000000796dff6d74f3e27060b71255fe517bfb23c93eed000000000000000000000000471ece3750da237f93b8e339c536989b8978a4380000000000000000000000000000000000000000000000000000000000000000
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000a321448d90d4e5b0a732867c18ea198e75cac48e000000000000000000000000796dff6d74f3e27060b71255fe517bfb23c93eed000000000000000000000000471ece3750da237f93b8e339c536989b8978a4380000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : chainId (uint16): 14
Arg [1] : wormhole (address): 0xa321448d90d4e5b0a732867c18ea198e75cac48e
Arg [2] : tokenBridge_ (address): 0x796dff6d74f3e27060b71255fe517bfb23c93eed
Arg [3] : wethAddress (address): 0x471ece3750da237f93b8e339c536989b8978a438
Arg [4] : unwrapWeth_ (bool): False
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000000000000000000000000000000000000000000e
Arg [1] : 000000000000000000000000a321448d90d4e5b0a732867c18ea198e75cac48e
Arg [2] : 000000000000000000000000796dff6d74f3e27060b71255fe517bfb23c93eed
Arg [3] : 000000000000000000000000471ece3750da237f93b8e339c536989b8978a438
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Deployed ByteCode Sourcemap
632:26699:9:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4250:222:11;;;;;;;;;;-1:-1:-1;4250:222:11;;;;;:::i;:::-;;:::i;:::-;;1612:496;;;;;;;;;;;;;:::i;3553:1500:9:-;;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;1688:31:16;;;1670:50;;1658:2;1643:18;3553:1500:9;;;;;;;;1279:107:10;;;;;;;;;;-1:-1:-1;1355:24:10;;1279:107;;;1877:25:16;;;1865:2;1850:18;1279:107:10;1731:177:16;2520:221:10;;;;;;;;;;-1:-1:-1;2520:221:10;;;;;:::i;:::-;;:::i;2747:223::-;;;;;;;;;;-1:-1:-1;2747:223:10;;;;;:::i;:::-;;:::i;5851:1563:9:-;;;;;;:::i;:::-;;:::i;2023:110:10:-;;;;;;;;;;-1:-1:-1;2023:110:10;;;;;:::i;:::-;-1:-1:-1;;;;;2103:23:10;2077:7;2103:23;;;:16;:23;;;;;;;2023:110;22584:811:9;;;;;;;;;;-1:-1:-1;22584:811:9;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;5347:32:16;;;5329:51;;5317:2;5302:18;22584:811:9;5183:203:16;6738:268:11;;;;;;;;;;-1:-1:-1;6738:268:11;;;;;:::i;:::-;;:::i;1886:131:10:-;;;;;;;;;;-1:-1:-1;1886:131:10;;;;;:::i;:::-;-1:-1:-1;;;;;1977:33:10;1951:7;1977:33;;;:26;:33;;;;;;;1886:131;12181:5092:9;;;;;;:::i;:::-;;:::i;26092:471::-;;;;;;;;;;-1:-1:-1;26092:471:9;;;;;:::i;:::-;;:::i;1392:119:10:-;;;;;;;;;;-1:-1:-1;1392:119:10;;;;;:::i;:::-;;:::i;:::-;;;6998:14:16;;6991:22;6973:41;;6961:2;6946:18;1392:119:10;6833:187:16;1123:150:10;;;;;;;;;;-1:-1:-1;1123:150:10;;;;;:::i;:::-;1224:42;;1198:7;1224:42;;;:26;:42;;;;;;;1123:150;1644:111;;;;;;;;;;-1:-1:-1;1722:26:10;;1644:111;;3075:530:11;;;;;;;;;;-1:-1:-1;3075:530:11;;;;;:::i;:::-;;:::i;4882:328::-;;;;;;;;;;-1:-1:-1;4882:328:11;;;;;:::i;:::-;;:::i;1761:119:10:-;;;;;;;;;;-1:-1:-1;1761:119:10;;;;;:::i;:::-;1845:28;;1819:7;1845:28;;;:18;:28;;;;;;;1761:119;1174:801:12;;;;;;;;;;-1:-1:-1;1174:801:12;;;;;:::i;:::-;;:::i;:::-;;;;;;8014:13:16;;8029:4;8010:24;7992:43;;8091:4;8079:17;;;8073:24;8051:20;;;8044:54;8154:4;8142:17;;;8136:24;8114:20;;;8107:54;8217:4;8205:17;;;8199:24;8177:20;;;8170:54;;;;7979:3;7964:19;;7775:455;2629:178:11;;;;;;;;;;-1:-1:-1;2629:178:11;;;;;:::i;:::-;;:::i;599:102:10:-;;;;;;;;;;-1:-1:-1;678:15:10;;-1:-1:-1;;;;;678:15:10;599:102;;407:83;;;;;;;;;;-1:-1:-1;471:12:10;;-1:-1:-1;;;;;471:12:10;407:83;;24964:737:9;;;;;;;;;;-1:-1:-1;24964:737:9;;;;;:::i;:::-;;:::i;5392:278:11:-;;;;;;;;;;-1:-1:-1;5392:278:11;;;;;:::i;:::-;;:::i;774:261::-;;;;;;;;;;-1:-1:-1;774:261:11;;;;;:::i;:::-;;:::i;1031:86:10:-;;;;;;;;;;-1:-1:-1;1071:6:10;1096:14;1031:86;;1096:14;;;;9433:38:16;;9421:2;9406:18;1031:86:10;9289:188:16;935:90:10;;;;;;;;;;-1:-1:-1;978:4:10;1001:17;;;;;;935:90;;451:391:12;;;;;;;;;;-1:-1:-1;451:391:12;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;1183:159:11:-;;;;;;;;;;-1:-1:-1;1183:159:11;;;;;:::i;:::-;;:::i;836:93:10:-;;;;;;;;;;-1:-1:-1;873:5:10;903:18;;;;-1:-1:-1;;;;;903:18:10;836:93;;2139:375;;;;;;;;;;-1:-1:-1;2139:375:10;;;;;:::i;:::-;;:::i;707:123::-;;;;;;;;;;-1:-1:-1;803:18:10;;-1:-1:-1;;;;;803:18:10;707:123;;3769:217:11;;;;;;;;;;-1:-1:-1;3769:217:11;;;;;:::i;:::-;;:::i;23838:705:9:-;;;;;;;;;;-1:-1:-1;23838:705:9;;;;;:::i;:::-;;:::i;1517:121:10:-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;496:97::-;;;;;;;;;;-1:-1:-1;567:19:10;;-1:-1:-1;;;;;567:19:10;496:97;;6197:365:11;;;;;;;;;;-1:-1:-1;6197:365:11;;;;;:::i;:::-;;:::i;7315:281::-;;;;;;;;;;-1:-1:-1;7315:281:11;;;;;:::i;:::-;;:::i;4250:222::-;7652:10;7641:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;7641:7:11;-1:-1:-1;;;;;7641:21:11;;7633:54;;;;-1:-1:-1;;;7633:54:11;;;;;;;:::i;:::-;;;;;;;;;4363:8:::1;7785;7772:21;;:9;1071:6:10::0;1096:14;;;;1031:86;7772:9:11::1;:21;;;7764:45;;;;-1:-1:-1::0;;;7764:45:11::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;4391:19:11;::::2;4383:45;;;::::0;-1:-1:-1;;;4383:45:11;;13416:2:16;4383:45:11::2;::::0;::::2;13398:21:16::0;13455:2;13435:18;;;13428:30;-1:-1:-1;;;13474:18:16;;;13467:43;13527:18;;4383:45:11::2;13214:337:16::0;4383:45:11::2;4439:26;4459:5;4439:19;:26::i;:::-;7697:1:::1;4250:222:::0;;:::o;1612:496::-;1711:16;1730:14;567:19:10;;-1:-1:-1;;;;;567:19:10;;496:97;1730:14:11;1711:33;-1:-1:-1;1763:10:11;-1:-1:-1;;;;;1763:22:11;;;1755:62;;;;-1:-1:-1;;;1755:62:11;;13758:2:16;1755:62:11;;;13740:21:16;13797:2;13777:18;;;13770:30;13836:29;13816:18;;;13809:57;13883:18;;1755:62:11;13556:351:16;1755:62:11;1868:20;1891:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;1891:7:11;234:12:13;:21;;-1:-1:-1;;;;;;234:21:13;-1:-1:-1;;;;;234:21:13;;;;;1868:30:11;-1:-1:-1;2015:27:11;2039:1;2015:15;:27::i;:::-;2092:8;-1:-1:-1;;;;;2058:43:11;2078:12;-1:-1:-1;;;;;2058:43:11;;;;;;;;;;;1662:446;;1612:496::o;3553:1500:9:-;3798:22;2261:21:0;:19;:21::i;:::-;3959:19:9::1;3981:10;678:15:10::0;;-1:-1:-1;;;;;678:15:10;;599:102;3981:10:9::1;-1:-1:-1::0;;;;;3981:21:9::1;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;3959:45;;4035:11;4022:9;:24;4014:55;;;::::0;-1:-1:-1;;;4014:55:9;;14303:2:16;4014:55:9::1;::::0;::::1;14285:21:16::0;14342:2;14322:18;;;14315:30;-1:-1:-1;;;14361:18:16;;;14354:48;14419:18;;4014:55:9::1;14101:342:16::0;4014:55:9::1;4232:19;4254:18;4266:5;4254:11;:18::i;:::-;4232:40;;4291:106;4322:38;4338:6;4346:13;4322:15;:38::i;:::-;4374:13;4291:17;:106::i;:::-;4282:115;;4536:28;4550:5;4557:6;4536:13;:28::i;:::-;4527:37;;4656:390;4694:296;;;;;;;;4742:5;-1:-1:-1::0;;;;;4694:296:9::1;;;;;4812:13;4694:296;;;;;;4773:6;4694:296;;;;4864:19;4694:296;;;;4914:11;4694:296;;;;;;4960:15;4694:296;;::::0;5004:7:::1;5025:11;4656:24;:390::i;:::-;4638:408;;3822:1231;;2303:20:0::0;1716:1;2809:7;:22;2629:209;2303:20;3553:1500:9;;;;;;;;:::o;2520:221:10:-;2620:7;2654:1;2643:8;:12;;;2639:73;;;2688:12;2699:1;2688:8;:12;:::i;:::-;2681:20;;:2;:20;:::i;:::-;2671:30;;;;:::i;:::-;;;2639:73;-1:-1:-1;2728:6:10;2520:221;;;;;:::o;2747:223::-;2849:7;2883:1;2872:8;:12;;;2868:73;;;2917:12;2928:1;2917:8;:12;:::i;:::-;2910:20;;:2;:20;:::i;:::-;2900:30;;;;:::i;5851:1563:9:-;6040:22;1001:17:10;;;;;;;6074:57:9;;;;-1:-1:-1;;;6074:57:9;;16716:2:16;6074:57:9;;;16698:21:16;;;16735:18;;;16728:30;16794:34;16774:18;;;16767:62;16846:18;;6074:57:9;16514:356:16;6074:57:9;6269:19;6291:10;678:15:10;;-1:-1:-1;;;;;678:15:10;;599:102;6291:10:9;-1:-1:-1;;;;;6291:21:9;;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;6269:45;;6344:11;6332:9;:23;6324:54;;;;-1:-1:-1;;;6324:54:9;;14303:2:16;6324:54:9;;;14285:21:16;14342:2;14322:18;;;14315:30;-1:-1:-1;;;14361:18:16;;;14354:48;14419:18;;6324:54:9;14101:342:16;6324:54:9;6449:14;6466:23;6478:11;6466:9;:23;:::i;:::-;6449:40;;6523:12;6547:50;6565:27;6581:6;6589:2;6565:15;:27::i;:::-;6594:2;6547:17;:50::i;:::-;6538:59;;:6;:59;:::i;:::-;6523:74;-1:-1:-1;6611:8:9;;6607:73;;6635:34;;6643:10;;6635:34;;;;;6664:4;;6635:34;;;;6664:4;6643:10;6635:34;;;;;;;;;;;;;;;;;;;;;6607:73;6740:22;6765:13;6774:4;6765:6;:13;:::i;:::-;6740:38;;6788:10;6801:6;873:5:10;903:18;-1:-1:-1;;;;;903:18:10;;;;;;836:93;6801:6:9;6788:19;;6860:4;-1:-1:-1;;;;;6860:12:9;;6894:14;6860:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7012:395;7050:301;;;;;;;;7106:4;-1:-1:-1;;;;;7050:301:9;;;;;7144:2;7050:301;;;;;;7172:14;7050:301;;;;7225:19;7050:301;;;;7275:11;7050:301;;;;;;7321:15;7050:301;;;7365:7;7386:11;7012:24;:395::i;:::-;6994:413;5851:1563;-1:-1:-1;;;;;;;;;;5851:1563:9:o;22584:811::-;22687:20;;22797:21;:7;22815:2;22797:17;:21::i;:::-;22773:45;-1:-1:-1;22828:17:9;22848:20;:7;22865:2;22848:16;:20::i;:::-;22828:40;;23004:9;1071:6:10;1096:14;;;;1031:86;23004:9:9;22990:23;;:10;:23;;;22986:403;;803:18:10;;-1:-1:-1;;;;;803:18:10;23098:53:9;;-1:-1:-1;;;23098:53:9;;17210:6:16;17198:19;;23098:53:9;;;17180:38:16;17234:18;;;17227:34;;;-1:-1:-1;;;;;23098:26:9;;;;;;;17153:18:16;;23098:53:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;23083:68;-1:-1:-1;;;;;;23173:26:9;;23165:57;;;;-1:-1:-1;;;23165:57:9;;17730:2:16;23165:57:9;;;17712:21:16;17769:2;17749:18;;;17742:30;-1:-1:-1;;;17788:18:16;;;17781:48;17846:18;;23165:57:9;17528:342:16;23165:57:9;22986:403;;;23347:31;23364:13;23347:16;:31::i;:::-;23332:46;;22986:403;22709:686;;22584:811;;;:::o;6738:268:11:-;7652:10;7641:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;7641:7:11;-1:-1:-1;;;;;7641:21:11;;7633:54;;;;-1:-1:-1;;;7633:54:11;;;;;;;:::i;:::-;6872:8:::1;7785;7772:21;;:9;1071:6:10::0;1096:14;;;;1031:86;7772:9:11::1;:21;;;7764:45;;;;-1:-1:-1::0;;;7764:45:11::1;;;;;;;:::i;:::-;6921:1:::2;6900:18;:22;6892:56;;;::::0;-1:-1:-1;;;6892:56:11;;18077:2:16;6892:56:11::2;::::0;::::2;18059:21:16::0;18116:2;18096:18;;;18089:30;-1:-1:-1;;;18135:18:16;;;18128:51;18196:18;;6892:56:11::2;17875:345:16::0;6892:56:11::2;6959:40;6980:18;1121:24:13::0;:36;1053:111;12181:5092:9;12342:20;12364:14;12380:13;12410:41;12428:22;;12410:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;12410:17:9;;-1:-1:-1;;;12410:41:9:i;:::-;12341:110;;;;;;12527:42;12572:54;12609:7;12572:23;:54::i;:::-;12527:99;;12697:17;12717:51;12734:17;:33;;;12717:16;:51::i;:::-;12697:71;;12778:15;12796:12;978:4:10;1001:17;;;;;;;;935:90;12796:12:9;12778:30;-1:-1:-1;;;;;;12858:23:9;;:10;:23;12854:238;;12897:139;12938:5;12961:9;12988:6;13012:10;12897:23;:139::i;:::-;13075:7;;;;;;12181:5092;;:::o;12854:238::-;13134:19;13156:18;13168:5;13156:11;:18::i;:::-;13134:40;;13268:102;13299:17;:34;;;13347:13;13268:17;:102::i;:::-;13231:34;;;:139;873:5:10;903:18;;;;-1:-1:-1;;;;;903:18:10;-1:-1:-1;;;;;13420:24:9;:5;-1:-1:-1;;;;;13420:24:9;;13416:266;;13460:166;13499:6;13523:9;13550:17;:34;;;13602:10;13460:21;:166::i;:::-;13665:7;;;;;;;12181:5092;;:::o;13416:266::-;13748:37;;;;:41;13744:2913;;13896:117;13931:17;:37;;;13986:13;13896:17;:117::i;:::-;13856:37;;;:157;14434:32;;14509:31;14534:5;14509:24;:31::i;:::-;14480:60;;14598:18;14558:17;:37;;;:58;14554:155;;;14636:37;;;:58;;;14554:155;14816:120;14862:5;14885:17;:37;;;14816:28;:120::i;:::-;14789:147;-1:-1:-1;15335:28:9;;15331:1316;;15490:24;15477:9;:37;;15448:140;;;;-1:-1:-1;;;15448:140:9;;18427:2:16;15448:140:9;;;18409:21:16;;;18446:18;;;18439:30;18505:34;18485:18;;;18478:62;18557:18;;15448:140:9;18225:356:16;15448:140:9;15678:21;15702:36;15714:24;15702:9;:36;:::i;:::-;15678:60;-1:-1:-1;15760:17:9;;15756:107;;15801:43;;15809:10;;15801:43;;;;;15830:13;;15801:43;;;;15830:13;15809:10;15801:43;;;;;;;;;;;;;;;;;;;;;15756:107;15948:53;;-1:-1:-1;;;;;15948:27:9;;;:53;;;;;15976:24;;15948:53;;;;15976:24;15948:27;:53;;;;;;;;;;;;;;;;;;;;;16157:5;-1:-1:-1;;;;;16060:225:9;16125:10;-1:-1:-1;;;;;16060:225:9;16094:9;-1:-1:-1;;;;;16060:225:9;;16184:17;:37;;;16243:24;16060:225;;;;;;18760:25:16;;;18816:2;18801:18;;18794:34;18748:2;18733:18;;18586:248;16060:225:9;;;;;;;;15365:935;15331:1316;;;16437:1;16397:37;;;:41;16538:9;:13;16534:99;;16575:39;;16583:10;;16604:9;16575:39;;;;;;;;;16604:9;16583:10;16575:39;;;;;;;;;;;;;;;;;;;;;16534:99;13791:2866;;13744:2913;16723:24;16799:17;:37;;;16762:17;:34;;;:74;;;;:::i;:::-;16723:113;-1:-1:-1;16902:20:9;;16898:180;;16938:129;16985:5;17009:10;17037:16;16938:22;:129::i;:::-;17145:121;17188:5;17208:9;17231:25;17240:16;17231:6;:25;:::i;:::-;17145:22;:121::i;:::-;12270:5003;;;;;;;;12181:5092;;:::o;26092:471::-;-1:-1:-1;;;;;2103:23:10;;26225:30:9;2103:23:10;;;:16;:23;;;;;;26351:13:9;26368:1;26351:18;26343:48;;;;-1:-1:-1;;;26343:48:9;;19171:2:16;26343:48:9;;;19153:21:16;19210:2;19190:18;;;19183:30;-1:-1:-1;;;19229:18:16;;;19222:47;19286:18;;26343:48:9;18969:341:16;26343:48:9;1722:26:10;;26518:37:9;;:13;:37;:::i;:::-;1355:24:10;;1845:28;;;1819:7;1845:28;;;:18;:28;;;;;;26438:14:9;26444:8;26438:2;:14;:::i;:::-;:42;;;;:::i;:::-;:64;;;;:::i;:::-;:118;;;;:::i;:::-;26401:155;26092:471;-1:-1:-1;;;;;26092:471:9:o;1392:119:10:-;-1:-1:-1;;;;;1476:28:10;1453:4;1476:28;;;:21;:28;;;;;;;;;1392:119::o;3075:530:11:-;7652:10;7641:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;7641:7:11;-1:-1:-1;;;;;7641:21:11;;7633:54;;;;-1:-1:-1;;;7633:54:11;;;;;;;:::i;:::-;3258:15;3237:115:::1;;;::::0;-1:-1:-1;;;3237:115:11;;19517:2:16;3237:115:11::1;::::0;::::1;19499:21:16::0;19556:2;19536:18;;;19529:30;19595:34;19575:18;;;19568:62;-1:-1:-1;;;19646:18:16;;;19639:37;19693:19;;3237:115:11::1;19315:403:16::0;3237:115:11::1;3383:13;::::0;::::1;::::0;;::::1;::::0;:38:::1;;-1:-1:-1::0;1071:6:10;1096:14;;3400:21:11;;::::1;1096:14:10::0;;3400:21:11::1;;3383:38;3362:124;;;::::0;-1:-1:-1;;;3362:124:11;;19925:2:16;3362:124:11::1;::::0;::::1;19907:21:16::0;19964:2;19944:18;;;19937:30;20003:34;19983:18;;;19976:62;-1:-1:-1;;;20054:18:16;;;20047:37;20101:19;;3362:124:11::1;19723:403:16::0;3362:124:11::1;992:36:13::0;;;;;:6;:36;;;:26;:36;;;;;:48;3075:530:11:o;3554:44::-:1;3075:530:::0;;:::o;4882:328::-;7652:10;7641:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;7641:7:11;-1:-1:-1;;;;;7641:21:11;;7633:54;;;;-1:-1:-1;;;7633:54:11;;;;;;;:::i;:::-;1071:6:10;1096:14;;;4998:21:11::1;;:8;:21;;::::0;4990:47:::1;;;::::0;-1:-1:-1;;;4990:47:11;;20333:2:16;4990:47:11::1;::::0;::::1;20315:21:16::0;20372:2;20352:18;;;20345:30;-1:-1:-1;;;20391:18:16;;;20384:43;20444:18;;4990:47:11::1;20131:337:16::0;4990:47:11::1;1224:42:10::0;;;5111:1:11::1;1224:42:10::0;;;:26;:42;;;;;;5047:114:11::1;;;::::0;-1:-1:-1;;;5047:114:11;;20675:2:16;5047:114:11::1;::::0;::::1;20657:21:16::0;20714:2;20694:18;;;20687:30;-1:-1:-1;;;20733:18:16;;;20726:52;20795:18;;5047:114:11::1;20473:346:16::0;5047:114:11::1;2685:28:13::0;;;;;:6;:28;;;:18;:28;;;;;:34;3075:530:11: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;;21026:2:16;1442:53:12;;;21008:21:16;21065:2;21045:18;;;21038:30;-1:-1:-1;;;21084:18:16;;;21077:47;21141:18;;1442:53:12;20824: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;;21372:2:16;1910:58:12;;;21354:21:16;21411:2;21391:18;;;21384:30;-1:-1:-1;;;21430:18:16;;;21423:52;21492:18;;1910:58:12;21170:346:16;1910:58:12;1299:676;1174:801;;;:::o;2629:178:11:-;7652:10;7641:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;7641:7:11;-1:-1:-1;;;;;7641:21:11;;7633:54;;;;-1:-1:-1;;;7633:54:11;;;;;;;:::i;:::-;2750:8:::1;7785;7772:21;;:9;1071:6:10::0;1096:14;;;;1031:86;7772:9:11::1;:21;;;7764:45;;;;-1:-1:-1::0;;;7764:45:11::1;;;;;;;:::i;:::-;675:6:13::0;:31;;-1:-1:-1;;675:31:13;;;;;;;;;7697:1:11::1;4250:222:::0;;:::o;24964:737:9:-;25084:20;25177:19;25199:18;25211:5;25199:11;:18::i;:::-;25177:40;;25227:20;25250:28;25270:6;873:5:10;903:18;-1:-1:-1;;;;;903:18:10;;;;;;836:93;25270:6:9;25250:11;:28::i;:::-;25227:51;;25309:14;25293:30;;:13;:30;;;25289:406;;;25457:30;25473:14;25457:13;:30;:::i;:::-;25450:38;;:2;:38;:::i;:::-;25426:21;25441:5;25426:14;:21::i;:::-;:62;;;;:::i;:::-;25392:14;25370:19;1355:24:10;;;1279:107;25370:19:9;:36;;;;:::i;:::-;:119;;;;:::i;:::-;25339:150;;25289:406;;;25663:21;25678:5;25663:14;:21::i;:::-;25613:30;25630:13;25613:14;:30;:::i;:::-;25606:38;;:2;:38;:::i;:::-;25573:14;25551:19;1355:24:10;;;1279:107;25551:19:9;:36;;;;:::i;:::-;:93;;;;:::i;:::-;:133;;;;:::i;:::-;25520:164;;25289:406;25106:595;;24964:737;;;;:::o;5392:278:11:-;7652:10;7641:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;7641:7:11;-1:-1:-1;;;;;7641:21:11;;7633:54;;;;-1:-1:-1;;;7633:54:11;;;;;;;:::i;:::-;5530:8:::1;7785;7772:21;;:9;1071:6:10::0;1096:14;;;;1031:86;7772:9:11::1;:21;;;7764:45;;;;-1:-1:-1::0;;;7764:45:11::1;;;;;;;:::i;:::-;5581:1:::2;5558:20;:24;5550:58;;;::::0;-1:-1:-1;;;5550:58:11;;18077:2:16;5550:58:11::2;::::0;::::2;18059:21:16::0;18116:2;18096:18;;;18089:30;-1:-1:-1;;;18135:18:16;;;18128:51;18196:18;;5550:58:11::2;17875:345:16::0;5550:58:11::2;5619:44;5642:20;1240:26:13::0;:38;1170:115;774:261:11;7652:10;7641:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;7641:7:11;-1:-1:-1;;;;;7641:21:11;;7633:54;;;;-1:-1:-1;;;7633:54:11;;;;;;;:::i;:::-;905:8:::1;7785;7772:21;;:9;1071:6:10::0;1096:14;;;;1031:86;7772:9:11::1;:21;;;7764:45;;;;-1:-1:-1::0;;;7764:45:11::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;933:22:11;::::2;925:67;;;::::0;-1:-1:-1;;;925:67:11;;21723:2:16;925:67:11::2;::::0;::::2;21705:21:16::0;;;21742:18;;;21735:30;21801:34;21781:18;;;21774:62;21853:18;;925:67:11::2;21521:356:16::0;925:67:11::2;1003:25;1019:8;1003: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;;21026:2:16;585:53:12;;;21008:21:16;21065:2;21045:18;;;21038:30;-1:-1:-1;;;21084:18:16;;;21077:47;21141:18;;585:53:12;20824:341:16;585:53:12;688:18;;720:25;;;;;759:28;;;;;801:24;;;;658:177;;;;688:18;759:28;;801:24;658:177;22129:3:16;22107:16;;;;-1:-1:-1;;;;;;22103:36:16;22091:49;;22165:1;22156:11;;22149:27;;;;22201:2;22192:12;;22185:28;22238:2;22229:12;;22222:28;22275:2;22266:12;;21882:402;658:177:12;;;;;;;;;;;;;648:187;;451:391;;;:::o;1183:159:11:-;7652:10;7641:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;7641:7:11;-1:-1:-1;;;;;7641:21:11;;7633:54;;;;-1:-1:-1;;;7633:54:11;;;;;;;:::i;:::-;1288:8:::1;7785;7772:21;;:9;1071:6:10::0;1096:14;;;;1031:86;7772:9:11::1;:21;;;7764:45;;;;-1:-1:-1::0;;;7764:45:11::1;;;;;;;:::i;:::-;1308:27:::2;1332:1;1308:15;:27::i;2139:375:10:-:0;2199:7;2253:18;;-1:-1:-1;;;;;2253:18:10;;;;;;2103:23;;:16;:23;;;;;;;;;;;;;;;2371:1;2353:15;:19;:40;;;;;2392:1;2376:13;:17;2353:40;2332:104;;;;-1:-1:-1;;;2332:104:10;;19171:2:16;2332:104:10;;;19153:21:16;19210:2;19190:18;;;19183:30;-1:-1:-1;;;19229:18:16;;;19222:47;19286:18;;2332:104:10;18969:341:16;2332:104:10;2494:13;2476:15;2454:19;1355:24;;;1279:107;2454:19;:37;;;;:::i;:::-;:53;;;;:::i;3769:217:11:-;7652:10;7641:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;7641:7:11;-1:-1:-1;;;;;7641:21:11;;7633:54;;;;-1:-1:-1;;;7633:54:11;;;;;;;:::i;:::-;3880:8:::1;7785;7772:21;;:9;1071:6:10::0;1096:14;;;;1031:86;7772:9:11::1;:21;;;7764:45;;;;-1:-1:-1::0;;;7764:45:11::1;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;3908:19:11;::::2;3900:45;;;::::0;-1:-1:-1;;;3900:45:11;;13416:2:16;3900:45:11::2;::::0;::::2;13398:21:16::0;13455:2;13435:18;;;13428:30;-1:-1:-1;;;13474:18:16;;;13467:43;13527:18;;3900:45:11::2;13214:337:16::0;3900:45:11::2;3956:23;3973:5;3956:16;:23::i;23838:705:9:-:0;23922:18;24013:19;24035:18;24047:5;24035:11;:18::i;:::-;24013:40;;24063:20;24086:28;24106:6;873:5:10;903:18;-1:-1:-1;;;;;903:18:10;;;;;;836:93;24086:28:9;24063:51;;24145:14;24129:30;;:13;:30;;;24125:412;;;1355:24:10;;24280:30:9;24296:14;24280:13;:30;:::i;:::-;24273:38;;:2;:38;:::i;:::-;24233:21;24248:5;24233:14;:21::i;:::-;-1:-1:-1;;;;;1977:33:10;;1951:7;1977:33;;;:26;:33;;;;;;24204:50:9;;;;:::i;:::-;:107;;;;:::i;:::-;:129;;;;:::i;:::-;24175:158;;24125:412;;;1355:24:10;;24472:30:9;24489:13;24472:14;:30;:::i;:::-;24465:38;;:2;:38;:::i;:::-;:60;;;;:::i;:::-;24423:21;24438:5;24423:14;:21::i;:::-;-1:-1:-1;;;;;1977:33:10;;1951:7;1977:33;;;:26;:33;;;;;;24394:26:9;1886:131:10;1517:121;1571:16;1606:6;:25;;1599:32;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;1599:32:10;;;;;;;;;;;;;;;;;;;;;;;1517:121;:::o;6197:365:11:-;7652:10;7641:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;7641:7:11;-1:-1:-1;;;;;7641:21:11;;7633:54;;;;-1:-1:-1;;;7633:54:11;;;;;;;:::i;:::-;6335:8:::1;7785;7772:21;;:9;1071:6:10::0;1096:14;;;;1031:86;7772:9:11::1;:21;;;7764:45;;;;-1:-1:-1::0;;;7764:45:11::1;;;;;;;:::i;:::-;6363:22:::2;6379:5;6363:15;:22::i;:::-;6355:53;;;;-1:-1:-1::0;;;6355:53:11::2;;;;;;;:::i;:::-;6437:1;6426:8;:12;6418:50;;;::::0;-1:-1:-1;;;6418:50:11;;22838:2:16;6418:50:11::2;::::0;::::2;22820:21:16::0;22877:2;22857:18;;;22850:30;22916:27;22896:18;;;22889:55;22961:18;;6418:50:11::2;22636:349:16::0;6418:50:11::2;-1:-1:-1::0;;;;;2805:23:13;;:6;:23;;;:16;:23;;;;;;:34;;;6523:32:11;2805:34:13;;:23;6523:32:11::2;::::0;::::2;7697:1:::1;6197:365:::0;;;:::o;7315:281::-;7652:10;7641:7;471:12:10;;-1:-1:-1;;;;;471:12:10;;407:83;7641:7:11;-1:-1:-1;;;;;7641:21:11;;7633:54;;;;-1:-1:-1;;;7633:54:11;;;;;;;:::i;:::-;7465:8:::1;7785;7772:21;;:9;1071:6:10::0;1096:14;;;;1031:86;7772:9:11::1;:21;;;7764:45;;;;-1:-1:-1::0;;;7764:45:11::1;;;;;;;:::i;:::-;7493:22:::2;7509:5;7493:15;:22::i;:::-;7485:53;;;;-1:-1:-1::0;;;7485:53:11::2;;;;;;;:::i;:::-;-1:-1:-1::0;;;;;2935:33:13;;:6;:33;;;:26;:33;;;;;:43;;;7549:40:11::2;7697:1:::1;7315:281:::0;;;:::o;1564:1043:13:-;-1:-1:-1;;;;;1648:28:13;;:6;:28;;;:21;:28;;;;;;;;1627:95;;;;-1:-1:-1;;;1627:95:13;;23192:2:16;1627:95:13;;;23174:21:16;23231:2;23211:18;;;23204:30;-1:-1:-1;;;23250:18:16;;;23243:50;23310:18;;1627:95:13;22990:344:16;1627:95:13;-1:-1:-1;;;;;1861:28:13;;1892:5;1861:28;;;:21;:28;;;;;;;;:36;;-1:-1:-1;;1861:36:13;;;1907:16;:23;;;;;:27;;;1944:26;:33;;;;;:37;;;2040:25;:32;;2225:160;2236:7;2232:1;:11;2225:160;;;2296:5;-1:-1:-1;;;;;2264:37:13;:6;:25;;2290:1;2264:28;;;;;;;;:::i;:::-;;;;;;;;;;;-1:-1:-1;;;;;2264:28:13;2260:81;2321:5;2260:81;2371:1;2366:6;2225:160;;;2404:7;2399:1;:12;2395:206;;2441:1;2431:7;:11;2427:119;;;2493:25;2519:11;2529:1;2519:7;:11;:::i;:::-;2493:38;;;;;;;;:::i;:::-;;;;;;;;;;;2462:25;:28;;-1:-1:-1;;;;;2493:38:13;;;;2488:1;;2462:28;;;;;;:::i;:::-;;;;;;;;;:69;;;;;-1:-1:-1;;;;;2462:69:13;;;;;-1:-1:-1;;;;;2462:69:13;;;;;;2427:119;2559:25;:31;;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;;2559:31:13;;;;;-1:-1:-1;;;;;;2559:31:13;;;;;;1617:990;;1564: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;;23805:2:16;2460:63:0;;;23787:21:16;23844:2;23824:18;;;23817:30;23883:33;23863:18;;;23856:61;23934:18;;2460:63:0;23603:355:16;2460:63:0;1759:1;2598:7;:18;2336:287::o;2976:247:10:-;3116:37;;;;;;;;;;;;;;;;-1:-1:-1;;;;;3116:37:10;-1:-1:-1;;;3116:37:10;;;3086:77;;3035:5;;;;-1:-1:-1;;;;;3086:16:10;;;:77;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3052:111;;;3191:15;3180:36;;;;;;;;;;;;:::i;:::-;3173:43;2976:247;-1:-1:-1;;;2976:247:10:o;26569:475:9:-;26663:7;26733:21;26757:17;26768:5;26757:10;:17::i;:::-;26733:41;;26811:134;26858:5;26878:10;26910:4;26929:6;26811:26;:134::i;:::-;27024:13;27004:17;27015:5;27004:10;:17::i;:::-;:33;;;;:::i;:::-;26997:40;26569:475;-1:-1:-1;;;;26569:475:9:o;7420:3667::-;7577:22;7662:29;7678:6;:12;;;7662:15;:29::i;:::-;7654:60;;;;-1:-1:-1;;;7654:60:9;;;;;;;:::i;:::-;7745:22;;;;7724:119;;;;-1:-1:-1;;;7724:119:9;;24848:2:16;7724:119:9;;;24830:21:16;24887:2;24867:18;;;24860:30;24926:34;24906:18;;;24899:62;-1:-1:-1;;;24977:18:16;;;24970:34;25021:19;;7724:119:9;24646:400:16;7724:119:9;8078:24;8105:86;8134:6;:13;;;8161:6;:20;;;8105:15;:86::i;:::-;8078:113;;8228:1;8209:16;:20;8201:62;;;;-1:-1:-1;;;8201:62:9;;25253:2:16;8201:62:9;;;25235:21:16;25292:2;25272:18;;;25265:30;25331:31;25311:18;;;25304:59;25380:18;;8201:62:9;25051:353:16;8201:62:9;8334:37;8374:99;8403:6;:26;;;8443:6;:20;;;8374:15;:99::i;:::-;8334:139;;8504:6;:26;;;8534:1;8504:31;:68;;;;8571:1;8539:29;:33;8504:68;8483:142;;;;-1:-1:-1;;;8483:142:9;;25611:2:16;8483:142:9;;;25593:21:16;25650:2;25630:18;;;25623:30;25689:29;25669:18;;;25662:57;25736:18;;8483:142:9;25409:351:16;8483:142:9;8817:18;;;;1224:42:10;;8770:22:9;1224:42:10;;;:26;:42;;;;;;;8846:62:9;;;;-1:-1:-1;;;8846:62:9;;25967:2:16;8846:62:9;;;25949:21:16;26006:2;25986:18;;;25979:30;-1:-1:-1;;;26025:18:16;;;26018:51;26086:18;;8846:62:9;25765:345:16;8846:62:9;9059:28;9090:210;9119:137;9156:6;:18;;;9192:6;:12;;;9222:6;:20;;;9119:19;:137::i;:::-;9270:6;:20;;;9090:15;:210::i;:::-;9059:241;-1:-1:-1;9350:52:9;9373:29;9059:241;9350:52;:::i;:::-;9331:16;:71;9310:137;;;;-1:-1:-1;;;9310:137:9;;26317:2:16;9310:137:9;;;26299:21:16;26356:2;26336:18;;;26329:30;-1:-1:-1;;;26375:18:16;;;26368:49;26434:18;;9310:137:9;26115:343:16;9310:137:9;9915:27;9945:291;9982:244;;;;;;;;10029:1;9982:244;;;;;;10066:20;9982:244;;;;10125:29;9982:244;;;;10189:6;:22;;;9982:244;;;9945:23;:291::i;:::-;9915:321;;10285:19;10307:13;803:18:10;;-1:-1:-1;;;;;803:18:10;;707:123;10307:13:9;10285:35;;10397:121;10439:6;:12;;;10474:6;10495;:13;;;10397:21;:121::i;:::-;10856:6;-1:-1:-1;;;;;10856:32:9;;10896:11;10922:6;:12;;;10948:6;:13;;;10975:6;:18;;;11007:14;11035:7;11056:14;10856: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;;27689:2:16;14912:62:8;;;27671:21:16;27728:2;27708:18;;;27701:30;-1:-1:-1;;;27747:18:16;;;27740:51;27808:18;;14912:62:8;27487: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;;28039:2:16;13031:60:8;;;28021:21:16;28078:2;28058:18;;;28051:30;-1:-1:-1;;;28097:18:16;;;28090:50;28157:18;;13031:60:8;27837:344:16;13031:60:8;-1:-1:-1;13168:29:8;13184:3;13168:29;13162:36;;12935:305::o;27050:199:9:-;27117:7;-1:-1:-1;;;;;;27144:22:9;;;27136:54;;;;-1:-1:-1;;;27136:54:9;;28388:2:16;27136:54:9;;;28370:21:16;28427:2;28407:18;;;28400:30;-1:-1:-1;;;28446:18:16;;;28439:49;28505:18;;27136:54:9;28186:343:16;27136:54:9;-1:-1:-1;27231:8:9;27050:199::o;17279:2765::-;17375:12;17389:7;17398;17826:33;17862:10;678:15:10;;-1:-1:-1;;;;;678:15:10;;599:102;17862:10:9;-1:-1:-1;;;;;17862:18:9;;17894:22;17862:64;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;17862:64:9;;;;;;;;;;;;:::i;:::-;17826:100;;18331:25;18359:81;18409:13;:21;;;18359:36;:81::i;:::-;18331:109;;18458:34;18474:17;18458:15;:34::i;:::-;18450:67;;;;-1:-1:-1;;;18450:67:9;;23192:2:16;18450:67:9;;;23174:21:16;23231:2;23211:18;;;23204:30;-1:-1:-1;;;23250:18:16;;;23243:50;23310:18;;18450:67:9;22990:344:16;18450:67:9;18584:21;18608:29;18619:17;18608:10;:29::i;:::-;18584:53;;18691:19;18713:13;803:18:10;;-1:-1:-1;;;;;803:18:10;;707:123;18713:13:9;18691:35;;18959:28;18990:6;-1:-1:-1;;;;;18990:34:9;;19038:22;18990:80;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;18990:80:9;;;;;;;;;;;;:::i;:::-;18959:111;;19162:22;19219:13;19187:29;19198:17;19187:10;:29::i;:::-;:45;;;;:::i;:::-;19162:70;;19327:48;19390:6;-1:-1:-1;;;;;19390:31:9;;19422:15;19390:48;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;19390:48:9;;;;;;;;;;;;:::i;:::-;19327:111;;19581:51;19603:13;:28;;;1224:42:10;;1198:7;1224:42;;;:26;:42;;;;;;;1123:150;19581:51:9;19557:8;:20;;;:75;19536:145;;;;-1:-1:-1;;;19536:145:9;;33674:2:16;19536:145:9;;;33656:21:16;33713:2;33693:18;;;33686:30;33752:25;33732:18;;;33725:53;33795:18;;19536:145:9;33472:347:16;19536:145:9;19888:13;:22;;;-1:-1:-1;;;;;19774:146:9;19846:13;:28;;;19804:13;:28;;;19774:146;;;;;;;;;;;;19952:16;;;;19982:14;;-1:-1:-1;20010:17:9;;-1:-1:-1;17279:2765:9;;-1:-1:-1;;;;;;17279:2765:9:o;20050:752::-;20276:9;:14;20268:62;;;;-1:-1:-1;;;20268:62:9;;34026:2:16;20268:62:9;;;34008:21:16;34065:2;34045:18;;;34038:30;34104:34;34084:18;;;34077:62;-1:-1:-1;;;34155:18:16;;;34148:33;34198:19;;20268:62:9;33824:399:16;20268:62:9;20372:10;903:18:10;-1:-1:-1;;;;;903:18:10;;;;;;;20459:22:9;;;;:36;;;;;20485:10;20459:36;20455:341;;;20566:21;;-1:-1:-1;;;20566:21:9;;;;;1877:25:16;;;-1:-1:-1;;;;;20566:13:9;;;;;1850:18:16;;20566:21:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;20601:35:9;;-1:-1:-1;;;;;20601:27:9;;;-1:-1:-1;20601:35:9;;;;;-1:-1:-1;20629:6:9;;20601:35;;;;20629:6;20601:27;:35;;;;;;;;;;;;;;;;;;;;;20455:341;;;20667:118;20714:5;20738:9;20765:6;20667:22;:118::i;:::-;20197:605;20050:752;;;;:::o;20808:1394::-;21038:9;:14;21030:45;;;;-1:-1:-1;;;21030:45:9;;34430:2:16;21030:45:9;;;34412:21:16;34469:2;34449:18;;;34442:30;-1:-1:-1;;;34488:18:16;;;34481:48;34546:18;;21030:45:9;34228:342:16;21030:45:9;21289:10;21285:911;;;873:5:10;903:18;21343:23:9;;-1:-1:-1;;;21343:23:9;;;;;1877:25:16;;;903:18:10;;;;-1:-1:-1;;;;;903:18:10;;21343:15:9;;1850:18:16;;21343:23:9;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21430:9;-1:-1:-1;;;;;21422:27:9;:48;21459:10;21450:6;:19;;;;:::i;:::-;21422:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;21539:14:9;;21535:93;;21573:40;;21581:10;;21573:40;;;;;21602:10;;21573:40;;;;21602:10;21581;21573:40;;;;;;;;;;;;;;;;;;;;;21535:93;21285:911;;;21693:10;903:18:10;;;;-1:-1:-1;;;;;903:18:10;21782:139:9;903:18:10;21861:9:9;21888:19;21897:10;21888:6;:19;:::i;21782:139::-;21990:14;;21986:200;;22024:147;22083:4;22111:10;22143;763:205:3;902:58;;-1:-1:-1;;;;;34767:32:16;;902:58:3;;;34749:51:16;34816:18;;;34809:34;;;875:86:3;;895:5;;-1:-1:-1;;;925:23:3;34722: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;;35056:2:16;12721:60:8;;;35038:21:16;35095:2;35075:18;;;35068:30;-1:-1:-1;;;35114:18:16;;;35107:49;35173:18;;12721:60:8;34854: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;;35404:2:16;14595:62:8;;;35386:21:16;35443:2;35423:18;;;35416:30;-1:-1:-1;;;35462:18:16;;;35455:51;35523:18;;14595:62:8;35202:345:16;1291:267:13;-1:-1:-1;;;;;1372:28:13;;:6;:28;;;:21;:28;;;;;;;;:37;1351:108;;;;-1:-1:-1;;;1351:108:13;;35754:2:16;1351:108:13;;;35736:21:16;35793:2;35773:18;;;35766:30;35832:26;35812:18;;;35805:54;35876:18;;1351:108:13;35552:348:16;1351:108:13;-1:-1:-1;;;;;1469:28:13;:6;:28;;;:21;:28;;;;;:35;;-1:-1:-1;;1469:35:13;1500:4;1469:35;;;;;;1514:25;:37;;;;;;;;;;;;;;-1:-1:-1;;;;;;1514:37:13;;;;;;1291:267::o;3229:370:10:-;3457:64;;;3515:4;3457:64;;;;5329:51:16;;;;3457:64:10;;;;;;;;;;5302:18:16;;;;3457:64:10;;;;;;;-1:-1:-1;;;;;3457:64:10;-1:-1:-1;;;3457:64:10;;;3423:112;;3287:15;;;;-1:-1:-1;;;;;3423:16:10;;;:112;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3377:158;;;3566:14;3555:37;;;;;;;;;;;;:::i;974:241:3:-;1139:68;;-1:-1:-1;;;;;36163:15:16;;;1139:68:3;;;36145:34:16;36215:15;;36195:18;;;36188:43;36247:18;;;36240:34;;;1112:96:3;;1132:5;;-1:-1:-1;;;1162:27:3;36080:18:16;;1139:68:3;35905: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;;;36497:34:16;-1:-1:-1;;;;;36567:15:16;;;36547:18;;;36540:43;1846:15:3;;;;;36432:18:16;;1846:39:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:44;1829:62;1808:163;;;;-1:-1:-1;;;1808:163:3;;36796:2:16;1808:163:3;;;36778:21:16;36835:2;36815:18;;;36808:30;36874:34;36854:18;;;36847:62;-1:-1:-1;;;36925:18:16;;;36918:52;36987:19;;1808:163:3;36594:418:16;1808:163:3;2008:62;;-1:-1:-1;;;;;34767:32:16;;2008:62:3;;;34749:51:16;34816:18;;;34809:34;;;1981:90:3;;2001:5;;-1:-1:-1;;;2031:22:3;34722:18:16;;2008:62:3;34575: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;;37469:2:16;4351:85:3;;;37451:21:16;37508:2;37488:18;;;37481:30;37547:34;37527:18;;;37520:62;-1:-1:-1;;;37598:18:16;;;37591:40;37648:19;;4351:85:3;37267: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;;38287:2:16;7908:60:4;;;38269:21:16;38326:2;38306:18;;;38299:30;38365:31;38345:18;;;38338:59;38414:18;;7908:60:4;38085: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;1913:114::-;1997:4;1990:5;1986:16;1979:5;1976:27;1966:55;;2017:1;2014;2007:12;2032:311;2098:6;2106;2159:2;2147:9;2138:7;2134:23;2130:32;2127:52;;;2175:1;2172;2165:12;2127:52;2211:9;2198:23;2188:33;;2271:2;2260:9;2256:18;2243:32;2284:29;2307:5;2284:29;:::i;2348:521::-;2432:6;2440;2448;2456;2509:3;2497:9;2488:7;2484:23;2480:33;2477:53;;;2526:1;2523;2516:12;2477:53;2562:9;2549:23;2539:33;;2622:2;2611:9;2607:18;2594:32;2635:30;2659:5;2635:30;:::i;:::-;2684:5;-1:-1:-1;2736:2:16;2721:18;;2708:32;;-1:-1:-1;2792:2:16;2777:18;;2764:32;2805;2764;2805;:::i;:::-;2348:521;;;;-1:-1:-1;2348:521:16;;-1:-1:-1;;2348:521:16:o;2874:247::-;2933:6;2986:2;2974:9;2965:7;2961:23;2957:32;2954:52;;;3002:1;2999;2992:12;2954:52;3041:9;3028:23;3060:31;3085:5;3060:31;:::i;3126:127::-;3187:10;3182:3;3178:20;3175:1;3168:31;3218:4;3215:1;3208:15;3242:4;3239:1;3232:15;3258:253;3330:2;3324:9;3372:4;3360:17;;-1:-1:-1;;;;;3392:34:16;;3428:22;;;3389:62;3386:88;;;3454:18;;:::i;:::-;3490:2;3483:22;3258:253;:::o;3516:255::-;3588:2;3582:9;3630:6;3618:19;;-1:-1:-1;;;;;3652:34:16;;3688:22;;;3649:62;3646:88;;;3714:18;;:::i;3776:255::-;3848:2;3842:9;3890:6;3878:19;;-1:-1:-1;;;;;3912:34:16;;3948:22;;;3909:62;3906:88;;;3974:18;;:::i;4036:275::-;4107:2;4101:9;4172:2;4153:13;;-1:-1:-1;;4149:27:16;4137:40;;-1:-1:-1;;;;;4192:34:16;;4228:22;;;4189:62;4186:88;;;4254:18;;:::i;:::-;4290:2;4283:22;4036:275;;-1:-1:-1;4036:275:16:o;4316:186::-;4364:4;-1:-1:-1;;;;;4389:6:16;4386:30;4383:56;;;4419:18;;:::i;:::-;-1:-1:-1;4485:2:16;4464:15;-1:-1:-1;;4460:29:16;4491:4;4456:40;;4316:186::o;4507:671::-;4575:6;4628:2;4616:9;4607:7;4603:23;4599:32;4596:52;;;4644:1;4641;4634:12;4596:52;4684:9;4671:23;-1:-1:-1;;;;;4709:6:16;4706:30;4703:50;;;4749:1;4746;4739:12;4703:50;4772:22;;4825:4;4817:13;;4813:27;-1:-1:-1;4803:55:16;;4854:1;4851;4844:12;4803:55;4890:2;4877:16;4915:48;4931:31;4959:2;4931:31;:::i;:::-;4915:48;:::i;:::-;4986:2;4979:5;4972:17;5026:7;5021:2;5016;5012;5008:11;5004:20;5001:33;4998:53;;;5047:1;5044;5037:12;4998:53;5102:2;5097;5093;5089:11;5084:2;5077:5;5073:14;5060:45;5146:1;5125:14;;;5141:2;5121:23;5114:34;;;;5129:5;4507:671;-1:-1:-1;;;;4507:671:16:o;5391:313::-;5458:6;5466;5519:2;5507:9;5498:7;5494:23;5490:32;5487:52;;;5535:1;5532;5525:12;5487:52;5574:9;5561:23;5593:30;5617:5;5593:30;:::i;:::-;5642:5;5694:2;5679:18;;;;5666:32;;-1:-1:-1;;;5391:313:16:o;5709:591::-;5779:6;5787;5840:2;5828:9;5819:7;5815:23;5811:32;5808:52;;;5856:1;5853;5846:12;5808:52;5896:9;5883:23;-1:-1:-1;;;;;5966:2:16;5958:6;5955:14;5952:34;;;5982:1;5979;5972:12;5952:34;6020:6;6009:9;6005:22;5995:32;;6065:7;6058:4;6054:2;6050:13;6046:27;6036:55;;6087:1;6084;6077:12;6036:55;6127:2;6114:16;6153:2;6145:6;6142:14;6139:34;;;6169:1;6166;6159:12;6139:34;6214:7;6209:2;6200:6;6196:2;6192:15;6188:24;6185:37;6182:57;;;6235:1;6232;6225:12;6182:57;6266:2;6258:11;;;;;6288:6;;-1:-1:-1;5709:591:16;;-1:-1:-1;;;;5709:591:16:o;6305:523::-;6379:6;6387;6395;6448:2;6436:9;6427:7;6423:23;6419:32;6416:52;;;6464:1;6461;6454:12;6416:52;6503:9;6490:23;6522:30;6546:5;6522:30;:::i;:::-;6571:5;-1:-1:-1;6628:2:16;6613:18;;6600:32;6641:33;6600:32;6641:33;:::i;:::-;6693:7;-1:-1:-1;6752:2:16;6737:18;;6724:32;6765:31;6724:32;6765:31;:::i;:::-;6815:7;6805:17;;;6305:523;;;;;:::o;7025:245::-;7083:6;7136:2;7124:9;7115:7;7111:23;7107:32;7104:52;;;7152:1;7149;7142:12;7104:52;7191:9;7178:23;7210:30;7234:5;7210:30;:::i;8235:118::-;8321:5;8314:13;8307:21;8300:5;8297:32;8287:60;;8343:1;8340;8333:12;8358:380;8422:6;8430;8483:2;8471:9;8462:7;8458:23;8454:32;8451:52;;;8499:1;8496;8489:12;8451:52;8538:9;8525:23;8557:30;8581:5;8557:30;:::i;:::-;8606:5;-1:-1:-1;8663:2:16;8648:18;;8635:32;8676:30;8635:32;8676:30;:::i;8969:315::-;9037:6;9045;9098:2;9086:9;9077:7;9073:23;9069:32;9066:52;;;9114:1;9111;9104:12;9066:52;9153:9;9140:23;9172:31;9197:5;9172:31;:::i;9482:713::-;9576:6;9629:3;9617:9;9608:7;9604:23;9600:33;9597:53;;;9646:1;9643;9636:12;9597:53;9679:2;9673:9;9721:3;9713:6;9709:16;9791:6;9779:10;9776:22;-1:-1:-1;;;;;9743:10:16;9740:34;9737:62;9734:88;;;9802:18;;:::i;:::-;9838:2;9831:22;9875:23;;9907:29;9875:23;9907:29;:::i;:::-;9960:5;9952:6;9945:21;;10027:2;10016:9;10012:18;9999:32;9994:2;9986:6;9982:15;9975:57;10093:2;10082:9;10078:18;10065:32;10060:2;10052:6;10048:15;10041:57;10159:2;10148:9;10144:18;10131:32;10126:2;10118:6;10114:15;10107:57;10183:6;10173:16;;;9482:713;;;;:::o;10200:250::-;10285:1;10295:113;10309:6;10306:1;10303:13;10295:113;;;10385:11;;;10379:18;10366:11;;;10359:39;10331:2;10324:10;10295:113;;;-1:-1:-1;;10442:1:16;10424:16;;10417:27;10200:250::o;10455:270::-;10496:3;10534:5;10528:12;10561:6;10556:3;10549:19;10577:76;10646:6;10639:4;10634:3;10630:14;10623:4;10616:5;10612:16;10577:76;:::i;:::-;10707:2;10686:15;-1:-1:-1;;10682:29:16;10673:39;;;;10714:4;10669:50;;10455:270;-1:-1:-1;;10455:270:16:o;10730:217::-;10877:2;10866:9;10859:21;10840:4;10897:44;10937:2;10926:9;10922:18;10914:6;10897:44;:::i;11403:658::-;11574:2;11626:21;;;11696:13;;11599:18;;;11718:22;;;11545:4;;11574:2;11797:15;;;;11771:2;11756:18;;;11545:4;11840:195;11854:6;11851:1;11848:13;11840:195;;;11919:13;;-1:-1:-1;;;;;11915:39:16;11903:52;;12010:15;;;;11975:12;;;;11951:1;11869:9;11840:195;;;-1:-1:-1;12052:3:16;;11403:658;-1:-1:-1;;;;;;11403:658:16:o;12066:454::-;12142:6;12150;12158;12211:2;12199:9;12190:7;12186:23;12182:32;12179:52;;;12227:1;12224;12217:12;12179:52;12266:9;12253:23;12285:30;12309:5;12285:30;:::i;:::-;12334:5;-1:-1:-1;12391:2:16;12376:18;;12363:32;12404:33;12363:32;12404:33;:::i;:::-;12066:454;;12456:7;;-1:-1:-1;;;12510:2:16;12495:18;;;;12482:32;;12066:454::o;12525:344::-;12727:2;12709:21;;;12766:2;12746:18;;;12739:30;-1:-1:-1;;;12800:2:16;12785:18;;12778:50;12860:2;12845:18;;12525:344::o;12874:335::-;13076:2;13058:21;;;13115:2;13095:18;;;13088:30;-1:-1:-1;;;13149:2:16;13134:18;;13127:41;13200:2;13185:18;;12874:335::o;13912:184::-;13982:6;14035:2;14023:9;14014:7;14010:23;14006:32;14003:52;;;14051:1;14048;14041:12;14003:52;-1:-1:-1;14074:16:16;;13912:184;-1:-1:-1;13912:184:16:o;14448:127::-;14509:10;14504:3;14500:20;14497:1;14490:31;14540:4;14537:1;14530:15;14564:4;14561:1;14554:15;14580:151;14670:4;14663:12;;;14649;;;14645:31;;14688:14;;14685:40;;;14705:18;;:::i;14736:422::-;14825:1;14868:5;14825:1;14882:270;14903:7;14893:8;14890:21;14882:270;;;14962:4;14958:1;14954:6;14950:17;14944:4;14941:27;14938:53;;;14971:18;;:::i;:::-;15021:7;15011:8;15007:22;15004:55;;;15041:16;;;;15004:55;15120:22;;;;15080:15;;;;14882:270;;;14886:3;14736:422;;;;;:::o;15163:806::-;15212:5;15242:8;15232:80;;-1:-1:-1;15283:1:16;15297:5;;15232:80;15331:4;15321:76;;-1:-1:-1;15368:1:16;15382:5;;15321:76;15413:4;15431:1;15426:59;;;;15499:1;15494:130;;;;15406:218;;15426:59;15456:1;15447:10;;15470:5;;;15494:130;15531:3;15521:8;15518:17;15515:43;;;15538:18;;:::i;:::-;-1:-1:-1;;15594:1:16;15580:16;;15609:5;;15406:218;;15708:2;15698:8;15695:16;15689:3;15683:4;15680:13;15676:36;15670:2;15660:8;15657:16;15652:2;15646:4;15643:12;15639:35;15636:77;15633:159;;;-1:-1:-1;15745:19:16;;;15777:5;;15633:159;15824:34;15849:8;15843:4;15824:34;:::i;:::-;15894:6;15890:1;15886:6;15882:19;15873:7;15870:32;15867:58;;;15905:18;;:::i;:::-;15943:20;;15163:806;-1:-1:-1;;;15163:806:16:o;15974:140::-;16032:5;16061:47;16102:4;16092:8;16088:19;16082:4;16061:47;:::i;16119:217::-;16159:1;16185;16175:132;;16229:10;16224:3;16220:20;16217:1;16210:31;16264:4;16261:1;16254:15;16292:4;16289:1;16282:15;16175:132;-1:-1:-1;16321:9:16;;16119:217::o;16341:168::-;16414:9;;;16445;;16462:15;;;16456:22;;16442:37;16432:71;;16483:18;;:::i;16875:128::-;16942:9;;;16963:11;;;16960:37;;;16977:18;;:::i;17272:251::-;17342:6;17395:2;17383:9;17374:7;17370:23;17366:32;17363:52;;;17411:1;17408;17401:12;17363:52;17443:9;17437:16;17462:31;17487:5;17462:31;:::i;18839:125::-;18904:9;;;18925:10;;;18922:36;;;18938:18;;:::i;22289:342::-;22491:2;22473:21;;;22530:2;22510:18;;;22503:30;-1:-1:-1;;;22564:2:16;22549:18;;22542:48;22622:2;22607:18;;22289:342::o;23339:127::-;23400:10;23395:3;23391:20;23388:1;23381:31;23431:4;23428:1;23421:15;23455:4;23452:1;23445:15;23471:127;23532:10;23527:3;23523:20;23520:1;23513:31;23563:4;23560:1;23553:15;23587:4;23584:1;23577:15;23963:287;24092:3;24130:6;24124:13;24146:66;24205:6;24200:3;24193:4;24185:6;24181:17;24146:66;:::i;:::-;24228:16;;;;;23963:287;-1:-1:-1;;23963:287:16:o;24255:134::-;24332:13;;24354:29;24332:13;24354:29;:::i;:::-;24255:134;;;:::o;24394:247::-;24462:6;24515:2;24503:9;24494:7;24490:23;24486:32;24483:52;;;24531:1;24528;24521:12;24483:52;24563:9;24557:16;24582:29;24605:5;24582:29;:::i;26463:628::-;26775:1;26771;26766:3;26762:11;26758:19;26750:6;26746:32;26735:9;26728:51;26815:6;26810:2;26799:9;26795:18;26788:34;26870:6;26862;26858:19;26853:2;26842:9;26838:18;26831:47;26914:6;26909:2;26898:9;26894:18;26887:34;26970:10;26962:6;26958:23;26952:3;26941:9;26937:19;26930:52;27019:3;27013;27002:9;26998:19;26991:32;26709:4;27040:45;27080:3;27069:9;27065:19;27057:6;27040:45;:::i;:::-;27032:53;26463:628;-1:-1:-1;;;;;;;;26463:628:16:o;27096:175::-;27174:13;;-1:-1:-1;;;;;27216:30:16;;27206:41;;27196:69;;27261:1;27258;27251:12;27276:206;27345:6;27398:2;27386:9;27377:7;27373:23;27369:32;27366:52;;;27414:1;27411;27404:12;27366:52;27437:39;27466:9;27437:39;:::i;28534:136::-;28612:13;;28634:30;28612:13;28634:30;:::i;28675:136::-;28753:13;;28775:30;28753:13;28775:30;:::i;28816:441::-;28869:5;28922:3;28915:4;28907:6;28903:17;28899:27;28889:55;;28940:1;28937;28930:12;28889:55;28969:6;28963:13;29000:48;29016:31;29044:2;29016:31;:::i;29000:48::-;29073:2;29064:7;29057:19;29119:3;29112:4;29107:2;29099:6;29095:15;29091:26;29088:35;29085:55;;;29136:1;29133;29126:12;29085:55;29149:77;29223:2;29216:4;29207:7;29203:18;29196:4;29188:6;29184:17;29149:77;:::i;29262:1291::-;29336:5;29389:3;29382:4;29374:6;29370:17;29366:27;29356:55;;29407:1;29404;29397:12;29356:55;29436:6;29430:13;29462:4;-1:-1:-1;;;;;29481:2:16;29478:26;29475:52;;;29507:18;;:::i;:::-;29547:36;29579:2;29574;29571:1;29567:10;29563:19;29547:36;:::i;:::-;29617:15;;;29703:1;29699:10;;;;29687:23;;29683:32;;;29648:12;;;;29727:15;;;29724:35;;;29755:1;29752;29745:12;29724:35;29791:2;29783:6;29779:15;29803:721;29819:6;29814:3;29811:15;29803:721;;;29897:4;29891:3;29886;29882:13;29878:24;29875:114;;;29943:1;29972:2;29968;29961:14;29875:114;30015:22;;:::i;:::-;30070:3;30064:10;30057:5;30050:25;30126:2;30121:3;30117:12;30111:19;30106:2;30099:5;30095:14;30088:43;30154:2;30199;30194:3;30190:12;30184:19;30216:31;30239:7;30216:31;:::i;:::-;30267:14;;;30260:31;30314:2;30350:12;;;30344:19;30376:31;30344:19;30376:31;:::i;:::-;30427:14;;;30420:31;30464:18;;30502:12;;;;29845:4;29836:14;29803:721;;;-1:-1:-1;30542:5:16;29262:1291;-1:-1:-1;;;;;;29262:1291:16:o;30558:1502::-;30648:6;30701:2;30689:9;30680:7;30676:23;30672:32;30669:52;;;30717:1;30714;30707:12;30669:52;30750:9;30744:16;-1:-1:-1;;;;;30820:2:16;30812:6;30809:14;30806:34;;;30836:1;30833;30826:12;30806:34;30859:22;;;;30915:6;30897:16;;;30893:29;30890:49;;;30935:1;30932;30925:12;30890:49;30961:22;;:::i;:::-;31006:31;31034:2;31006:31;:::i;:::-;30999:5;30992:46;31070:41;31107:2;31103;31099:11;31070:41;:::i;:::-;31065:2;31058:5;31054:14;31047:65;31144:41;31181:2;31177;31173:11;31144:41;:::i;:::-;31139:2;31132:5;31128:14;31121:65;31218:41;31255:2;31251;31247:11;31218:41;:::i;:::-;31213:2;31206:5;31202:14;31195:65;31307:3;31303:2;31299:12;31293:19;31287:3;31280:5;31276:15;31269:44;31346:42;31383:3;31379:2;31375:12;31346:42;:::i;:::-;31340:3;31333:5;31329:15;31322:67;31422:41;31458:3;31454:2;31450:12;31422:41;:::i;:::-;31416:3;31409:5;31405:15;31398:66;31503:3;31499:2;31495:12;31489:19;31533:2;31523:8;31520:16;31517:36;;;31549:1;31546;31539:12;31517:36;31586:55;31633:7;31622:8;31618:2;31614:17;31586:55;:::i;:::-;31580:3;31573:5;31569:15;31562:80;;31661:3;31696:41;31733:2;31729;31725:11;31696:41;:::i;:::-;31680:14;;;31673:65;31757:3;31791:11;;;31785:18;31815:16;;;31812:36;;;31844:1;31841;31834:12;31812:36;31880:76;31948:7;31937:8;31933:2;31929:17;31880:76;:::i;:::-;31864:14;;;31857:100;;;;-1:-1:-1;31976:3:16;32017:11;;;32011:18;31995:14;;;31988:42;;;;-1:-1:-1;31868:5:16;30558:1502;-1:-1:-1;;;30558:1502:16:o;32065:335::-;32144:6;32197:2;32185:9;32176:7;32172:23;32168:32;32165:52;;;32213:1;32210;32203:12;32165:52;32246:9;32240:16;-1:-1:-1;;;;;32271:6:16;32268:30;32265:50;;;32311:1;32308;32301:12;32265:50;32334:60;32386:7;32377:6;32366:9;32362:22;32334:60;:::i;32405:1062::-;32511:6;32564:2;32552:9;32543:7;32539:23;32535:32;32532:52;;;32580:1;32577;32570:12;32532:52;32613:9;32607:16;-1:-1:-1;;;;;32683:2:16;32675:6;32672:14;32669:34;;;32699:1;32696;32689:12;32669:34;32722:22;;;;32778:6;32760:16;;;32756:29;32753:49;;;32798:1;32795;32788:12;32753:49;32824:22;;:::i;:::-;32869:31;32897:2;32869:31;:::i;:::-;32862:5;32855:46;32947:2;32943;32939:11;32933:18;32928:2;32921:5;32917:14;32910:42;32998:2;32994;32990:11;32984:18;32979:2;32972:5;32968:14;32961:42;33035:41;33072:2;33068;33064:11;33035:41;:::i;:::-;33030:2;33023:5;33019:14;33012:65;33124:3;33120:2;33116:12;33110:19;33104:3;33097:5;33093:15;33086:44;33163:42;33200:3;33196:2;33192:12;33163:42;:::i;:::-;33157:3;33150:5;33146:15;33139:67;33253:3;33249:2;33245:12;33239:19;33233:3;33226:5;33222:15;33215:44;33298:3;33294:2;33290:12;33284:19;33328:2;33318:8;33315:16;33312:36;;;33344:1;33341;33334:12;33312:36;33381:55;33428:7;33417:8;33413:2;33409:17;33381:55;:::i;:::-;33375:3;33364:15;;33357:80;-1:-1:-1;33368:5:16;32405:1062;-1:-1:-1;;;;;32405:1062:16:o;37017:245::-;37084:6;37137:2;37125:9;37116:7;37112:23;37108:32;37105:52;;;37153:1;37150;37143:12;37105:52;37185:9;37179:16;37204:28;37226:5;37204:28;:::i
Swarm Source
ipfs://043ecf0d1429bfc7866a5607e98ae2b1cca0eeef46c7279047c0211efe0f0767
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.