Overview
S Balance
0 S
S Value
-More Info
Private Name Tags
ContractCreator
Loading...
Loading
Contract Name:
Forwarder
Compiler Version
v0.8.19+commit.7dd6d404
Contract Source Code (Solidity)
/** *Submitted for verification at SonicScan.org on 2024-12-18 */ // SPDX-License-Identifier: GPL-3.0-or-later // Hydrometer combines powerful liquidity incentives, low slippage, and a vote-locked governance model using $HYDRO and $veHYDRO tokens, ensuring an innovative and decentralized experience for all users. //https://x.com/Hydrometer_Fi pragma solidity 0.8.19; // OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol) // OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } } // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } } /** * @dev String operations. */ library Strings { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } } /** * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. * * These functions can be used to verify that a message was signed by the holder * of the private keys of a given address. */ library ECDSA { enum RecoverError { NoError, InvalidSignature, InvalidSignatureLength, InvalidSignatureS, InvalidSignatureV // Deprecated in v4.8 } function _throwError(RecoverError error) private pure { if (error == RecoverError.NoError) { return; // no error: do nothing } else if (error == RecoverError.InvalidSignature) { revert("ECDSA: invalid signature"); } else if (error == RecoverError.InvalidSignatureLength) { revert("ECDSA: invalid signature length"); } else if (error == RecoverError.InvalidSignatureS) { revert("ECDSA: invalid signature 's' value"); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature` or error string. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. * * Documentation for signature generation: * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { if (signature.length == 65) { bytes32 r; bytes32 s; uint8 v; // ecrecover takes the signature parameters, and the only way to get them // currently is to use assembly. /// @solidity memory-safe-assembly assembly { r := mload(add(signature, 0x20)) s := mload(add(signature, 0x40)) v := byte(0, mload(add(signature, 0x60))) } return tryRecover(hash, v, r, s); } else { return (address(0), RecoverError.InvalidSignatureLength); } } /** * @dev Returns the address that signed a hashed message (`hash`) with * `signature`. This address can then be used for verification purposes. * * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: * this function rejects them by requiring the `s` value to be in the lower * half order, and the `v` value to be either 27 or 28. * * IMPORTANT: `hash` _must_ be the result of a hash operation for the * verification to be secure: it is possible to craft signatures that * recover to arbitrary addresses for non-hashed data. A safe way to ensure * this is by receiving a hash of the original message (which may otherwise * be too long), and then calling {toEthSignedMessageHash} on it. */ function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, signature); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. * * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] * * _Available since v4.3._ */ function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); uint8 v = uint8((uint256(vs) >> 255) + 27); return tryRecover(hash, v, r, s); } /** * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. * * _Available since v4.2._ */ function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, r, vs); _throwError(error); return recovered; } /** * @dev Overload of {ECDSA-tryRecover} that receives the `v`, * `r` and `s` signature fields separately. * * _Available since v4.3._ */ function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most // signatures from current libraries generate a unique signature with an s-value in the lower half order. // // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept // these malleable signatures as well. if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { return (address(0), RecoverError.InvalidSignatureS); } // If the signature is valid (and not malleable), return the signer address address signer = ecrecover(hash, v, r, s); if (signer == address(0)) { return (address(0), RecoverError.InvalidSignature); } return (signer, RecoverError.NoError); } /** * @dev Overload of {ECDSA-recover} that receives the `v`, * `r` and `s` signature fields separately. */ function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { (address recovered, RecoverError error) = tryRecover(hash, v, r, s); _throwError(error); return recovered; } /** * @dev Returns an Ethereum Signed Message, created from a `hash`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { // 32 is the length in bytes of hash, // enforced by the type signature above /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") mstore(0x1c, hash) message := keccak256(0x00, 0x3c) } } /** * @dev Returns an Ethereum Signed Message, created from `s`. This * produces hash corresponding to the one signed with the * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] * JSON-RPC method as part of EIP-191. * * See {recover}. */ function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); } /** * @dev Returns an Ethereum Signed Typed Data, created from a * `domainSeparator` and a `structHash`. This produces hash corresponding * to the one signed with the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] * JSON-RPC method as part of EIP-712. * * See {recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, "\x19\x01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) data := keccak256(ptr, 0x42) } } /** * @dev Returns an Ethereum Signed Data with intended validator, created from a * `validator` and `data` according to the version 0 of EIP-191. * * See {recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked("\x19\x00", validator, data)); } } pragma abicoder v2; interface IForwarder { struct ForwardRequest { address from; address to; uint256 value; uint256 gas; uint256 nonce; bytes data; uint256 validUntil; } event DomainRegistered(bytes32 indexed domainSeparator, bytes domainValue); event RequestTypeRegistered(bytes32 indexed typeHash, string typeStr); function getNonce(address from) external view returns(uint256); /** * verify the transaction would execute. * validate the signature and the nonce of the request. * revert if either signature or nonce are incorrect. * also revert if domainSeparator or requestTypeHash are not registered. */ function verify( ForwardRequest calldata forwardRequest, bytes32 domainSeparator, bytes32 requestTypeHash, bytes calldata suffixData, bytes calldata signature ) external view; /** * execute a transaction * @param forwardRequest - all transaction parameters * @param domainSeparator - domain used when signing this request * @param requestTypeHash - request type used when signing this request. * @param suffixData - the extension data used when signing this request. * @param signature - signature to validate. * * the transaction is verified, and then executed. * the success and ret of "call" are returned. * This method would revert only verification errors. target errors * are reported using the returned "success" and ret string */ function execute( ForwardRequest calldata forwardRequest, bytes32 domainSeparator, bytes32 requestTypeHash, bytes calldata suffixData, bytes calldata signature ) external payable returns (bool success, bytes memory ret); /** * Register a new Request typehash. * @param typeName - the name of the request type. * @param typeSuffix - any extra data after the generic params. * (must add at least one param. The generic ForwardRequest type is always registered by the constructor) */ function registerRequestType(string calldata typeName, string calldata typeSuffix) external; /** * Register a new domain separator. * The domain separator must have the following fields: name,version,chainId, verifyingContract. * the chainId is the current network's chainId, and the verifyingContract is this forwarder. * This method is given the domain name and version to create and register the domain separator value. * @param name the domain's display name * @param version the domain/protocol version */ function registerDomainSeparator(string calldata name, string calldata version) external; } contract Forwarder is IForwarder { using ECDSA for bytes32; string public constant GENERIC_PARAMS = "address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data,uint256 validUntil"; string public constant EIP712_DOMAIN_TYPE = "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"; mapping(bytes32 => bool) public typeHashes; mapping(bytes32 => bool) public domains; // Nonces of senders, used to prevent replay attacks mapping(address => uint256) private nonces; // solhint-disable-next-line no-empty-blocks receive() external payable {} function getNonce(address from) public view override returns (uint256) { return nonces[from]; } constructor() { string memory requestType = string(abi.encodePacked("ForwardRequest(", GENERIC_PARAMS, ")")); registerRequestTypeInternal(requestType); } function verify( ForwardRequest calldata req, bytes32 domainSeparator, bytes32 requestTypeHash, bytes calldata suffixData, bytes calldata sig) external override view { _verifyNonce(req); _verifySig(req, domainSeparator, requestTypeHash, suffixData, sig); } function execute( ForwardRequest calldata req, bytes32 domainSeparator, bytes32 requestTypeHash, bytes calldata suffixData, bytes calldata sig ) external payable override returns (bool success, bytes memory ret) { _verifySig(req, domainSeparator, requestTypeHash, suffixData, sig); _verifyAndUpdateNonce(req); require(req.validUntil == 0 || req.validUntil > block.number, "FWD: request expired"); uint gasForTransfer = 0; if ( req.value != 0 ) { gasForTransfer = 40000; //buffer in case we need to move eth after the transaction. } bytes memory callData = abi.encodePacked(req.data, req.from); require(gasleft()*63/64 >= req.gas + gasForTransfer, "FWD: insufficient gas"); // solhint-disable-next-line avoid-low-level-calls (success,ret) = req.to.call{gas : req.gas, value : req.value}(callData); if ( req.value != 0 && address(this).balance>0 ) { // can't fail: req.from signed (off-chain) the request, so it must be an EOA... payable(req.from).transfer(address(this).balance); } return (success,ret); } function _verifyNonce(ForwardRequest calldata req) internal view { require(nonces[req.from] == req.nonce, "FWD: nonce mismatch"); } function _verifyAndUpdateNonce(ForwardRequest calldata req) internal { require(nonces[req.from]++ == req.nonce, "FWD: nonce mismatch"); } function registerRequestType(string calldata typeName, string calldata typeSuffix) external override { for (uint i = 0; i < bytes(typeName).length; i++) { bytes1 c = bytes(typeName)[i]; require(c != "(" && c != ")", "FWD: invalid typename"); } string memory requestType = string(abi.encodePacked(typeName, "(", GENERIC_PARAMS, ",", typeSuffix)); registerRequestTypeInternal(requestType); } function registerDomainSeparator(string calldata name, string calldata version) external override { uint256 chainId; /* solhint-disable-next-line no-inline-assembly */ assembly { chainId := chainid() } bytes memory domainValue = abi.encode( keccak256(bytes(EIP712_DOMAIN_TYPE)), keccak256(bytes(name)), keccak256(bytes(version)), chainId, address(this)); bytes32 domainHash = keccak256(domainValue); domains[domainHash] = true; emit DomainRegistered(domainHash, domainValue); } function registerRequestTypeInternal(string memory requestType) internal { bytes32 requestTypehash = keccak256(bytes(requestType)); typeHashes[requestTypehash] = true; emit RequestTypeRegistered(requestTypehash, requestType); } function _verifySig( ForwardRequest calldata req, bytes32 domainSeparator, bytes32 requestTypeHash, bytes calldata suffixData, bytes calldata sig) internal view { require(domains[domainSeparator], "FWD: unregistered domain sep."); require(typeHashes[requestTypeHash], "FWD: unregistered typehash"); bytes32 digest = keccak256(abi.encodePacked( "\x19\x01", domainSeparator, keccak256(_getEncoded(req, requestTypeHash, suffixData)) )); require(digest.recover(sig) == req.from, "FWD: signature mismatch"); } function _getEncoded( ForwardRequest calldata req, bytes32 requestTypeHash, bytes calldata suffixData ) public pure returns ( bytes memory ) { // we use encodePacked since we append suffixData as-is, not as dynamic param. // still, we must make sure all first params are encoded as abi.encode() // would encode them - as 256-bit-wide params. return abi.encodePacked( requestTypeHash, uint256(uint160(req.from)), uint256(uint160(req.to)), req.value, req.gas, req.nonce, keccak256(req.data), req.validUntil, suffixData ); } } contract ProtocolForwarder is Forwarder { constructor() Forwarder() {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"domainValue","type":"bytes"}],"name":"DomainRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"typeHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"typeStr","type":"string"}],"name":"RequestTypeRegistered","type":"event"},{"inputs":[],"name":"EIP712_DOMAIN_TYPE","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GENERIC_PARAMS","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"validUntil","type":"uint256"}],"internalType":"struct IForwarder.ForwardRequest","name":"req","type":"tuple"},{"internalType":"bytes32","name":"requestTypeHash","type":"bytes32"},{"internalType":"bytes","name":"suffixData","type":"bytes"}],"name":"_getEncoded","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"domains","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"validUntil","type":"uint256"}],"internalType":"struct IForwarder.ForwardRequest","name":"req","type":"tuple"},{"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"internalType":"bytes32","name":"requestTypeHash","type":"bytes32"},{"internalType":"bytes","name":"suffixData","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"execute","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"ret","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"}],"name":"registerDomainSeparator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"typeName","type":"string"},{"internalType":"string","name":"typeSuffix","type":"string"}],"name":"registerRequestType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"typeHashes","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"validUntil","type":"uint256"}],"internalType":"struct IForwarder.ForwardRequest","name":"req","type":"tuple"},{"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"internalType":"bytes32","name":"requestTypeHash","type":"bytes32"},{"internalType":"bytes","name":"suffixData","type":"bytes"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"verify","outputs":[],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060006040518060800160405280605d8152602001620013b0605d9139604051602001620000409190620000ee565b60408051601f1981840301815291905290506200005d8162000064565b5062000167565b8051602080830191909120600081815291829052604091829020805460ff19166001179055905181907f64d6bce64323458c44643c51fe45113efc882082f7b7fd5f09f0d69d2eedb20290620000bc90859062000132565b60405180910390a25050565b60005b83811015620000e5578181015183820152602001620000cb565b50506000910152565b6e08cdee4eec2e4c8a4cae2eacae6e85608b1b8152600082516200011a81600f850160208701620000c8565b602960f81b600f939091019283015250601001919050565b602081526000825180602084015262000153816040850160208701620000c8565b601f01601f19169190910160400192915050565b61123980620001776000396000f3fe6080604052600436106100955760003560e01c8063c3f28abd11610059578063c3f28abd14610192578063c722f177146101a7578063d9210be5146101d7578063e024dc7f146101f7578063e2b62f2d1461021857600080fd5b8063066a310c146100a157806321fe98df146100cc5780632d0335ab1461010c5780639c7b459214610150578063ad9f99c71461017257600080fd5b3661009c57005b600080fd5b3480156100ad57600080fd5b506100b6610238565b6040516100c39190610d30565b60405180910390f35b3480156100d857600080fd5b506100fc6100e7366004610d4a565b60006020819052908152604090205460ff1681565b60405190151581526020016100c3565b34801561011857600080fd5b50610142610127366004610d63565b6001600160a01b031660009081526002602052604090205490565b6040519081526020016100c3565b34801561015c57600080fd5b5061017061016b366004610dce565b610254565b005b34801561017e57600080fd5b5061017061018d366004610e52565b61034b565b34801561019e57600080fd5b506100b661036c565b3480156101b357600080fd5b506100fc6101c2366004610d4a565b60016020526000908152604090205460ff1681565b3480156101e357600080fd5b506101706101f2366004610dce565b610388565b61020a610205366004610e52565b61048b565b6040516100c3929190610efa565b34801561022457600080fd5b506100b6610233366004610f1d565b6106a2565b6040518060800160405280605d8152602001611155605d913981565b600046905060006040518060800160405280605281526020016111b26052913980519060200120868660405161028b929190610f74565b604051809103902085856040516102a3929190610f74565b6040805191829003822060208301949094528101919091526060810191909152608081018390523060a082015260c00160408051601f198184030181528282528051602080830191909120600081815260019283905293909320805460ff1916909117905592509081907f4bc68689cbe89a4a6333a3ab0a70093874da3e5bfb71e93102027f3f073687d89061033a908590610d30565b60405180910390a250505050505050565b6103548761073c565b610363878787878787876107b9565b50505050505050565b6040518060800160405280605281526020016111b26052913981565b60005b838110156104365760008585838181106103a7576103a7610f84565b909101356001600160f81b031916915050600560fb1b81148015906103da5750602960f81b6001600160f81b0319821614155b6104235760405162461bcd60e51b81526020600482015260156024820152744657443a20696e76616c696420747970656e616d6560581b60448201526064015b60405180910390fd5b508061042e81610fb0565b91505061038b565b50600084846040518060800160405280605d8152602001611155605d9139858560405160200161046a959493929190610fc9565b604051602081830303815290604052905061048481610981565b5050505050565b6000606061049e898989898989896107b9565b6104a7896109e3565b60c089013515806104bb5750438960c00135115b6104fe5760405162461bcd60e51b81526020600482015260146024820152731195d10e881c995c5d595cdd08195e1c1a5c995960621b604482015260640161041a565b600060408a01351561050f5750619c405b600061051e60a08c018c611017565b61052b60208e018e610d63565b60405160200161053d9392919061105e565b60408051601f19818403018152919052905061055d8260608d0135611084565b60405a61056b90603f611097565b61057591906110ae565b10156105bb5760405162461bcd60e51b81526020600482015260156024820152744657443a20696e73756666696369656e742067617360581b604482015260640161041a565b6105cb60408c0160208d01610d63565b6001600160a01b03168b606001358c60400135836040516105ec91906110d0565b600060405180830381858888f193505050503d806000811461062a576040519150601f19603f3d011682016040523d82523d6000602084013e61062f565b606091505b50909450925060408b0135158015906106485750600047115b156106945761065a60208c018c610d63565b6001600160a01b03166108fc479081150290604051600060405180830381858888f19350505050158015610692573d6000803e3d6000fd5b505b505097509795505050505050565b6060836106b26020870187610d63565b6001600160a01b03166106cb6040880160208901610d63565b6001600160a01b03166040880135606089013560808a01356106f060a08c018c611017565b6040516106fe929190610f74565b6040519081900381206107239796959493929160c08e0135908c908c906020016110ec565b6040516020818303038152906040529050949350505050565b6080810135600260006107526020850185610d63565b6001600160a01b03166001600160a01b0316815260200190815260200160002054146107b65760405162461bcd60e51b815260206004820152601360248201527208cae887440dcdedcc6ca40dad2e6dac2e8c6d606b1b604482015260640161041a565b50565b60008681526001602052604090205460ff166108175760405162461bcd60e51b815260206004820152601d60248201527f4657443a20756e7265676973746572656420646f6d61696e207365702e000000604482015260640161041a565b60008581526020819052604090205460ff166108755760405162461bcd60e51b815260206004820152601a60248201527f4657443a20756e72656769737465726564207479706568617368000000000000604482015260640161041a565b600086610884898888886106a2565b80516020918201206040516108b093920161190160f01b81526002810192909252602282015260420190565b60408051601f19818403018152919052805160209182012091506108d690890189610d63565b6001600160a01b031661092184848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050610a679050565b6001600160a01b0316146109775760405162461bcd60e51b815260206004820152601760248201527f4657443a207369676e6174757265206d69736d61746368000000000000000000604482015260640161041a565b5050505050505050565b8051602080830191909120600081815291829052604091829020805460ff19166001179055905181907f64d6bce64323458c44643c51fe45113efc882082f7b7fd5f09f0d69d2eedb202906109d7908590610d30565b60405180910390a25050565b6080810135600260006109f96020850185610d63565b6001600160a01b0316815260208101919091526040016000908120805491610a2083610fb0565b91905055146107b65760405162461bcd60e51b815260206004820152601360248201527208cae887440dcdedcc6ca40dad2e6dac2e8c6d606b1b604482015260640161041a565b6000806000610a768585610a8d565b91509150610a8381610ad2565b5090505b92915050565b6000808251604103610ac35760208301516040840151606085015160001a610ab787828585610c1c565b94509450505050610acb565b506000905060025b9250929050565b6000816004811115610ae657610ae661113e565b03610aee5750565b6001816004811115610b0257610b0261113e565b03610b4f5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161041a565b6002816004811115610b6357610b6361113e565b03610bb05760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161041a565b6003816004811115610bc457610bc461113e565b036107b65760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161041a565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115610c535750600090506003610cd7565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610ca7573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610cd057600060019250925050610cd7565b9150600090505b94509492505050565b60005b83811015610cfb578181015183820152602001610ce3565b50506000910152565b60008151808452610d1c816020860160208601610ce0565b601f01601f19169290920160200192915050565b602081526000610d436020830184610d04565b9392505050565b600060208284031215610d5c57600080fd5b5035919050565b600060208284031215610d7557600080fd5b81356001600160a01b0381168114610d4357600080fd5b60008083601f840112610d9e57600080fd5b50813567ffffffffffffffff811115610db657600080fd5b602083019150836020828501011115610acb57600080fd5b60008060008060408587031215610de457600080fd5b843567ffffffffffffffff80821115610dfc57600080fd5b610e0888838901610d8c565b90965094506020870135915080821115610e2157600080fd5b50610e2e87828801610d8c565b95989497509550505050565b600060e08284031215610e4c57600080fd5b50919050565b600080600080600080600060a0888a031215610e6d57600080fd5b873567ffffffffffffffff80821115610e8557600080fd5b610e918b838c01610e3a565b985060208a0135975060408a0135965060608a0135915080821115610eb557600080fd5b610ec18b838c01610d8c565b909650945060808a0135915080821115610eda57600080fd5b50610ee78a828b01610d8c565b989b979a50959850939692959293505050565b8215158152604060208201526000610f156040830184610d04565b949350505050565b60008060008060608587031215610f3357600080fd5b843567ffffffffffffffff80821115610f4b57600080fd5b610f5788838901610e3a565b9550602087013594506040870135915080821115610e2157600080fd5b8183823760009101908152919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201610fc257610fc2610f9a565b5060010190565b848682376000858201600560fb1b81528551610fec816001840160208a01610ce0565b600b60fa1b600192909101918201528385600283013760009301600201928352509095945050505050565b6000808335601e1984360301811261102e57600080fd5b83018035915067ffffffffffffffff82111561104957600080fd5b602001915036819003821315610acb57600080fd5b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b80820180821115610a8757610a87610f9a565b8082028115828204841417610a8757610a87610f9a565b6000826110cb57634e487b7160e01b600052601260045260246000fd5b500490565b600082516110e2818460208701610ce0565b9190910192915050565b8a81528960208201528860408201528760608201528660808201528560a08201528460c08201528360e082015260006101008385828501376000929093019092019081529a9950505050505050505050565b634e487b7160e01b600052602160045260246000fdfe616464726573732066726f6d2c6164647265737320746f2c75696e743235362076616c75652c75696e74323536206761732c75696e74323536206e6f6e63652c627974657320646174612c75696e743235362076616c6964556e74696c454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429a264697066735822122010042a0e84b9be2a3810671a36cb2a11ab8bcd35171f702553221e0d46af0c7e64736f6c63430008130033616464726573732066726f6d2c6164647265737320746f2c75696e743235362076616c75652c75696e74323536206761732c75696e74323536206e6f6e63652c627974657320646174612c75696e743235362076616c6964556e74696c
Deployed Bytecode
0x6080604052600436106100955760003560e01c8063c3f28abd11610059578063c3f28abd14610192578063c722f177146101a7578063d9210be5146101d7578063e024dc7f146101f7578063e2b62f2d1461021857600080fd5b8063066a310c146100a157806321fe98df146100cc5780632d0335ab1461010c5780639c7b459214610150578063ad9f99c71461017257600080fd5b3661009c57005b600080fd5b3480156100ad57600080fd5b506100b6610238565b6040516100c39190610d30565b60405180910390f35b3480156100d857600080fd5b506100fc6100e7366004610d4a565b60006020819052908152604090205460ff1681565b60405190151581526020016100c3565b34801561011857600080fd5b50610142610127366004610d63565b6001600160a01b031660009081526002602052604090205490565b6040519081526020016100c3565b34801561015c57600080fd5b5061017061016b366004610dce565b610254565b005b34801561017e57600080fd5b5061017061018d366004610e52565b61034b565b34801561019e57600080fd5b506100b661036c565b3480156101b357600080fd5b506100fc6101c2366004610d4a565b60016020526000908152604090205460ff1681565b3480156101e357600080fd5b506101706101f2366004610dce565b610388565b61020a610205366004610e52565b61048b565b6040516100c3929190610efa565b34801561022457600080fd5b506100b6610233366004610f1d565b6106a2565b6040518060800160405280605d8152602001611155605d913981565b600046905060006040518060800160405280605281526020016111b26052913980519060200120868660405161028b929190610f74565b604051809103902085856040516102a3929190610f74565b6040805191829003822060208301949094528101919091526060810191909152608081018390523060a082015260c00160408051601f198184030181528282528051602080830191909120600081815260019283905293909320805460ff1916909117905592509081907f4bc68689cbe89a4a6333a3ab0a70093874da3e5bfb71e93102027f3f073687d89061033a908590610d30565b60405180910390a250505050505050565b6103548761073c565b610363878787878787876107b9565b50505050505050565b6040518060800160405280605281526020016111b26052913981565b60005b838110156104365760008585838181106103a7576103a7610f84565b909101356001600160f81b031916915050600560fb1b81148015906103da5750602960f81b6001600160f81b0319821614155b6104235760405162461bcd60e51b81526020600482015260156024820152744657443a20696e76616c696420747970656e616d6560581b60448201526064015b60405180910390fd5b508061042e81610fb0565b91505061038b565b50600084846040518060800160405280605d8152602001611155605d9139858560405160200161046a959493929190610fc9565b604051602081830303815290604052905061048481610981565b5050505050565b6000606061049e898989898989896107b9565b6104a7896109e3565b60c089013515806104bb5750438960c00135115b6104fe5760405162461bcd60e51b81526020600482015260146024820152731195d10e881c995c5d595cdd08195e1c1a5c995960621b604482015260640161041a565b600060408a01351561050f5750619c405b600061051e60a08c018c611017565b61052b60208e018e610d63565b60405160200161053d9392919061105e565b60408051601f19818403018152919052905061055d8260608d0135611084565b60405a61056b90603f611097565b61057591906110ae565b10156105bb5760405162461bcd60e51b81526020600482015260156024820152744657443a20696e73756666696369656e742067617360581b604482015260640161041a565b6105cb60408c0160208d01610d63565b6001600160a01b03168b606001358c60400135836040516105ec91906110d0565b600060405180830381858888f193505050503d806000811461062a576040519150601f19603f3d011682016040523d82523d6000602084013e61062f565b606091505b50909450925060408b0135158015906106485750600047115b156106945761065a60208c018c610d63565b6001600160a01b03166108fc479081150290604051600060405180830381858888f19350505050158015610692573d6000803e3d6000fd5b505b505097509795505050505050565b6060836106b26020870187610d63565b6001600160a01b03166106cb6040880160208901610d63565b6001600160a01b03166040880135606089013560808a01356106f060a08c018c611017565b6040516106fe929190610f74565b6040519081900381206107239796959493929160c08e0135908c908c906020016110ec565b6040516020818303038152906040529050949350505050565b6080810135600260006107526020850185610d63565b6001600160a01b03166001600160a01b0316815260200190815260200160002054146107b65760405162461bcd60e51b815260206004820152601360248201527208cae887440dcdedcc6ca40dad2e6dac2e8c6d606b1b604482015260640161041a565b50565b60008681526001602052604090205460ff166108175760405162461bcd60e51b815260206004820152601d60248201527f4657443a20756e7265676973746572656420646f6d61696e207365702e000000604482015260640161041a565b60008581526020819052604090205460ff166108755760405162461bcd60e51b815260206004820152601a60248201527f4657443a20756e72656769737465726564207479706568617368000000000000604482015260640161041a565b600086610884898888886106a2565b80516020918201206040516108b093920161190160f01b81526002810192909252602282015260420190565b60408051601f19818403018152919052805160209182012091506108d690890189610d63565b6001600160a01b031661092184848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508693925050610a679050565b6001600160a01b0316146109775760405162461bcd60e51b815260206004820152601760248201527f4657443a207369676e6174757265206d69736d61746368000000000000000000604482015260640161041a565b5050505050505050565b8051602080830191909120600081815291829052604091829020805460ff19166001179055905181907f64d6bce64323458c44643c51fe45113efc882082f7b7fd5f09f0d69d2eedb202906109d7908590610d30565b60405180910390a25050565b6080810135600260006109f96020850185610d63565b6001600160a01b0316815260208101919091526040016000908120805491610a2083610fb0565b91905055146107b65760405162461bcd60e51b815260206004820152601360248201527208cae887440dcdedcc6ca40dad2e6dac2e8c6d606b1b604482015260640161041a565b6000806000610a768585610a8d565b91509150610a8381610ad2565b5090505b92915050565b6000808251604103610ac35760208301516040840151606085015160001a610ab787828585610c1c565b94509450505050610acb565b506000905060025b9250929050565b6000816004811115610ae657610ae661113e565b03610aee5750565b6001816004811115610b0257610b0261113e565b03610b4f5760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015260640161041a565b6002816004811115610b6357610b6361113e565b03610bb05760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015260640161041a565b6003816004811115610bc457610bc461113e565b036107b65760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b606482015260840161041a565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115610c535750600090506003610cd7565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015610ca7573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610cd057600060019250925050610cd7565b9150600090505b94509492505050565b60005b83811015610cfb578181015183820152602001610ce3565b50506000910152565b60008151808452610d1c816020860160208601610ce0565b601f01601f19169290920160200192915050565b602081526000610d436020830184610d04565b9392505050565b600060208284031215610d5c57600080fd5b5035919050565b600060208284031215610d7557600080fd5b81356001600160a01b0381168114610d4357600080fd5b60008083601f840112610d9e57600080fd5b50813567ffffffffffffffff811115610db657600080fd5b602083019150836020828501011115610acb57600080fd5b60008060008060408587031215610de457600080fd5b843567ffffffffffffffff80821115610dfc57600080fd5b610e0888838901610d8c565b90965094506020870135915080821115610e2157600080fd5b50610e2e87828801610d8c565b95989497509550505050565b600060e08284031215610e4c57600080fd5b50919050565b600080600080600080600060a0888a031215610e6d57600080fd5b873567ffffffffffffffff80821115610e8557600080fd5b610e918b838c01610e3a565b985060208a0135975060408a0135965060608a0135915080821115610eb557600080fd5b610ec18b838c01610d8c565b909650945060808a0135915080821115610eda57600080fd5b50610ee78a828b01610d8c565b989b979a50959850939692959293505050565b8215158152604060208201526000610f156040830184610d04565b949350505050565b60008060008060608587031215610f3357600080fd5b843567ffffffffffffffff80821115610f4b57600080fd5b610f5788838901610e3a565b9550602087013594506040870135915080821115610e2157600080fd5b8183823760009101908152919050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201610fc257610fc2610f9a565b5060010190565b848682376000858201600560fb1b81528551610fec816001840160208a01610ce0565b600b60fa1b600192909101918201528385600283013760009301600201928352509095945050505050565b6000808335601e1984360301811261102e57600080fd5b83018035915067ffffffffffffffff82111561104957600080fd5b602001915036819003821315610acb57600080fd5b8284823760609190911b6bffffffffffffffffffffffff19169101908152601401919050565b80820180821115610a8757610a87610f9a565b8082028115828204841417610a8757610a87610f9a565b6000826110cb57634e487b7160e01b600052601260045260246000fd5b500490565b600082516110e2818460208701610ce0565b9190910192915050565b8a81528960208201528860408201528760608201528660808201528560a08201528460c08201528360e082015260006101008385828501376000929093019092019081529a9950505050505050505050565b634e487b7160e01b600052602160045260246000fdfe616464726573732066726f6d2c6164647265737320746f2c75696e743235362076616c75652c75696e74323536206761732c75696e74323536206e6f6e63652c627974657320646174612c75696e743235362076616c6964556e74696c454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c75696e7432353620636861696e49642c6164647265737320766572696679696e67436f6e747261637429a264697066735822122010042a0e84b9be2a3810671a36cb2a11ab8bcd35171f702553221e0d46af0c7e64736f6c63430008130033
Deployed Bytecode Sourcemap
29216:5627:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;29288:135;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;29569:42;;;;;;;;;;-1:-1:-1;29569:42:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;1120:14:1;;1113:22;1095:41;;1083:2;1068:18;29569:42:0;955:187:1;29862:119:0;;;;;;;;;;-1:-1:-1;29862:119:0;;;;;:::i;:::-;-1:-1:-1;;;;;29961:12:0;29934:7;29961:12;;;:6;:12;;;;;;;29862:119;;;;1584:25:1;;;1572:2;1557:18;29862:119:0;1438:177:1;32538:616:0;;;;;;;;;;-1:-1:-1;32538:616:0;;;;;:::i;:::-;;:::i;:::-;;30175:331;;;;;;;;;;-1:-1:-1;30175:331:0;;;;;:::i;:::-;;:::i;29432:128::-;;;;;;;;;;;;;:::i;29618:39::-;;;;;;;;;;-1:-1:-1;29618:39:0;;;;;:::i;:::-;;;;;;;;;;;;;;;;32070:460;;;;;;;;;;-1:-1:-1;32070:460:0;;;;;:::i;:::-;;:::i;30514:1236::-;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;34091:749::-;;;;;;;;;;-1:-1:-1;34091:749:0;;;;;:::i;:::-;;:::i;29288:135::-;;;;;;;;;;;;;;;;;;;:::o;32538:616::-;32647:15;32755:9;32744:20;;32778:24;32846:18;;;;;;;;;;;;;;;;;32830:36;;;;;;32897:4;;32881:22;;;;;;;:::i;:::-;;;;;;;;32934:7;;32918:25;;;;;;;:::i;:::-;;;;;;;;;;32805:189;;;5791:25:1;;;;5832:18;;5825:34;;;;5875:18;;;5868:34;;;;5918:18;;;5911:34;;;32988:4:0;5961:19:1;;;5954:61;5763:19;;32805:189:0;;;-1:-1:-1;;32805:189:0;;;;;;;;;33028:22;;32805:189;33028:22;;;;;;;33007:18;33063:19;;;33085:4;33063:19;;;;;;;;:26;;-1:-1:-1;;33063:26:0;;;;;;32805:189;-1:-1:-1;33028:22:0;;;33105:41;;;;32805:189;;33105:41;:::i;:::-;;;;;;;;32636:518;;;32538:616;;;;:::o;30175:331::-;30404:17;30417:3;30404:12;:17::i;:::-;30432:66;30443:3;30448:15;30465;30482:10;;30494:3;;30432:10;:66::i;:::-;30175:331;;;;;;;:::o;29432:128::-;;;;;;;;;;;;;;;;;;;:::o;32070:460::-;32189:6;32184:175;32201:26;;;32184:175;;;32249:8;32266;;32276:1;32260:18;;;;;;;:::i;:::-;;;;;-1:-1:-1;;;;;;32260:18:0;;-1:-1:-1;;;;;32301:8:0;;;;;:20;;-1:-1:-1;;;;;;;;;;32313:8:0;;;;32301:20;32293:54;;;;-1:-1:-1;;;32293:54:0;;6360:2:1;32293:54:0;;;6342:21:1;6399:2;6379:18;;;6372:30;-1:-1:-1;;;6418:18:1;;;6411:51;6479:18;;32293:54:0;;;;;;;;;-1:-1:-1;32229:3:0;;;;:::i;:::-;;;;32184:175;;;;32371:25;32423:8;;32438:14;;;;;;;;;;;;;;;;;32459:10;;32406:64;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;32371:100;;32482:40;32510:11;32482:27;:40::i;:::-;32171:359;32070:460;;;;:::o;30514:1236::-;30759:12;30773:16;30802:66;30813:3;30818:15;30835;30852:10;;30864:3;;30802:10;:66::i;:::-;30879:26;30901:3;30879:21;:26::i;:::-;30926:14;;;;:19;;:52;;;30966:12;30949:3;:14;;;:29;30926:52;30918:85;;;;-1:-1:-1;;;30918:85:0;;7867:2:1;30918:85:0;;;7849:21:1;7906:2;7886:18;;;7879:30;-1:-1:-1;;;7925:18:1;;;7918:50;7985:18;;30918:85:0;7665:344:1;30918:85:0;31016:19;31055:9;;;;:14;31050:131;;-1:-1:-1;31104:5:0;31050:131;31191:21;31232:8;;;;:3;:8;:::i;:::-;31242;;;;:3;:8;:::i;:::-;31215:36;;;;;;;;;;:::i;:::-;;;;-1:-1:-1;;31215:36:0;;;;;;;;;;-1:-1:-1;31289:24:0;31299:14;31289:7;;;;:24;:::i;:::-;31283:2;31270:9;:12;;31280:2;31270:12;:::i;:::-;:15;;;;:::i;:::-;:43;;31262:77;;;;-1:-1:-1;;;31262:77:0;;9632:2:1;31262:77:0;;;9614:21:1;9671:2;9651:18;;;9644:30;-1:-1:-1;;;9690:18:1;;;9683:51;9751:18;;31262:77:0;9430:345:1;31262:77:0;31426:6;;;;;;;;:::i;:::-;-1:-1:-1;;;;;31426:11:0;31444:3;:7;;;31461:3;:9;;;31472:8;31426:55;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;31410:71:0;;-1:-1:-1;31410:71:0;-1:-1:-1;31497:9:0;;;;:14;;;;:41;;;31537:1;31515:21;:23;31497:41;31492:218;;;31657:8;;;;:3;:8;:::i;:::-;-1:-1:-1;;;;;31649:26:0;:49;31676:21;31649:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;31492:218;31722:20;;30514:1236;;;;;;;;;;:::o;34091:749::-;34273:12;34568:15;34614:8;;;;:3;:8;:::i;:::-;-1:-1:-1;;;;;34598:26:0;34655:6;;;;;;;;:::i;:::-;-1:-1:-1;;;;;34639:24:0;34678:9;;;;34702:7;;;;34724:9;;;;34758:8;;;;34678:3;34758:8;:::i;:::-;34748:19;;;;;;;:::i;:::-;;;;;;;;;34537:295;;;;;;;;34782:14;;;;;34811:10;;;;34537:295;;;:::i;:::-;;;;;;;;;;;;;34530:302;;34091:749;;;;;;:::o;31758:145::-;31862:9;;;;31842:6;:16;31849:8;;;;31862:3;31849:8;:::i;:::-;-1:-1:-1;;;;;31842:16:0;-1:-1:-1;;;;;31842:16:0;;;;;;;;;;;;;:29;31834:61;;;;-1:-1:-1;;;31834:61:0;;11105:2:1;31834:61:0;;;11087:21:1;11144:2;11124:18;;;11117:30;-1:-1:-1;;;11163:18:1;;;11156:49;11222:18;;31834:61:0;10903:343:1;31834:61:0;31758:145;:::o;33431:652::-;33671:24;;;;:7;:24;;;;;;;;33663:66;;;;-1:-1:-1;;;33663:66:0;;11453:2:1;33663:66:0;;;11435:21:1;11492:2;11472:18;;;11465:30;11531:31;11511:18;;;11504:59;11580:18;;33663:66:0;11251:353:1;33663:66:0;33748:10;:27;;;;;;;;;;;;;33740:66;;;;-1:-1:-1;;;33740:66:0;;11811:2:1;33740:66:0;;;11793:21:1;11850:2;11830:18;;;11823:30;11889:28;11869:18;;;11862:56;11935:18;;33740:66:0;11609:350:1;33740:66:0;33817:14;33891:15;33935:45;33947:3;33952:15;33969:10;;33935:11;:45::i;:::-;33925:56;;;;;;;33844:152;;;;;;-1:-1:-1;;;12222:27:1;;12274:1;12265:11;;12258:27;;;;12310:2;12301:12;;12294:28;12347:2;12338:12;;11964:392;33844:152:0;;;;-1:-1:-1;;33844:152:0;;;;;;;;;33834:163;;33844:152;33834:163;;;;;-1:-1:-1;34039:8:0;;;;:3;:8;:::i;:::-;-1:-1:-1;;;;;34016:31:0;:19;34031:3;;34016:19;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;34016:6:0;;:19;-1:-1:-1;;34016:14:0;:19;-1:-1:-1;34016:19:0:i;:::-;-1:-1:-1;;;;;34016:31:0;;34008:67;;;;-1:-1:-1;;;34008:67:0;;12563:2:1;34008:67:0;;;12545:21:1;12602:2;12582:18;;;12575:30;12641:25;12621:18;;;12614:53;12684:18;;34008:67:0;12361:347:1;34008:67:0;33652:431;33431:652;;;;;;;:::o;33162:261::-;33274:29;;;;;;;;;;33248:23;33314:27;;;;;;;;;;;;:34;;-1:-1:-1;;33314:34:0;33344:4;33314:34;;;33364:51;;33274:29;;33364:51;;;;33290:11;;33364:51;:::i;:::-;;;;;;;;33235:188;33162:261;:::o;31911:151::-;32021:9;;;;31999:6;:16;32006:8;;;;32021:3;32006:8;:::i;:::-;-1:-1:-1;;;;;31999:16:0;;;;;;;;;;;;-1:-1:-1;31999:16:0;;;:18;;;;;;:::i;:::-;;;;;:31;31991:63;;;;-1:-1:-1;;;31991:63:0;;11105:2:1;31991:63:0;;;11087:21:1;11144:2;11124:18;;;11117:30;-1:-1:-1;;;11163:18:1;;;11156:49;11222:18;;31991:63:0;10903:343:1;20738:231:0;20816:7;20837:17;20856:18;20878:27;20889:4;20895:9;20878:10;:27::i;:::-;20836:69;;;;20916:18;20928:5;20916:11;:18::i;:::-;-1:-1:-1;20952:9:0;-1:-1:-1;20738:231:0;;;;;:::o;19189:747::-;19270:7;19279:12;19308:9;:16;19328:2;19308:22;19304:625;;19652:4;19637:20;;19631:27;19702:4;19687:20;;19681:27;19760:4;19745:20;;19739:27;19347:9;19731:36;19803:25;19814:4;19731:36;19631:27;19681;19803:10;:25::i;:::-;19796:32;;;;;;;;;19304:625;-1:-1:-1;19877:1:0;;-1:-1:-1;19881:35:0;19304:625;19189:747;;;;;:::o;17582:521::-;17660:20;17651:5;:29;;;;;;;;:::i;:::-;;17647:449;;17582:521;:::o;17647:449::-;17758:29;17749:5;:38;;;;;;;;:::i;:::-;;17745:351;;17804:34;;-1:-1:-1;;;17804:34:0;;13047:2:1;17804:34:0;;;13029:21:1;13086:2;13066:18;;;13059:30;13125:26;13105:18;;;13098:54;13169:18;;17804:34:0;12845:348:1;17745:351:0;17869:35;17860:5;:44;;;;;;;;:::i;:::-;;17856:240;;17921:41;;-1:-1:-1;;;17921:41:0;;13400:2:1;17921:41:0;;;13382:21:1;13439:2;13419:18;;;13412:30;13478:33;13458:18;;;13451:61;13529:18;;17921:41:0;13198:355:1;17856:240:0;17993:30;17984:5;:39;;;;;;;;:::i;:::-;;17980:116;;18040:44;;-1:-1:-1;;;18040:44:0;;13760:2:1;18040:44:0;;;13742:21:1;13799:2;13779:18;;;13772:30;13838:34;13818:18;;;13811:62;-1:-1:-1;;;13889:18:1;;;13882:32;13931:19;;18040:44:0;13558:398:1;22122:1477:0;22210:7;;23144:66;23131:79;;23127:163;;;-1:-1:-1;23243:1:0;;-1:-1:-1;23247:30:0;23227:51;;23127:163;23404:24;;;23387:14;23404:24;;;;;;;;;14188:25:1;;;14261:4;14249:17;;14229:18;;;14222:45;;;;14283:18;;;14276:34;;;14326:18;;;14319:34;;;23404:24:0;;14160:19:1;;23404:24:0;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;23404:24:0;;-1:-1:-1;;23404:24:0;;;-1:-1:-1;;;;;;;23443:20:0;;23439:103;;23496:1;23500:29;23480:50;;;;;;;23439:103;23562:6;-1:-1:-1;23570:20:0;;-1:-1:-1;22122:1477:0;;;;;;;;:::o;14:250:1:-;99:1;109:113;123:6;120:1;117:13;109:113;;;199:11;;;193:18;180:11;;;173:39;145:2;138:10;109:113;;;-1:-1:-1;;256:1:1;238:16;;231:27;14:250::o;269:271::-;311:3;349:5;343:12;376:6;371:3;364:19;392:76;461:6;454:4;449:3;445:14;438:4;431:5;427:16;392:76;:::i;:::-;522:2;501:15;-1:-1:-1;;497:29:1;488:39;;;;529:4;484:50;;269:271;-1:-1:-1;;269:271:1:o;545:220::-;694:2;683:9;676:21;657:4;714:45;755:2;744:9;740:18;732:6;714:45;:::i;:::-;706:53;545:220;-1:-1:-1;;;545:220:1:o;770:180::-;829:6;882:2;870:9;861:7;857:23;853:32;850:52;;;898:1;895;888:12;850:52;-1:-1:-1;921:23:1;;770:180;-1:-1:-1;770:180:1:o;1147:286::-;1206:6;1259:2;1247:9;1238:7;1234:23;1230:32;1227:52;;;1275:1;1272;1265:12;1227:52;1301:23;;-1:-1:-1;;;;;1353:31:1;;1343:42;;1333:70;;1399:1;1396;1389:12;1620:348;1672:8;1682:6;1736:3;1729:4;1721:6;1717:17;1713:27;1703:55;;1754:1;1751;1744:12;1703:55;-1:-1:-1;1777:20:1;;1820:18;1809:30;;1806:50;;;1852:1;1849;1842:12;1806:50;1889:4;1881:6;1877:17;1865:29;;1941:3;1934:4;1925:6;1917;1913:19;1909:30;1906:39;1903:59;;;1958:1;1955;1948:12;1973:721;2065:6;2073;2081;2089;2142:2;2130:9;2121:7;2117:23;2113:32;2110:52;;;2158:1;2155;2148:12;2110:52;2198:9;2185:23;2227:18;2268:2;2260:6;2257:14;2254:34;;;2284:1;2281;2274:12;2254:34;2323:59;2374:7;2365:6;2354:9;2350:22;2323:59;:::i;:::-;2401:8;;-1:-1:-1;2297:85:1;-1:-1:-1;2489:2:1;2474:18;;2461:32;;-1:-1:-1;2505:16:1;;;2502:36;;;2534:1;2531;2524:12;2502:36;;2573:61;2626:7;2615:8;2604:9;2600:24;2573:61;:::i;:::-;1973:721;;;;-1:-1:-1;2653:8:1;-1:-1:-1;;;;1973:721:1:o;2699:163::-;2766:5;2811:3;2802:6;2797:3;2793:16;2789:26;2786:46;;;2828:1;2825;2818:12;2786:46;-1:-1:-1;2850:6:1;2699:163;-1:-1:-1;2699:163:1:o;2867:1105::-;3018:6;3026;3034;3042;3050;3058;3066;3119:3;3107:9;3098:7;3094:23;3090:33;3087:53;;;3136:1;3133;3126:12;3087:53;3176:9;3163:23;3205:18;3246:2;3238:6;3235:14;3232:34;;;3262:1;3259;3252:12;3232:34;3285:74;3351:7;3342:6;3331:9;3327:22;3285:74;:::i;:::-;3275:84;;3406:2;3395:9;3391:18;3378:32;3368:42;;3457:2;3446:9;3442:18;3429:32;3419:42;;3514:2;3503:9;3499:18;3486:32;3470:48;;3543:2;3533:8;3530:16;3527:36;;;3559:1;3556;3549:12;3527:36;3598:61;3651:7;3640:8;3629:9;3625:24;3598:61;:::i;:::-;3678:8;;-1:-1:-1;3572:87:1;-1:-1:-1;3766:3:1;3751:19;;3738:33;;-1:-1:-1;3783:16:1;;;3780:36;;;3812:1;3809;3802:12;3780:36;;3851:61;3904:7;3893:8;3882:9;3878:24;3851:61;:::i;:::-;2867:1105;;;;-1:-1:-1;2867:1105:1;;-1:-1:-1;2867:1105:1;;;;3825:87;;-1:-1:-1;;;2867:1105:1:o;3977:299::-;4160:6;4153:14;4146:22;4135:9;4128:41;4205:2;4200;4189:9;4185:18;4178:30;4109:4;4225:45;4266:2;4255:9;4251:18;4243:6;4225:45;:::i;:::-;4217:53;3977:299;-1:-1:-1;;;;3977:299:1:o;4281:747::-;4403:6;4411;4419;4427;4480:2;4468:9;4459:7;4455:23;4451:32;4448:52;;;4496:1;4493;4486:12;4448:52;4536:9;4523:23;4565:18;4606:2;4598:6;4595:14;4592:34;;;4622:1;4619;4612:12;4592:34;4645:74;4711:7;4702:6;4691:9;4687:22;4645:74;:::i;:::-;4635:84;;4766:2;4755:9;4751:18;4738:32;4728:42;;4823:2;4812:9;4808:18;4795:32;4779:48;;4852:2;4842:8;4839:16;4836:36;;;4868:1;4865;4858:12;5256:271;5439:6;5431;5426:3;5413:33;5395:3;5465:16;;5490:13;;;5465:16;5256:271;-1:-1:-1;5256:271:1:o;6026:127::-;6087:10;6082:3;6078:20;6075:1;6068:31;6118:4;6115:1;6108:15;6142:4;6139:1;6132:15;6508:127;6569:10;6564:3;6560:20;6557:1;6550:31;6600:4;6597:1;6590:15;6624:4;6621:1;6614:15;6640:135;6679:3;6700:17;;;6697:43;;6720:18;;:::i;:::-;-1:-1:-1;6767:1:1;6756:13;;6640:135::o;6780:880::-;7273:6;7265;7260:3;7247:33;7229:3;7308:6;7303:3;7299:16;-1:-1:-1;;;7331:2:1;7324:15;7368:6;7362:13;7384:73;7450:6;7446:1;7442:2;7438:10;7431:4;7423:6;7419:17;7384:73;:::i;:::-;-1:-1:-1;;;7515:1:1;7476:15;;;;7507:10;;;7500:23;7565:6;7557;7553:1;7545:10;;7532:40;7634:1;7595:15;;7612:1;7591:23;7623:13;;;-1:-1:-1;7591:23:1;;6780:880;-1:-1:-1;;;;;6780:880:1:o;8014:521::-;8091:4;8097:6;8157:11;8144:25;8251:2;8247:7;8236:8;8220:14;8216:29;8212:43;8192:18;8188:68;8178:96;;8270:1;8267;8260:12;8178:96;8297:33;;8349:20;;;-1:-1:-1;8392:18:1;8381:30;;8378:50;;;8424:1;8421;8414:12;8378:50;8457:4;8445:17;;-1:-1:-1;8488:14:1;8484:27;;;8474:38;;8471:58;;;8525:1;8522;8515:12;8540:360;8751:6;8743;8738:3;8725:33;8821:2;8817:15;;;;-1:-1:-1;;8813:53:1;8777:16;;8802:65;;;8891:2;8883:11;;8540:360;-1:-1:-1;8540:360:1:o;8905:125::-;8970:9;;;8991:10;;;8988:36;;;9004:18;;:::i;9035:168::-;9108:9;;;9139;;9156:15;;;9150:22;;9136:37;9126:71;;9177:18;;:::i;9208:217::-;9248:1;9274;9264:132;;9318:10;9313:3;9309:20;9306:1;9299:31;9353:4;9350:1;9343:15;9381:4;9378:1;9371:15;9264:132;-1:-1:-1;9410:9:1;;9208:217::o;9780:287::-;9909:3;9947:6;9941:13;9963:66;10022:6;10017:3;10010:4;10002:6;9998:17;9963:66;:::i;:::-;10045:16;;;;;9780:287;-1:-1:-1;;9780:287:1:o;10072:826::-;10465:6;10460:3;10453:19;10502:6;10497:2;10492:3;10488:12;10481:28;10539:6;10534:2;10529:3;10525:12;10518:28;10576:6;10571:2;10566:3;10562:12;10555:28;10614:6;10608:3;10603;10599:13;10592:29;10652:6;10646:3;10641;10637:13;10630:29;10690:6;10684:3;10679;10675:13;10668:29;10728:6;10722:3;10717;10713:13;10706:29;10435:3;10754;10801:6;10793;10788:2;10783:3;10779:12;10766:42;10872:1;10831:16;;;;10827:25;;;10861:13;;;10827:25;10072:826;-1:-1:-1;;;;;;;;;;10072:826:1:o;12713:127::-;12774:10;12769:3;12765:20;12762:1;12755:31;12805:4;12802:1;12795:15;12829:4;12826:1;12819:15
Swarm Source
ipfs://10042a0e84b9be2a3810671a36cb2a11ab8bcd35171f702553221e0d46af0c7e
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.