Overview
xDAI Balance
xDAI Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
39636732 | 3 days ago | Contract Creation | 0 xDAI |
Loading...
Loading
Contract Name:
AmbireAccount7702
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 1000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.8.19; import './AmbireAccount.sol'; /** * @notice A contract that extends AmbireAccount to make it 7702 adaptable * @dev We hardcode the entry point address so we don't have to use * any storage slots after authorization. If it changes, the users * will have to authrorize another contract with the new entry point addr * to continue */ contract AmbireAccount7702 is AmbireAccount { address private constant ENTRY_POINT = address(0x0000000071727De22E5E9d8BAf0edAc6f37da032); function privileges(address key) public override view returns (bytes32) { if (key == address(this)) return bytes32(uint256(2)); // if the entry point is the sender, we return the marker priv if (key == ENTRY_POINT) return ENTRY_POINT_MARKER; return getAmbireStorage().privileges[key]; } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.8.19; import './libs/SignatureValidator.sol'; import './ExternalSigValidator.sol'; import './libs/erc4337/PackedUserOperation.sol'; import './libs/erc4337/UserOpHelper.sol'; import './deployless/IAmbireAccount.sol'; import './libs/Eip712HashBuilder.sol'; /** * @notice A validator that performs DKIM signature recovery * @dev All external/public functions (that are not view/pure) use `payable` because AmbireAccount * is a wallet contract, and any ETH sent to it is not lost, but on the other hand not having `payable` * makes the Solidity compiler add an extra check for `msg.value`, which in this case is wasted gas */ contract AmbireAccount is IAmbireAccount { // @dev We do not have a constructor. This contract cannot be initialized with any valid `privileges` by itself! // The intended use case is to deploy one base implementation contract, and create a minimal proxy for each user wallet, by // using our own code generation to insert SSTOREs to initialize `privileges` (it was previously called IdentityProxyDeploy.js, now src/libs/proxyDeploy/deploy.ts) // @dev This is how we understand if msg.sender is the entry point bytes32 constant ENTRY_POINT_MARKER = 0x0000000000000000000000000000000000000000000000000000000000007171; // Externally validated signatures uint8 private constant SIGMODE_EXTERNALLY_VALIDATED = 255; bytes32 constant AMBIRE_STORAGE_POSITION = keccak256("ambire.smart.contracts.storage"); // Events event LogPrivilegeChanged(address indexed addr, bytes32 priv); event LogErr(address indexed to, uint256 value, bytes data, bytes returnData); // only used in tryCatch // This contract can accept ETH without calldata receive() external payable {} /** * @dev To support EIP 721 and EIP 1155, we need to respond to those methods with their own method signature * @return bytes4 onERC721Received function selector */ function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) { return this.onERC721Received.selector; } /** * @dev To support EIP 721 and EIP 1155, we need to respond to those methods with their own method signature * @return bytes4 onERC1155Received function selector */ function onERC1155Received(address, address, uint256, uint256, bytes calldata) external pure returns (bytes4) { return this.onERC1155Received.selector; } /** * @dev To support EIP 721 and EIP 1155, we need to respond to those methods with their own method signature * @return bytes4 onERC1155Received function selector */ function onERC1155BatchReceived( address, address, uint256[] calldata, uint256[] calldata, bytes calldata ) external pure returns (bytes4) { return this.onERC1155BatchReceived.selector; } /** * @notice nothing to do here * @dev this contract can accept ETH with calldata, hence payable */ fallback() external payable { } function getAmbireStorage() internal pure returns (AmbireStorage storage ds) { bytes32 position = AMBIRE_STORAGE_POSITION; assembly { ds.slot := position } } function nonce() external view returns (uint256) { return getAmbireStorage().nonce; } function privileges(address key) public virtual view returns (bytes32) { return getAmbireStorage().privileges[key]; } /** * @notice used to set the privilege of a key (by `addr`) * @dev normal signatures will be considered valid if the * `addr` they are signed with has non-zero (not 0x000..000) privilege set; we can set the privilege to * a hash of the recovery keys and timelock (see `RecoveryInfo`) to enable recovery signatures * @param addr the address to give privs to * @param priv the privs to give */ function setAddrPrivilege(address addr, bytes32 priv) external payable { require(msg.sender == address(this), 'ONLY_ACCOUNT_CAN_CALL'); getAmbireStorage().privileges[addr] = priv; emit LogPrivilegeChanged(addr, priv); } /** * @notice Useful when we need to do multiple operations but ignore failures in some of them * @param to address we're sending value to * @param value the amount * @param data callData */ function tryCatch(address to, uint256 value, bytes calldata data) external payable { require(msg.sender == address(this), 'ONLY_ACCOUNT_CAN_CALL'); uint256 gasBefore = gasleft(); (bool success, bytes memory returnData) = to.call{ value: value, gas: gasBefore }(data); require(gasleft() > gasBefore / 64, 'TRYCATCH_OOG'); if (!success) emit LogErr(to, value, data, returnData); } /** * @notice same as `tryCatch` but with a gas limit * @param to address we're sending value to * @param value the amount * @param data callData * @param gasLimit how much gas is allowed */ function tryCatchLimit(address to, uint256 value, bytes calldata data, uint256 gasLimit) external payable { require(msg.sender == address(this), 'ONLY_ACCOUNT_CAN_CALL'); uint256 gasBefore = gasleft(); (bool success, bytes memory returnData) = to.call{ value: value, gas: gasLimit }(data); require(gasleft() > gasBefore / 64, 'TRYCATCH_OOG'); if (!success) emit LogErr(to, value, data, returnData); } /** * @notice execute: this method is used to execute a single bundle of calls that are signed with a key * that is authorized to execute on this account (in `privileges`) * @dev WARNING: if the signature of this is changed, we have to change AmbireAccountFactory * @param calls the transaction we're executing. They may not execute * if specific cases. One such is when setting a timelock * @param signature the signature for the transactions */ function execute(Transaction[] calldata calls, bytes calldata signature) public payable { address signerKey; uint8 sigMode = uint8(signature[signature.length - 1]); uint256 currentNonce = getAmbireStorage().nonce; // we increment the nonce here (not using `nonce++` to save some gas) getAmbireStorage().nonce = currentNonce + 1; if (sigMode == SIGMODE_EXTERNALLY_VALIDATED) { bool isValidSig; uint256 timestampValidAfter; (signerKey, isValidSig, timestampValidAfter) = validateExternalSig(calls, signature); if (!isValidSig) { require(block.timestamp >= timestampValidAfter, 'SIGNATURE_VALIDATION_TIMELOCK'); revert('SIGNATURE_VALIDATION_FAIL'); } } else { (signerKey, ) = SignatureValidator.recoverAddrAllowUnprotected( Eip712HashBuilder.getExecute712Hash( currentNonce, calls, keccak256(abi.encode(address(this), block.chainid, currentNonce, calls)) ), signature, true ); require(privileges(signerKey) != bytes32(0), 'INSUFFICIENT_PRIVILEGE'); } executeBatch(calls); // The actual anti-bricking mechanism - do not allow a signerKey to drop their own privileges require(privileges(signerKey) != bytes32(0), 'PRIVILEGE_NOT_DOWNGRADED'); } /** * @notice allows executing multiple bundles of calls (batch together multiple executes) * @param toExec an array of execute function parameters */ function executeMultiple(ExecuteArgs[] calldata toExec) external payable { for (uint256 i = 0; i != toExec.length; i++) execute(toExec[i].calls, toExec[i].signature); } /** * @notice Allows executing calls if the caller itself is authorized * @dev no need for nonce management here cause we're not dealing with sigs * @param calls the transaction we're executing */ function executeBySender(Transaction[] calldata calls) external payable { require(privileges(msg.sender) != bytes32(0), 'INSUFFICIENT_PRIVILEGE'); executeBatch(calls); // again, anti-bricking require(privileges(msg.sender) != bytes32(0), 'PRIVILEGE_NOT_DOWNGRADED'); } /** * @notice allows the contract itself to execute a batch of calls * self-calling is useful in cases like wanting to do multiple things in a tryCatchLimit * @param calls the calls we're executing */ function executeBySelf(Transaction[] calldata calls) external payable { require(msg.sender == address(this), 'ONLY_ACCOUNT_CAN_CALL'); executeBatch(calls); } /** * @notice allows the contract itself to execute a single calls * self-calling is useful when you want to workaround the executeBatch() * protection of not being able to call address(0) * @param call the call we're executing */ function executeBySelfSingle(Transaction calldata call) external payable { require(msg.sender == address(this), 'ONLY_ACCOUNT_CAN_CALL'); executeCall(call.to, call.value, call.data); } /** * @notice Execute a batch of transactions * @param calls the transaction we're executing */ function executeBatch(Transaction[] memory calls) internal { uint256 len = calls.length; for (uint256 i = 0; i < len; i++) { Transaction memory call = calls[i]; if (call.to != address(0)) executeCall(call.to, call.value, call.data); } } /** * @notice Execute a signle transaction * @dev we shouldn't use address.call(), cause: https://github.com/ethereum/solidity/issues/2884 * @param to the address we're sending to * @param value the amount we're sending * @param data callData */ function executeCall(address to, uint256 value, bytes memory data) internal { assembly { let result := call(gas(), to, value, add(data, 0x20), mload(data), 0, 0) if eq(result, 0) { let size := returndatasize() let ptr := mload(0x40) returndatacopy(ptr, 0, size) revert(ptr, size) } } } /** * @notice EIP-1271 implementation * @dev see https://eips.ethereum.org/EIPS/eip-1271 * @param hash the signed hash * @param signature the signature for the signed hash * @return bytes4 is it a success or a failure */ function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4) { (address recovered, bool usedUnprotected) = SignatureValidator.recoverAddrAllowUnprotected(hash, signature, false); if (uint256(privileges(recovered)) > (usedUnprotected ? 1 : 0)) { // bytes4(keccak256("isValidSignature(bytes32,bytes)") return 0x1626ba7e; } else { return 0xffffffff; } } /** * @notice EIP-1155 implementation * we pretty much only need to signal that we support the interface for 165, but for 1155 we also need the fallback function * @param interfaceID the interface we're signaling support for * @return bool do we support the interface or not */ function supportsInterface(bytes4 interfaceID) external pure returns (bool) { bool supported = interfaceID == 0x01ffc9a7 || // ERC-165 support (i.e. `bytes4(keccak256('supportsInterface(bytes4)'))`). interfaceID == 0x150b7a02 || // ERC721TokenReceiver interfaceID == 0x4e2312e0 || // ERC-1155 `ERC1155TokenReceiver` support (i.e. `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)")) ^ bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`). interfaceID == 0x0a417632; // used for checking whether the account is v2 or not return supported; } // // EIP-4337 implementation // // return value in case of signature failure, with no time-range. // equivalent to packSigTimeRange(true,0,0); uint256 constant internal SIG_VALIDATION_FAILED = 1; // equivalent to packSigTimeRange(false,0,0); uint256 constant internal SIG_VALIDATION_SUCCESS = 0; /** * @notice EIP-4337 implementation * @dev We have an edge case for enabling ERC-4337 in the first if statement. * If the function call is to execute, we do not perform an userOp sig validation. * We require a one time hash nonce commitment from the paymaster for the given * req. We use this to give permissions to the entry point on the fly * and enable ERC-4337 * @param op the PackedUserOperation we're executing * @param userOpHash the hash we've committed to * @param missingAccountFunds the funds the account needs to pay * @return uint256 0 for success, 1 for signature failure, and a uint256 * packed timestamp for a future valid signature: * address aggregator, uint48 validUntil, uint48 validAfter */ function validateUserOp(PackedUserOperation calldata op, bytes32 userOpHash, uint256 missingAccountFunds) external payable returns (uint256) { // enable running executeMultiple operation through the entryPoint if // a paymaster sponsors it with a commitment one-time nonce. // two use cases: // 1) enable 4337 on a network by giving privileges to the entryPoint // 2) key recovery. If the key is lost, we cannot sign the userOp, // so we have to go to `execute` to trigger the recovery logic // Why executeMultiple but not execute? // executeMultiple allows us to combine recovery + fee payment calls. // The fee payment call will be with a signature from the new key if (op.callData.length >= 4 && bytes4(op.callData[0:4]) == this.executeMultiple.selector) { // Require a paymaster, otherwise this mode can be used by anyone to get the user to spend their deposit // @estimation-no-revert if (op.signature.length != 0) return SIG_VALIDATION_FAILED; require( op.paymasterAndData.length >= UserOpHelper.PAYMASTER_DATA_OFFSET && bytes20(op.paymasterAndData[:UserOpHelper.PAYMASTER_ADDR_OFFSET]) != bytes20(0), 'validateUserOp: paymaster required in execute() mode' ); // hashing in everything except sender (nonces are scoped by sender anyway), nonce, signature uint256 targetNonce = uint256(keccak256( abi.encode(op.initCode, op.callData, op.accountGasLimits, op.preVerificationGas, op.gasFees, op.paymasterAndData) )) << 64; // @estimation-no-revert if (op.nonce != targetNonce) return SIG_VALIDATION_FAILED; return SIG_VALIDATION_SUCCESS; } require(privileges(msg.sender) == ENTRY_POINT_MARKER, 'validateUserOp: not from entryPoint'); // @estimation // paying should happen even if signature validation fails if (missingAccountFunds > 0) { // NOTE: MAY pay more than the minimum, to deposit for future transactions (bool success,) = msg.sender.call{value : missingAccountFunds}(''); // ignore failure (its EntryPoint's job to verify, not account.) (success); } // this is replay-safe because userOpHash is retrieved like this: keccak256(abi.encode(userOp.hash(), address(this), block.chainid)) (address signer, ) = SignatureValidator.recoverAddrAllowUnprotected( Eip712HashBuilder.getUserOp712Hash(op, userOpHash), op.signature, true ); if (privileges(signer) == bytes32(0)) return SIG_VALIDATION_FAILED; return SIG_VALIDATION_SUCCESS; } function validateExternalSig(Transaction[] memory calls, bytes calldata signature) internal returns(address signerKey, bool isValidSig, uint256 timestampValidAfter) { (bytes memory sig, ) = SignatureValidator.splitSignature(signature); // the address of the validator we're using for this validation address validatorAddr; // all the data needed by the validator to execute the validation. // In the case of DKIMRecoverySigValidator, this is AccInfo: // abi.encode {string emailFrom; string emailTo; string domainName; // bytes dkimPubKeyModulus; bytes dkimPubKeyExponent; address secondaryKey; // bool acceptUnknownSelectors; uint32 waitUntilAcceptAdded; // uint32 waitUntilAcceptRemoved; bool acceptEmptyDKIMSig; // bool acceptEmptySecondSig;uint32 onlyOneSigTimelock;} // The struct is declared in DKIMRecoverySigValidator bytes memory validatorData; // the signature data needed by the external validator. // In the case of DKIMRecoverySigValidator, this is abi.encode( // SignatureMeta memory sigMeta, bytes memory dkimSig, bytes memory secondSig // ). bytes memory innerSig; // the signerKey in this case is an arbitrary value that does // not have any specific purpose other than representing // the privileges key (signerKey, validatorAddr, validatorData, innerSig) = abi.decode(sig, (address, address, bytes, bytes)); require( privileges(signerKey) == keccak256(abi.encode(validatorAddr, validatorData)), 'EXTERNAL_VALIDATION_NOT_SET' ); // The sig validator itself should throw when a signature isn't validated successfully // the return value just indicates whether we want to execute the current calls (isValidSig, timestampValidAfter) = ExternalSigValidator(validatorAddr).validateSig(validatorData, innerSig, calls); } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity ^0.8.7; import '../libs/Transaction.sol'; interface IAmbireAccount { struct AmbireStorage { mapping(address => bytes32) privileges; uint256 nonce; } struct RecoveryInfo { address[] keys; uint timelock; } struct ExecuteArgs { Transaction[] calls; bytes signature; } // storage access methods function nonce() external view returns (uint256); function privileges(address key) external view returns (bytes32); function setAddrPrivilege(address addr, bytes32 priv) external payable; function tryCatch(address to, uint value, bytes calldata data) external payable; function tryCatchLimit(address to, uint value, bytes calldata data, uint gasLimit) external payable; function execute(Transaction[] calldata txns, bytes calldata signature) external payable; function executeBySender(Transaction[] calldata txns) external payable; function executeBySelf(Transaction[] calldata txns) external payable; function executeMultiple(ExecuteArgs[] calldata toExec) external payable; // EIP 1271 implementation // see https://eips.ethereum.org/EIPS/eip-1271 function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4); function supportsInterface(bytes4 interfaceID) external view returns (bool); }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.8.19; import './libs/Transaction.sol'; /** * @title ExternalSigValidator * @notice A way to add custom recovery to AmbireAccount. * address accountAddr is the Ambire account address * bytes calldata data is all the data needed by the ExternalSigValidator. * It could be anything and it's validator specific. * bytes calldata sig is the signature we're validating. Notice its not * bytes32 so there could be cases where its not only the signature. It's * validator specific * uint256 nonce - the Ambire account nonce * Transaction[] calldata calls - the txns that are going to be executed * if the validation is successful * @dev Not all passed properties necessarily need to be used. */ abstract contract ExternalSigValidator { function validateSig( bytes calldata data, bytes calldata sig, Transaction[] calldata calls ) external virtual returns (bool isValidSignature, uint256 timestampValidAfter); }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.8.19; library Bytes { function trimToSize(bytes memory b, uint256 newLen) internal pure { require(b.length > newLen, 'BytesLib: only shrinking'); assembly { mstore(b, newLen) } } /***********************************| | Read Bytes Functions | |__________________________________*/ /** * @dev Reads a bytes32 value from a position in a byte array. * @param b Byte array containing a bytes32 value. * @param index Index in byte array of bytes32 value. * @return result bytes32 value from byte array. */ function readBytes32(bytes memory b, uint256 index) internal pure returns (bytes32 result) { // Arrays are prefixed by a 256 bit length parameter index += 32; require(b.length >= index, 'BytesLib: length'); // Read the bytes32 from array memory assembly { result := mload(add(b, index)) } return result; } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.8.19; import './erc4337/PackedUserOperation.sol'; import './Transaction.sol'; import '../deployless/IAmbireAccount.sol'; library Eip712HashBuilder { function getDomainHash() internal view returns (bytes32) { return keccak256( abi.encode( keccak256( 'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)' ), keccak256(bytes('Ambire')), keccak256(bytes('1')), block.chainid, address(this), bytes32(0) ) ); } function getCallsEncoding(Transaction[] memory calls) internal pure returns (bytes32) { bytes32[] memory callHashes = new bytes32[](calls.length); for (uint256 i = 0; i < calls.length; i++) { callHashes[i] = getCallEncoding(calls[i]); } return keccak256(abi.encodePacked(callHashes)); } function getCallEncoding(Transaction memory call) internal pure returns (bytes32) { return keccak256( abi.encode( keccak256(bytes('Transaction(address to,uint256 value,bytes data)')), call.to, call.value, keccak256(call.data) ) ); } function getExecute712Hash( uint256 nonce, Transaction[] calldata calls, bytes32 hash ) internal view returns (bytes32) { return keccak256( abi.encodePacked( '\x19\x01', getDomainHash(), keccak256( abi.encode( keccak256( bytes( 'AmbireExecuteAccountOp(address account,uint256 chainId,uint256 nonce,Transaction[] calls,bytes32 hash)Transaction(address to,uint256 value,bytes data)' ) ), address(this), block.chainid, nonce, getCallsEncoding(calls), hash ) ) ) ); } function getUserOp712Hash( PackedUserOperation calldata op, bytes32 hash ) internal view returns (bytes32) { // decode the calls if any Transaction[] memory calls; if (op.callData.length >= 4) { bytes4 functionSig = bytes4(op.callData[0:4]); if (functionSig == IAmbireAccount.executeBySender.selector) { calls = abi.decode(op.callData[4:], (Transaction[])); } else if (functionSig == IAmbireAccount.execute.selector) { (calls, ) = abi.decode(op.callData[4:], (Transaction[], bytes)); } } return keccak256( abi.encodePacked( '\x19\x01', getDomainHash(), keccak256( abi.encode( keccak256( bytes( // removed entryPoint from here as its in the final hash prop 'Ambire4337AccountOp(address account,uint256 chainId,uint256 nonce,bytes initCode,bytes32 accountGasLimits,uint256 preVerificationGas,bytes32 gasFees,bytes paymasterAndData,bytes callData,Transaction[] calls,bytes32 hash)Transaction(address to,uint256 value,bytes data)' ) ), address(this), block.chainid, op.nonce, keccak256(op.initCode), op.accountGasLimits, op.preVerificationGas, op.gasFees, keccak256(op.paymasterAndData), keccak256(op.callData), getCallsEncoding(calls), hash ) ) ) ); } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.8.19; /** * User Operation struct * @param sender - The sender account of this request. * @param nonce - Unique value the sender uses to verify it is not a replay. * @param initCode - If set, the account contract will be created by this constructor/ * @param callData - The method call to execute on this account. * @param accountGasLimits - Packed gas limits for validateUserOp and gas limit passed to the callData method call. * @param preVerificationGas - Gas not calculated by the handleOps method, but added to the gas paid. * Covers batch overhead. * @param gasFees - packed gas fields maxPriorityFeePerGas and maxFeePerGas - Same as EIP-1559 gas parameters. * @param paymasterAndData - If set, this field holds the paymaster address, verification gas limit, postOp gas limit and paymaster-specific extra data * The paymaster will pay for the transaction instead of the sender. * @param signature - Sender-verified signature over the entire request, the EntryPoint address and the chain ID. */ struct PackedUserOperation { address sender; uint256 nonce; bytes initCode; bytes callData; // callGasLimit + verificationGasLimit bytes32 accountGasLimits; uint256 preVerificationGas; // maxFeePerGas + maxPriorityFeePerGas bytes32 gasFees; bytes paymasterAndData; bytes signature; }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.8.19; library UserOpHelper { uint256 public constant PAYMASTER_ADDR_OFFSET = 20; // 52 = 20 address + 16 paymasterVerificationGasLimit + 16 paymasterPostOpGasLimit uint256 public constant PAYMASTER_DATA_OFFSET = 52; }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.8.19; import './Bytes.sol'; interface IERC1271Wallet { function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4 magicValue); } library SignatureValidator { using Bytes for bytes; enum SignatureMode { // the first mode Unprotected is used in combination with EIP-1271 signature verification to do // EIP-712 verifications, as well as "Ethereum signed message:" message verifications // The caveat with this is that we need to ensure that the signer key used for it isn't reused, or the message body // itself contains context about the wallet (such as it's address) // We do this, rather than applying the prefix on-chain, because if we do you won't be able to see the message // when signing on a hardware wallet (you'll only see the hash) - since `isValidSignature` can only receive the hash - // if the prefix is applied on-chain you can never match it - it's hash(prefix+hash(msg)) vs hash(prefix+msg) // As for transactions (`execute()`), those can be signed with any of the modes // Otherwise, if it's reused, we MUST use `Standard` mode which always wraps the final digest hash, but unfortnately this means // you can't preview the full message when signing on a HW wallet Unprotected, Standard, SmartWallet, Spoof, Schnorr, Multisig, // WARNING: Signature modes should not be more than 26 as the "v" // value for standard ecrecover is 27/28 // WARNING: must always be last LastUnused } // bytes4(keccak256("isValidSignature(bytes32,bytes)")) bytes4 internal constant ERC1271_MAGICVALUE_BYTES32 = 0x1626ba7e; // secp256k1 group order uint256 internal constant Q = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141; function splitSignature(bytes memory sig) internal pure returns (bytes memory, uint8) { uint8 modeRaw; unchecked { modeRaw = uint8(sig[sig.length - 1]); } sig.trimToSize(sig.length - 1); return (sig, modeRaw); } function recoverAddr(bytes32 hash, bytes memory sig, bool allowSpoofing) internal view returns (address) { (address recovered, bool usedUnprotected) = recoverAddrAllowUnprotected(hash, sig, allowSpoofing); require(!usedUnprotected, 'SV_USED_UNBOUND'); return recovered; } function recoverAddrAllowUnprotected(bytes32 hash, bytes memory sig, bool allowSpoofing) internal view returns (address, bool) { require(sig.length != 0, 'SV_SIGLEN'); uint8 modeRaw; unchecked { modeRaw = uint8(sig[sig.length - 1]); } // Ensure we're in bounds for mode; Solidity does this as well but it will just silently blow up rather than showing a decent error if (modeRaw >= uint8(SignatureMode.LastUnused)) { // NOTE: this edge case is crazy powerful; first of all, why it's safe: because if you use a regular ECDSA 65-byte format defined by OpenZeppelin and others, // it will always end in 27 or 28, which are not valid signature modes. So it's not possible to mistake this for any other type of signature, and we'll always end up // hitting `modeRaw >= uint8(SignatureMode.LastUnused)` condition // it's used for two things // 1) EIP-7702 (originally designed for EIP-3074): this one is fairly obvious: we can continue validating EOA sigs as normal if the account is EIP-7702 delegated // This is needed because proper sig libraries should start by calling `isValidSignature` (EIP-1271) if a certain account has code, // before trying pure ECDSA (see EIP-6492 Rationale to understand why). // 2) EOA simulations: when we use state override to simulate stuff from an actual EOA (via virtually converting it to AmbireAccount), // we may be simulating stuff that's dependent on EOA signatures that this user already made (eg swap using permit2). So within this simulation, we need to // retain the permit2 sig being a valid sig. if (sig.length == 65) modeRaw = uint8(SignatureMode.Unprotected); else revert('SV_SIGMODE'); } SignatureMode mode = SignatureMode(modeRaw); // the address of the key we are gonna be returning address signerKey; // wrap in the EIP712 wrapping if it's not unbound // multisig gets an exception because each inner sig will have to apply this logic // @TODO should spoofing be removed from this? bool isUnprotected = mode == SignatureMode.Unprotected || mode == SignatureMode.Multisig; if (!isUnprotected) { bytes32 DOMAIN_SEPARATOR = keccak256(abi.encode( keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)'), keccak256(bytes('Ambire')), keccak256(bytes('1')), block.chainid, address(this), bytes32(0) )); hash = keccak256(abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR, keccak256(abi.encode( keccak256(bytes('AmbireOperation(address account,bytes32 hash)')), address(this), hash )) )); } // {r}{s}{v}{mode} if (mode == SignatureMode.Unprotected || mode == SignatureMode.Standard) { require(sig.length == 65 || sig.length == 66, 'SV_LEN'); bytes32 r = sig.readBytes32(0); bytes32 s = sig.readBytes32(32); uint8 v = uint8(sig[64]); signerKey = ecrecover(hash, v, r, s); // {sig}{verifier}{mode} } else if (mode == SignatureMode.Schnorr) { // Based on https://hackmd.io/@nZ-twauPRISEa6G9zg3XRw/SyjJzSLt9 // You can use this library to produce signatures: https://github.com/borislav-itskov/schnorrkel.js // px := public key x-coord // e := schnorr signature challenge // s := schnorr signature // parity := public key y-coord parity (27 or 28) // last uint8 is for the Ambire sig mode - it's ignored sig.trimToSize(sig.length - 1); (bytes32 px, bytes32 e, bytes32 s, uint8 parity) = abi.decode(sig, (bytes32, bytes32, bytes32, uint8)); // ecrecover = (m, v, r, s); bytes32 sp = bytes32(Q - mulmod(uint256(s), uint256(px), Q)); bytes32 ep = bytes32(Q - mulmod(uint256(e), uint256(px), Q)); require(sp != bytes32(Q)); // the ecrecover precompile implementation checks that the `r` and `s` // inputs are non-zero (in this case, `px` and `ep`), thus we don't need to // check if they're zero. address R = ecrecover(sp, parity, px, ep); require(R != address(0), 'SV_ZERO_SIG'); require(e == keccak256(abi.encodePacked(R, uint8(parity), px, hash)), 'SV_SCHNORR_FAILED'); signerKey = address(uint160(uint256(keccak256(abi.encodePacked('SCHNORR', px))))); } else if (mode == SignatureMode.Multisig) { sig.trimToSize(sig.length - 1); bytes[] memory signatures = abi.decode(sig, (bytes[])); // since we're in a multisig, we care if any of the inner sigs are unbound isUnprotected = false; for (uint256 i = 0; i != signatures.length; i++) { (address inner, bool isInnerUnprotected) = recoverAddrAllowUnprotected(hash, signatures[i], false); if (isInnerUnprotected) isUnprotected = true; signerKey = address( uint160(uint256(keccak256(abi.encodePacked(signerKey, inner)))) ); } } else if (mode == SignatureMode.SmartWallet) { // 32 bytes for the addr, 1 byte for the type = 33 require(sig.length > 33, 'SV_LEN_WALLET'); uint256 newLen; unchecked { newLen = sig.length - 33; } IERC1271Wallet wallet = IERC1271Wallet(address(uint160(uint256(sig.readBytes32(newLen))))); sig.trimToSize(newLen); require(ERC1271_MAGICVALUE_BYTES32 == wallet.isValidSignature(hash, sig), 'SV_WALLET_INVALID'); signerKey = address(wallet); // {address}{mode}; the spoof mode is used when simulating calls } else if (mode == SignatureMode.Spoof && allowSpoofing) { // This is safe cause it's specifically intended for spoofing sigs in simulation conditions, where tx.origin can be controlled // We did not choose 0x00..00 because in future network upgrades tx.origin may be nerfed or there may be edge cases in which // it is zero, such as native account abstraction // slither-disable-next-line tx-origin require(tx.origin == address(1) || tx.origin == address(6969), 'SV_SPOOF_ORIGIN'); require(sig.length == 33, 'SV_SPOOF_LEN'); sig.trimToSize(32); // To simulate the gas usage; check is just to silence unused warning require(ecrecover(0, 0, 0, 0) != address(6969)); signerKey = abi.decode(sig, (address)); } else { revert('SV_TYPE'); } require(signerKey != address(0), 'SV_ZERO_SIG'); return (signerKey, isUnprotected); } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity ^0.8.19; // Transaction structure // we handle replay protection separately by requiring (address(this), chainID, nonce) as part of the sig // @dev a better name for this would be `Call`, but we are keeping `Transaction` for backwards compatibility struct Transaction { address to; uint256 value; bytes data; }
{ "viaIR": true, "optimizer": { "enabled": true, "runs": 1000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"returnData","type":"bytes"}],"name":"LogErr","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"bytes32","name":"priv","type":"bytes32"}],"name":"LogPrivilegeChanged","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Transaction[]","name":"calls","type":"tuple[]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Transaction[]","name":"calls","type":"tuple[]"}],"name":"executeBySelf","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Transaction","name":"call","type":"tuple"}],"name":"executeBySelfSingle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Transaction[]","name":"calls","type":"tuple[]"}],"name":"executeBySender","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Transaction[]","name":"calls","type":"tuple[]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct IAmbireAccount.ExecuteArgs[]","name":"toExec","type":"tuple[]"}],"name":"executeMultiple","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"key","type":"address"}],"name":"privileges","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bytes32","name":"priv","type":"bytes32"}],"name":"setAddrPrivilege","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"tryCatch","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"tryCatchLimit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"bytes32","name":"accountGasLimits","type":"bytes32"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"bytes32","name":"gasFees","type":"bytes32"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct PackedUserOperation","name":"op","type":"tuple"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"},{"internalType":"uint256","name":"missingAccountFunds","type":"uint256"}],"name":"validateUserOp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
6080806040523461001657612b9a908161001c8239f35b600080fdfe60806040526004361015610018575b361561001657005b005b60003560e01c806301ffc9a7146101185780630d5828d414610113578063150b7a021461010e5780631626ba7e1461010957806319822f7c146101045780633628d042146100ff5780636171d1c9146100fa5780636769de82146100f5578063a2ea6766146100f0578063abc5345e146100eb578063affed0e0146100e6578063bc197c81146100e1578063bf1cb383146100dc578063c066a5b1146100d7578063e6a6332e146100d25763f23a6e610361000e576107fc565b610790565b610769565b6106fc565b610653565b610616565b6105e1565b610561565b61053b565b6104bb565b6103c6565b61037b565b61032a565b6102d0565b610217565b610134565b6001600160e01b031981160361012f57565b600080fd5b3461012f57602036600319011261012f5760206001600160e01b031960043561015c8161011d565b167f01ffc9a70000000000000000000000000000000000000000000000000000000081149081156101f5575b81156101cb575b81156101a1575b506040519015158152f35b7f0a4176320000000000000000000000000000000000000000000000000000000091501438610196565b7f4e2312e0000000000000000000000000000000000000000000000000000000008114915061018f565b630a85bd0160e11b81149150610188565b6001600160a01b0381160361012f57565b604036600319011261012f5760043561022f81610206565b7f08ac40e0195c5998554e98853c23964a13a24309e127b2d016e8ec4adecf5e8360206001600160a01b036024359361026930331461086f565b1692836000527fcf2d407e18d78434343f77ac26e3f37aebbb1bffbd82f21ecba2a4839c706b7f825280604060002055604051908152a2005b9181601f8401121561012f5782359167ffffffffffffffff831161012f576020838186019501011161012f57565b3461012f57608036600319011261012f576102ec600435610206565b6102f7602435610206565b60643567ffffffffffffffff811161012f576103179036906004016102a2565b50506020604051630a85bd0160e11b8152f35b3461012f57604036600319011261012f5760243567ffffffffffffffff811161012f5761036961036060209236906004016102a2565b9060043561108e565b6001600160e01b031960405191168152f35b60031960603682011261012f576004359067ffffffffffffffff821161012f5761012090823603011261012f576103be60209160443590602435906004016112a3565b604051908152f35b608036600319011261012f576004356103de81610206565b6024359060443567ffffffffffffffff811161012f576104029036906004016102a2565b909161040f30331461086f565b5a92600080604051858482378086810183815203908886606435f1610441610435610983565b955a9060061c106109c9565b1561044857005b7f80c2637928bd94d0e1a90eaac1efc1553be6391d962fe5c82a01e90122c84ccc936001600160a01b039361048592604051958695169785610a7d565b0390a2005b9181601f8401121561012f5782359167ffffffffffffffff831161012f576020808501948460051b01011161012f57565b604036600319011261012f5767ffffffffffffffff60043581811161012f576104e890369060040161048a565b9060243592831161012f576105046100169336906004016102a2565b929091610dfe565b602060031982011261012f576004359067ffffffffffffffff821161012f576105379160040161048a565b9091565b61001661055c61054a3661050c565b61055530331461086f565b3691610cb8565b611014565b61056a3661050c565b60005b81810361057657005b610581818385610fab565b803590601e198136030182121561012f57019081359167ffffffffffffffff831161012f576020809101928060051b3603841361012f576105dc936105046105d7936105ce86898b610fab565b90810190610fcd565b610f9c565b61056d565b61060361055c6105f03661050c565b6105556105fc3361173a565b1515610c3a565b61001661060f3361173a565b1515610db3565b3461012f57600036600319011261012f5760207fcf2d407e18d78434343f77ac26e3f37aebbb1bffbd82f21ecba2a4839c706b8054604051908152f35b3461012f5760a036600319011261012f5761066f600435610206565b61067a602435610206565b67ffffffffffffffff60443581811161012f5761069b90369060040161048a565b505060643581811161012f576106b590369060040161048a565b505060843590811161012f576106cf9036906004016102a2565b50506040517fbc197c81000000000000000000000000000000000000000000000000000000008152602090f35b606036600319011261012f5760043561071481610206565b6024359060443567ffffffffffffffff811161012f576107389036906004016102a2565b909161074530331461086f565b5a9260008060405185848237808681018381520390888689f1610441610435610983565b3461012f57602036600319011261012f5760206103be60043561078b81610206565b61173a565b60031960203682011261012f5760043567ffffffffffffffff811161012f5760608160040192823603011261012f57610016916107ce30331461086f565b60246107f36107ec8335936107e285610206565b6044860190610fcd565b3691610c03565b9201359061106d565b3461012f5760a036600319011261012f57610818600435610206565b610823602435610206565b60843567ffffffffffffffff811161012f576108439036906004016102a2565b505060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b1561087657565b606460405162461bcd60e51b815260206004820152601560248201527f4f4e4c595f4143434f554e545f43414e5f43414c4c00000000000000000000006044820152fd5b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff8211176108ec57604052565b6108ba565b60c0810190811067ffffffffffffffff8211176108ec57604052565b6040810190811067ffffffffffffffff8211176108ec57604052565b60a0810190811067ffffffffffffffff8211176108ec57604052565b90601f8019910116810190811067ffffffffffffffff8211176108ec57604052565b67ffffffffffffffff81116108ec57601f01601f191660200190565b3d156109ae573d9061099482610967565b916109a26040519384610945565b82523d6000602084013e565b606090565b634e487b7160e01b600052601160045260246000fd5b156109d057565b606460405162461bcd60e51b815260206004820152600c60248201527f54525943415443485f4f4f4700000000000000000000000000000000000000006044820152fd5b908060209392818452848401376000828201840152601f01601f1916010190565b60005b838110610a485750506000910152565b8181015183820152602001610a38565b90602091610a7181518092818552858086019101610a35565b601f01601f1916010190565b9291610aa99492610a9b928552606060208601526060850191610a14565b916040818403910152610a58565b90565b600019810191908211610abb57565b6109b3565b9070014551231950b75fc4402da1732fc9bebe19918203918211610abb57565b634e487b7160e01b600052603260045260246000fd5b90821015610b02570190565b610ae0565b9060018201809211610abb57565b9491909460808101936001600160a01b0380971682526020928383015260409081830152836060956080878501525260a082019060a08560051b84010197876000945b878610610b6c575050505050505050505090565b90919293949596979899609f198282030186528a35605e198436030181121561012f578301848135610b9d81610206565b168252888101358983015285810135601e198236030181121561012f5701888101903567ffffffffffffffff811161012f57803603821361012f57610bef8a9283928e86818c60019901520191610a14565b9c0196019601949897969593929190610b58565b929192610c0f82610967565b91610c1d6040519384610945565b82948184528183011161012f578281602093846000960137010152565b15610c4157565b606460405162461bcd60e51b815260206004820152601660248201527f494e53554646494349454e545f50524956494c454745000000000000000000006044820152fd5b67ffffffffffffffff81116108ec5760051b60200190565b9080601f8301121561012f57816020610aa993359101610c03565b90929192610cc581610c85565b91604091610cd583519485610945565b839581855260208095019160051b83019381851161012f5783925b858410610d005750505050505050565b67ffffffffffffffff90843582811161012f5786019060608286031261012f578351610d2b816108d0565b8235610d3681610206565b8152898301358a8201528483013593841161012f57610d59868b95869501610c9d565b85820152815201930192610cf0565b15610d6f57565b606460405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f56414c49444154494f4e5f54494d454c4f434b0000006044820152fd5b15610dba57565b606460405162461bcd60e51b815260206004820152601860248201527f50524956494c4547455f4e4f545f444f574e47524144454400000000000000006044820152fd5b91929092610e47610e41610e1b610e1485610aac565b8585610af6565b357fff000000000000000000000000000000000000000000000000000000000000001690565b60f81c90565b60ff807fcf2d407e18d78434343f77ac26e3f37aebbb1bffbd82f21ecba2a4839c706b805492610e9d610e7985610b07565b7fcf2d407e18d78434343f77ac26e3f37aebbb1bffbd82f21ecba2a4839c706b8055565b1603610f2c575090610eb991610eb4368686610cb8565b611651565b9093919315610edb57509161078b61055c61060f93610ed9953691610cb8565b565b610ee790421015610d68565b60405162461bcd60e51b815260206004820152601960248201527f5349474e41545552455f56414c49444154494f4e5f4641494c000000000000006044820152606490fd5b83610f8960018795610f8361078b96610f7b61055c97610ed99c61060f9c6040516020810190610f7281610f64868689463089610b15565b03601f198101835282610945565b5190209261179e565b923691610c03565b906123ff565b5093610f976105fc8661173a565b610555565b6000198114610abb5760010190565b9190811015610b025760051b81013590603e198136030182121561012f570190565b903590601e198136030182121561012f570180359067ffffffffffffffff821161012f5760200191813603831361012f57565b8051821015610b025760209160051b010190565b80519060005b82811061102657505050565b8061103461104d9284611000565b516001600160a01b0381511680611052575b5050610f9c565b61101a565b81604060206110669401519101519161106d565b3880611046565b916000928392602083519301915af11561108357565b3d604051816000823efd5b600090610f836110a3936110aa953691610c03565b919061173a565b90600090156110d7575060ff60015b1610156110cb57630b135d3f60e11b90565b6001600160e01b031990565b60ff906110b9565b9060041161012f5790600490565b9060141161012f5790601490565b909291928360041161012f57831161012f57600401916003190190565b6001600160e01b0319903581811693926004811061113557505050565b60040360031b82901b16169150565b6bffffffffffffffffffffffff19903581811693926014811061116657505050565b60140360031b82901b16169150565b1561117c57565b608460405162461bcd60e51b815260206004820152603460248201527f76616c6964617465557365724f703a207061796d61737465722072657175697260448201527f656420696e20657865637574652829206d6f64650000000000000000000000006064820152fd5b949795929093611207610aa99a98956112159460c0895260c0890191610a14565b918683036020880152610a14565b9560408401526060830152608082015260a0818503910152610a14565b1561123957565b608460405162461bcd60e51b815260206004820152602360248201527f76616c6964617465557365724f703a206e6f742066726f6d20656e747279506f60448201527f696e7400000000000000000000000000000000000000000000000000000000006064820152fd5b916060830160046112b48286610fcd565b9050101580611418575b611333575061130b92610f836107ec6112f9611305956001956112ec6171716112e63361173a565b14611232565b8061131a575b5084611d5c565b92610100810190610fcd565b5061173a565b1561131557600090565b600190565b600080808093335af15061132c610983565b50386112f2565b915050611344610100830183610fcd565b9050611411576113cb60209160e084019060346113618387610fcd565b90501015806113d8575b61137490611175565b6113c261139f610f6461139661138d60408a018a610fcd565b9190958a610fcd565b9390968a610fcd565b918a6040519788968c88019a60c084013594608060a0860135950135938d6111e6565b51902060401b90565b9101350361131557600090565b506113746114076113f26113ec8589610fcd565b906110ed565b6bffffffffffffffffffffffff199291611144565b161515905061136b565b5050600190565b507fa2ea6766000000000000000000000000000000000000000000000000000000006001600160e01b031961145f6114596114538589610fcd565b906110df565b90611118565b16146112be565b81601f8201121561012f57805161147c81610967565b9261148a6040519485610945565b8184526020828401011161012f57610aa99160208085019101610a35565b9060808282031261012f5781516114be81610206565b9260208301516114cd81610206565b9260408101519267ffffffffffffffff9384811161012f57816114f1918401611466565b93606083015190811161012f57610aa99201611466565b6040906001600160a01b03610aa994931681528160208201520190610a58565b1561152f57565b606460405162461bcd60e51b815260206004820152601b60248201527f45585445524e414c5f56414c49444154494f4e5f4e4f545f53455400000000006044820152fd5b919082604091031261012f578151801515810361012f5760209092015190565b906115b86115a960609283855283850190610a58565b60209484820386860152610a58565b926040928381860391015284519182855281850182808560051b8801019701946000925b8584106115ee57505050505050505090565b90919293949596989785806116316001938d601f1990820301885285878d516001600160a01b038151168452858101518685015201519181898201520190610a58565b9a9b990197969591909101930191906115dc565b6040513d6000823e3d90fd5b60409061168161167161166c6116f395600098973691610c03565b611f8d565b50602080825183010191016114a8565b916001600160a01b039891988091169316976116be61169f8a61173a565b875160208101906116b581610f64878b86611508565b51902014611528565b8551968795869485937ffcfbba4d00000000000000000000000000000000000000000000000000000000855260048501611593565b03925af1801561173557600091829161170b57509091565b9050610537915060403d811161172e575b6117268183610945565b810190611573565b503d61171c565b611645565b6001600160a01b0316308114611798576f71727de22e5e9d8baf0edac6f37da0328114611791576000527fcf2d407e18d78434343f77ac26e3f37aebbb1bffbd82f21ecba2a4839c706b7f60205260406000205490565b5061717190565b50600290565b9261190e9261191a92946118d06118986118936117b9611992565b9860966040516117c8816108f1565b8181527f743235362076616c75652c62797465732064617461290000000000000000000060a060208301927f416d62697265457865637574654163636f756e744f702861646472657373206184527f63636f756e742c75696e7432353620636861696e49642c75696e74323536206e60408201527f6f6e63652c5472616e73616374696f6e5b5d2063616c6c732c6279746573333260608201527f2068617368295472616e73616374696f6e286164647265737320746f2c75696e6080820152015220953691610cb8565b611a39565b60408051602081019586523091810191909152466060820152608081019390935260a083015260c082019390935291829060e0820190565b03916118e4601f1993848101835282610945565b519020604051938491602083019687909160429261190160f01b8352600283015260228201520190565b03908101835282610945565b51902090565b6040519061192d8261090d565b600682527f416d6269726500000000000000000000000000000000000000000000000000006020830152565b604051906119668261090d565b600182527f31000000000000000000000000000000000000000000000000000000000000006020830152565b61199a611920565b60208151910120610f6461191a6119af611959565b8051602091820120604080517fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac564729381019384529081019590955260608501524660808501523060a0850152600060c08501529291829060e0820190565b805160208092019160005b828110611a25575050505090565b835185529381019392810192600101611a17565b611a66908051611a4881610c85565b91604091611a5883519485610945565b808452601f19948591610c85565b0194602095368786013760005b8251811015611b405780611a8a611b3b9285611000565b518551611a96816108d0565b6030908181527f616c75652c627974657320646174612900000000000000000000000000000000888c8301927f5472616e73616374696f6e286164647265737320746f2c75696e7432353620768452015220906001600160a01b0381511690878b8201519101518b8151910120908851928c8401948552898401526060830152608090818301528152611b2881610929565b519020611b358288611000565b52610f9c565b611a73565b509461190e9394915061191a925193849182018096611a0c565b9080601f8301121561012f57816020610aa993359101610cb8565b91909160408184031261012f5767ffffffffffffffff92813584811161012f5781611ba1918401611b5a565b93602083013590811161012f57610aa99201610c9d565b9060208282031261012f57813567ffffffffffffffff811161012f57610aa99201611b5a565b60405190610140820182811067ffffffffffffffff8211176108ec5760405261010c82527f2c62797465732064617461290000000000000000000000000000000000000000610120837f416d62697265343333374163636f756e744f702861646472657373206163636f60208201527f756e742c75696e7432353620636861696e49642c75696e74323536206e6f6e6360408201527f652c627974657320696e6974436f64652c62797465733332206163636f756e7460608201527f4761734c696d6974732c75696e7432353620707265566572696669636174696f60808201527f6e4761732c6279746573333220676173466565732c6279746573207061796d6160a08201527f73746572416e64446174612c62797465732063616c6c446174612c5472616e7360c08201527f616374696f6e5b5d2063616c6c732c627974657333322068617368295472616e60e08201527f73616374696f6e286164647265737320746f2c75696e743235362076616c75656101008201520152565b906060808301916004611d6f8486610fcd565b90501015611ea6575b61191a9192611d85611992565b94611e66611d91611bde565b93845196602097888097012090611dae6107ec6040870187610fcd565b87815191012095611de7611ddb6107ec611dce6107ec60e08b018b610fcd565b8b81519101209389610fcd565b89815191012092611a39565b926040519889978189019960c08201359360a0830135936080840135930135908c469130919895926001600160a01b036101609b9895929e9d9c9996936101808c019f8c521660208b015260408a01526060890152608088015260a087015260c086015260e08501526101008401526101208301526101408201520152565b0391611e7a601f1993848101835282610945565b5190209261190e60405194859283019687909160429261190160f01b8352600283015260228201520190565b6001600160e01b0319611ebf6114596114538688610fcd565b167fabc5345e000000000000000000000000000000000000000000000000000000008103611f16575061191a9150611f0c611f04611efd8587610fcd565b80916110fb565b810190611bb8565b925b929150611d78565b7f6171d1c90000000000000000000000000000000000000000000000000000000014611f47575b61191a9192611f0e565b61191a9150611f64611f5c611efd8587610fcd565b810190611b75565b509150611f3d565b805160401015610b025760600190565b908151811015610b02570160200190565b9060001991611f9f8382510182611f7c565b5160f81c928151908101908111610abb57611fba9082612012565b9190565b602081511115611fce5760209052565b606460405162461bcd60e51b815260206004820152601860248201527f42797465734c69623a206f6e6c7920736872696e6b696e6700000000000000006044820152fd5b8181511115611fce5752565b1561202557565b606460405162461bcd60e51b815260206004820152600960248201527f53565f5349474c454e00000000000000000000000000000000000000000000006044820152fd5b6007111561207357565b634e487b7160e01b600052602160045260246000fd5b60405190612096826108d0565b602d82527f62797465733332206861736829000000000000000000000000000000000000006040837f416d626972654f7065726174696f6e2861646472657373206163636f756e742c60208201520152565b156120ef57565b606460405162461bcd60e51b815260206004820152600f60248201527f53565f53504f4f465f4f524947494e00000000000000000000000000000000006044820152fd5b1561213a57565b606460405162461bcd60e51b815260206004820152600c60248201527f53565f53504f4f465f4c454e00000000000000000000000000000000000000006044820152fd5b1561012f57565b9081602091031261012f5751610aa981610206565b156121a157565b606460405162461bcd60e51b815260206004820152600d60248201527f53565f4c454e5f57414c4c4554000000000000000000000000000000000000006044820152fd5b9081602091031261012f5751610aa98161011d565b604090610aa9939281528160208201520190610a58565b1561221857565b606460405162461bcd60e51b815260206004820152601160248201527f53565f57414c4c45545f494e56414c49440000000000000000000000000000006044820152fd5b90602090818382031261012f57825167ffffffffffffffff9384821161012f570181601f8201121561012f57805161229381610c85565b946122a16040519687610945565b818652848087019260051b8401019380851161012f57858401925b8584106122cd575050505050505090565b835183811161012f5787916122e7848480948a0101611466565b8152019301926122bc565b919082608091031261012f578151916020810151916060604083015192015160ff8116810361012f5790565b1561232557565b606460405162461bcd60e51b815260206004820152600b60248201527f53565f5a45524f5f5349470000000000000000000000000000000000000000006044820152fd5b1561237057565b606460405162461bcd60e51b815260206004820152601160248201527f53565f5343484e4f52525f4641494c45440000000000000000000000000000006044820152fd5b156123bb57565b606460405162461bcd60e51b815260206004820152600660248201527f53565f4c454e00000000000000000000000000000000000000000000000000006044820152fd5b9092919261240f8151151561201e565b61244a610e4161242460001984510184611f7c565b517fff000000000000000000000000000000000000000000000000000000000000001690565b600660ff82161015612a8f575b60ff169361246485612069565b60009061247086612069565b85159586158781612a7a575b881561299b575b61248c83612069565b90612988575b1561253457505050806020926124b76000935160418114908115612529575b506123b4565b6125036124c383612ae5565b926124dc610e416124246124d684612b39565b93611f6c565b93604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15611735576000515b611fba6001600160a01b038216151561231e565b6042915014386124b1565b61253d81612069565b600481036126ef5750505061259c6125dc9260206125788461256a61256460009751610aac565b82612012565b8280825183010191016122f2565b978396899398949270014551231950b75fc4402da1732fc9bebe1993849109610ac0565b916125b56125ac828a8c09610ac0565b9184141561217e565b87604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156117355761268f6126de9383926126ea96612672600051926126126001600160a01b038516151561231e565b6040519687936020850195869290605594927fff00000000000000000000000000000000000000000000000000000000000000916bffffffffffffffffffffffff199060601b16855260f81b166014840152601583015260358201520190565b0393612686601f1995868101835282610945565b51902014612369565b6126cf604051918261190e6020820195866027917f5343484e4f525200000000000000000000000000000000000000000000000000825260078201520190565b5190206001600160a01b031690565b6001600160a01b031690565b612515565b6126fe81979397959495612069565b600581036127bb5750505061271c6127168351610aac565b83612012565b61273060209283808251830101910161225c565b600080955b825187146127b057612753600061274c8986611000565b51866123ff565b6127a7575b6126de6127a192610f646126cf61279b946040519283918c83019586906028926bffffffffffffffffffffffff19809260601b16835260601b1660148201520190565b96610f9c565b95612735565b60019250612758565b935094505050612515565b6127c88197949397612069565b6002810361288657505061282e91506127e4602184511161219a565b60206001600160a01b0381198551016128106128096126de6126de6126de858b612b49565b9187612012565b169360405180948192630b135d3f60e11b95868452600484016121fa565b0381865afa918215611735576126ea926001600160e01b031991600091612858575b501614612211565b612879915060203d811161287f575b6128718183610945565b8101906121e5565b38612850565b503d612867565b600391925061289481612069565b149081612980575b501561293b57600132148015612930575b6128b6906120e8565b6128c36021835114612133565b6128cc82611fbe565b602081604051806128f481906000606060808401938281528260208201528260408201520152565b838052039060015afa15611735576126ea91612921611b396001600160a01b036126de945116141561217e565b60208082518301019101612185565b5032611b39146128ad565b60405162461bcd60e51b815260206004820152600760248201527f53565f54595045000000000000000000000000000000000000000000000000006044820152606490fd5b90503861289c565b5061299281612069565b60018114612492565b956129a4611920565b612a71612a1782516020809401206129ba611959565b805190850120604080517fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac56472818801908152602081019490945290830191909152466060830152306080830152600060a083015291829060c0830190565b0391612a2b601f1993848101835282610945565b51902093612a65611e7a612a3d612089565b8051908701206040805180890192835230602084015290820194909452929182906060850190565b03848101835282610945565b51902095612483565b9750612a8582612069565b600582149761247c565b508051604103612aa0576000612457565b60405162461bcd60e51b815260206004820152600a60248201527f53565f5349474d4f4445000000000000000000000000000000000000000000006044820152606490fd5b6020815110612af5576020015190565b606460405162461bcd60e51b815260206004820152601060248201527f42797465734c69623a206c656e677468000000000000000000000000000000006044820152fd5b6040815110612af5576040015190565b9060208101808211610abb57825110612af55701602001519056fea264697066735822122035704f3ab926712d40be663bc2adadbeef93c1909174a5e2b473d4a4de58ab6564736f6c63430008130033
Deployed Bytecode
0x60806040526004361015610018575b361561001657005b005b60003560e01c806301ffc9a7146101185780630d5828d414610113578063150b7a021461010e5780631626ba7e1461010957806319822f7c146101045780633628d042146100ff5780636171d1c9146100fa5780636769de82146100f5578063a2ea6766146100f0578063abc5345e146100eb578063affed0e0146100e6578063bc197c81146100e1578063bf1cb383146100dc578063c066a5b1146100d7578063e6a6332e146100d25763f23a6e610361000e576107fc565b610790565b610769565b6106fc565b610653565b610616565b6105e1565b610561565b61053b565b6104bb565b6103c6565b61037b565b61032a565b6102d0565b610217565b610134565b6001600160e01b031981160361012f57565b600080fd5b3461012f57602036600319011261012f5760206001600160e01b031960043561015c8161011d565b167f01ffc9a70000000000000000000000000000000000000000000000000000000081149081156101f5575b81156101cb575b81156101a1575b506040519015158152f35b7f0a4176320000000000000000000000000000000000000000000000000000000091501438610196565b7f4e2312e0000000000000000000000000000000000000000000000000000000008114915061018f565b630a85bd0160e11b81149150610188565b6001600160a01b0381160361012f57565b604036600319011261012f5760043561022f81610206565b7f08ac40e0195c5998554e98853c23964a13a24309e127b2d016e8ec4adecf5e8360206001600160a01b036024359361026930331461086f565b1692836000527fcf2d407e18d78434343f77ac26e3f37aebbb1bffbd82f21ecba2a4839c706b7f825280604060002055604051908152a2005b9181601f8401121561012f5782359167ffffffffffffffff831161012f576020838186019501011161012f57565b3461012f57608036600319011261012f576102ec600435610206565b6102f7602435610206565b60643567ffffffffffffffff811161012f576103179036906004016102a2565b50506020604051630a85bd0160e11b8152f35b3461012f57604036600319011261012f5760243567ffffffffffffffff811161012f5761036961036060209236906004016102a2565b9060043561108e565b6001600160e01b031960405191168152f35b60031960603682011261012f576004359067ffffffffffffffff821161012f5761012090823603011261012f576103be60209160443590602435906004016112a3565b604051908152f35b608036600319011261012f576004356103de81610206565b6024359060443567ffffffffffffffff811161012f576104029036906004016102a2565b909161040f30331461086f565b5a92600080604051858482378086810183815203908886606435f1610441610435610983565b955a9060061c106109c9565b1561044857005b7f80c2637928bd94d0e1a90eaac1efc1553be6391d962fe5c82a01e90122c84ccc936001600160a01b039361048592604051958695169785610a7d565b0390a2005b9181601f8401121561012f5782359167ffffffffffffffff831161012f576020808501948460051b01011161012f57565b604036600319011261012f5767ffffffffffffffff60043581811161012f576104e890369060040161048a565b9060243592831161012f576105046100169336906004016102a2565b929091610dfe565b602060031982011261012f576004359067ffffffffffffffff821161012f576105379160040161048a565b9091565b61001661055c61054a3661050c565b61055530331461086f565b3691610cb8565b611014565b61056a3661050c565b60005b81810361057657005b610581818385610fab565b803590601e198136030182121561012f57019081359167ffffffffffffffff831161012f576020809101928060051b3603841361012f576105dc936105046105d7936105ce86898b610fab565b90810190610fcd565b610f9c565b61056d565b61060361055c6105f03661050c565b6105556105fc3361173a565b1515610c3a565b61001661060f3361173a565b1515610db3565b3461012f57600036600319011261012f5760207fcf2d407e18d78434343f77ac26e3f37aebbb1bffbd82f21ecba2a4839c706b8054604051908152f35b3461012f5760a036600319011261012f5761066f600435610206565b61067a602435610206565b67ffffffffffffffff60443581811161012f5761069b90369060040161048a565b505060643581811161012f576106b590369060040161048a565b505060843590811161012f576106cf9036906004016102a2565b50506040517fbc197c81000000000000000000000000000000000000000000000000000000008152602090f35b606036600319011261012f5760043561071481610206565b6024359060443567ffffffffffffffff811161012f576107389036906004016102a2565b909161074530331461086f565b5a9260008060405185848237808681018381520390888689f1610441610435610983565b3461012f57602036600319011261012f5760206103be60043561078b81610206565b61173a565b60031960203682011261012f5760043567ffffffffffffffff811161012f5760608160040192823603011261012f57610016916107ce30331461086f565b60246107f36107ec8335936107e285610206565b6044860190610fcd565b3691610c03565b9201359061106d565b3461012f5760a036600319011261012f57610818600435610206565b610823602435610206565b60843567ffffffffffffffff811161012f576108439036906004016102a2565b505060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b1561087657565b606460405162461bcd60e51b815260206004820152601560248201527f4f4e4c595f4143434f554e545f43414e5f43414c4c00000000000000000000006044820152fd5b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff8211176108ec57604052565b6108ba565b60c0810190811067ffffffffffffffff8211176108ec57604052565b6040810190811067ffffffffffffffff8211176108ec57604052565b60a0810190811067ffffffffffffffff8211176108ec57604052565b90601f8019910116810190811067ffffffffffffffff8211176108ec57604052565b67ffffffffffffffff81116108ec57601f01601f191660200190565b3d156109ae573d9061099482610967565b916109a26040519384610945565b82523d6000602084013e565b606090565b634e487b7160e01b600052601160045260246000fd5b156109d057565b606460405162461bcd60e51b815260206004820152600c60248201527f54525943415443485f4f4f4700000000000000000000000000000000000000006044820152fd5b908060209392818452848401376000828201840152601f01601f1916010190565b60005b838110610a485750506000910152565b8181015183820152602001610a38565b90602091610a7181518092818552858086019101610a35565b601f01601f1916010190565b9291610aa99492610a9b928552606060208601526060850191610a14565b916040818403910152610a58565b90565b600019810191908211610abb57565b6109b3565b9070014551231950b75fc4402da1732fc9bebe19918203918211610abb57565b634e487b7160e01b600052603260045260246000fd5b90821015610b02570190565b610ae0565b9060018201809211610abb57565b9491909460808101936001600160a01b0380971682526020928383015260409081830152836060956080878501525260a082019060a08560051b84010197876000945b878610610b6c575050505050505050505090565b90919293949596979899609f198282030186528a35605e198436030181121561012f578301848135610b9d81610206565b168252888101358983015285810135601e198236030181121561012f5701888101903567ffffffffffffffff811161012f57803603821361012f57610bef8a9283928e86818c60019901520191610a14565b9c0196019601949897969593929190610b58565b929192610c0f82610967565b91610c1d6040519384610945565b82948184528183011161012f578281602093846000960137010152565b15610c4157565b606460405162461bcd60e51b815260206004820152601660248201527f494e53554646494349454e545f50524956494c454745000000000000000000006044820152fd5b67ffffffffffffffff81116108ec5760051b60200190565b9080601f8301121561012f57816020610aa993359101610c03565b90929192610cc581610c85565b91604091610cd583519485610945565b839581855260208095019160051b83019381851161012f5783925b858410610d005750505050505050565b67ffffffffffffffff90843582811161012f5786019060608286031261012f578351610d2b816108d0565b8235610d3681610206565b8152898301358a8201528483013593841161012f57610d59868b95869501610c9d565b85820152815201930192610cf0565b15610d6f57565b606460405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f56414c49444154494f4e5f54494d454c4f434b0000006044820152fd5b15610dba57565b606460405162461bcd60e51b815260206004820152601860248201527f50524956494c4547455f4e4f545f444f574e47524144454400000000000000006044820152fd5b91929092610e47610e41610e1b610e1485610aac565b8585610af6565b357fff000000000000000000000000000000000000000000000000000000000000001690565b60f81c90565b60ff807fcf2d407e18d78434343f77ac26e3f37aebbb1bffbd82f21ecba2a4839c706b805492610e9d610e7985610b07565b7fcf2d407e18d78434343f77ac26e3f37aebbb1bffbd82f21ecba2a4839c706b8055565b1603610f2c575090610eb991610eb4368686610cb8565b611651565b9093919315610edb57509161078b61055c61060f93610ed9953691610cb8565b565b610ee790421015610d68565b60405162461bcd60e51b815260206004820152601960248201527f5349474e41545552455f56414c49444154494f4e5f4641494c000000000000006044820152606490fd5b83610f8960018795610f8361078b96610f7b61055c97610ed99c61060f9c6040516020810190610f7281610f64868689463089610b15565b03601f198101835282610945565b5190209261179e565b923691610c03565b906123ff565b5093610f976105fc8661173a565b610555565b6000198114610abb5760010190565b9190811015610b025760051b81013590603e198136030182121561012f570190565b903590601e198136030182121561012f570180359067ffffffffffffffff821161012f5760200191813603831361012f57565b8051821015610b025760209160051b010190565b80519060005b82811061102657505050565b8061103461104d9284611000565b516001600160a01b0381511680611052575b5050610f9c565b61101a565b81604060206110669401519101519161106d565b3880611046565b916000928392602083519301915af11561108357565b3d604051816000823efd5b600090610f836110a3936110aa953691610c03565b919061173a565b90600090156110d7575060ff60015b1610156110cb57630b135d3f60e11b90565b6001600160e01b031990565b60ff906110b9565b9060041161012f5790600490565b9060141161012f5790601490565b909291928360041161012f57831161012f57600401916003190190565b6001600160e01b0319903581811693926004811061113557505050565b60040360031b82901b16169150565b6bffffffffffffffffffffffff19903581811693926014811061116657505050565b60140360031b82901b16169150565b1561117c57565b608460405162461bcd60e51b815260206004820152603460248201527f76616c6964617465557365724f703a207061796d61737465722072657175697260448201527f656420696e20657865637574652829206d6f64650000000000000000000000006064820152fd5b949795929093611207610aa99a98956112159460c0895260c0890191610a14565b918683036020880152610a14565b9560408401526060830152608082015260a0818503910152610a14565b1561123957565b608460405162461bcd60e51b815260206004820152602360248201527f76616c6964617465557365724f703a206e6f742066726f6d20656e747279506f60448201527f696e7400000000000000000000000000000000000000000000000000000000006064820152fd5b916060830160046112b48286610fcd565b9050101580611418575b611333575061130b92610f836107ec6112f9611305956001956112ec6171716112e63361173a565b14611232565b8061131a575b5084611d5c565b92610100810190610fcd565b5061173a565b1561131557600090565b600190565b600080808093335af15061132c610983565b50386112f2565b915050611344610100830183610fcd565b9050611411576113cb60209160e084019060346113618387610fcd565b90501015806113d8575b61137490611175565b6113c261139f610f6461139661138d60408a018a610fcd565b9190958a610fcd565b9390968a610fcd565b918a6040519788968c88019a60c084013594608060a0860135950135938d6111e6565b51902060401b90565b9101350361131557600090565b506113746114076113f26113ec8589610fcd565b906110ed565b6bffffffffffffffffffffffff199291611144565b161515905061136b565b5050600190565b507fa2ea6766000000000000000000000000000000000000000000000000000000006001600160e01b031961145f6114596114538589610fcd565b906110df565b90611118565b16146112be565b81601f8201121561012f57805161147c81610967565b9261148a6040519485610945565b8184526020828401011161012f57610aa99160208085019101610a35565b9060808282031261012f5781516114be81610206565b9260208301516114cd81610206565b9260408101519267ffffffffffffffff9384811161012f57816114f1918401611466565b93606083015190811161012f57610aa99201611466565b6040906001600160a01b03610aa994931681528160208201520190610a58565b1561152f57565b606460405162461bcd60e51b815260206004820152601b60248201527f45585445524e414c5f56414c49444154494f4e5f4e4f545f53455400000000006044820152fd5b919082604091031261012f578151801515810361012f5760209092015190565b906115b86115a960609283855283850190610a58565b60209484820386860152610a58565b926040928381860391015284519182855281850182808560051b8801019701946000925b8584106115ee57505050505050505090565b90919293949596989785806116316001938d601f1990820301885285878d516001600160a01b038151168452858101518685015201519181898201520190610a58565b9a9b990197969591909101930191906115dc565b6040513d6000823e3d90fd5b60409061168161167161166c6116f395600098973691610c03565b611f8d565b50602080825183010191016114a8565b916001600160a01b039891988091169316976116be61169f8a61173a565b875160208101906116b581610f64878b86611508565b51902014611528565b8551968795869485937ffcfbba4d00000000000000000000000000000000000000000000000000000000855260048501611593565b03925af1801561173557600091829161170b57509091565b9050610537915060403d811161172e575b6117268183610945565b810190611573565b503d61171c565b611645565b6001600160a01b0316308114611798576f71727de22e5e9d8baf0edac6f37da0328114611791576000527fcf2d407e18d78434343f77ac26e3f37aebbb1bffbd82f21ecba2a4839c706b7f60205260406000205490565b5061717190565b50600290565b9261190e9261191a92946118d06118986118936117b9611992565b9860966040516117c8816108f1565b8181527f743235362076616c75652c62797465732064617461290000000000000000000060a060208301927f416d62697265457865637574654163636f756e744f702861646472657373206184527f63636f756e742c75696e7432353620636861696e49642c75696e74323536206e60408201527f6f6e63652c5472616e73616374696f6e5b5d2063616c6c732c6279746573333260608201527f2068617368295472616e73616374696f6e286164647265737320746f2c75696e6080820152015220953691610cb8565b611a39565b60408051602081019586523091810191909152466060820152608081019390935260a083015260c082019390935291829060e0820190565b03916118e4601f1993848101835282610945565b519020604051938491602083019687909160429261190160f01b8352600283015260228201520190565b03908101835282610945565b51902090565b6040519061192d8261090d565b600682527f416d6269726500000000000000000000000000000000000000000000000000006020830152565b604051906119668261090d565b600182527f31000000000000000000000000000000000000000000000000000000000000006020830152565b61199a611920565b60208151910120610f6461191a6119af611959565b8051602091820120604080517fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac564729381019384529081019590955260608501524660808501523060a0850152600060c08501529291829060e0820190565b805160208092019160005b828110611a25575050505090565b835185529381019392810192600101611a17565b611a66908051611a4881610c85565b91604091611a5883519485610945565b808452601f19948591610c85565b0194602095368786013760005b8251811015611b405780611a8a611b3b9285611000565b518551611a96816108d0565b6030908181527f616c75652c627974657320646174612900000000000000000000000000000000888c8301927f5472616e73616374696f6e286164647265737320746f2c75696e7432353620768452015220906001600160a01b0381511690878b8201519101518b8151910120908851928c8401948552898401526060830152608090818301528152611b2881610929565b519020611b358288611000565b52610f9c565b611a73565b509461190e9394915061191a925193849182018096611a0c565b9080601f8301121561012f57816020610aa993359101610cb8565b91909160408184031261012f5767ffffffffffffffff92813584811161012f5781611ba1918401611b5a565b93602083013590811161012f57610aa99201610c9d565b9060208282031261012f57813567ffffffffffffffff811161012f57610aa99201611b5a565b60405190610140820182811067ffffffffffffffff8211176108ec5760405261010c82527f2c62797465732064617461290000000000000000000000000000000000000000610120837f416d62697265343333374163636f756e744f702861646472657373206163636f60208201527f756e742c75696e7432353620636861696e49642c75696e74323536206e6f6e6360408201527f652c627974657320696e6974436f64652c62797465733332206163636f756e7460608201527f4761734c696d6974732c75696e7432353620707265566572696669636174696f60808201527f6e4761732c6279746573333220676173466565732c6279746573207061796d6160a08201527f73746572416e64446174612c62797465732063616c6c446174612c5472616e7360c08201527f616374696f6e5b5d2063616c6c732c627974657333322068617368295472616e60e08201527f73616374696f6e286164647265737320746f2c75696e743235362076616c75656101008201520152565b906060808301916004611d6f8486610fcd565b90501015611ea6575b61191a9192611d85611992565b94611e66611d91611bde565b93845196602097888097012090611dae6107ec6040870187610fcd565b87815191012095611de7611ddb6107ec611dce6107ec60e08b018b610fcd565b8b81519101209389610fcd565b89815191012092611a39565b926040519889978189019960c08201359360a0830135936080840135930135908c469130919895926001600160a01b036101609b9895929e9d9c9996936101808c019f8c521660208b015260408a01526060890152608088015260a087015260c086015260e08501526101008401526101208301526101408201520152565b0391611e7a601f1993848101835282610945565b5190209261190e60405194859283019687909160429261190160f01b8352600283015260228201520190565b6001600160e01b0319611ebf6114596114538688610fcd565b167fabc5345e000000000000000000000000000000000000000000000000000000008103611f16575061191a9150611f0c611f04611efd8587610fcd565b80916110fb565b810190611bb8565b925b929150611d78565b7f6171d1c90000000000000000000000000000000000000000000000000000000014611f47575b61191a9192611f0e565b61191a9150611f64611f5c611efd8587610fcd565b810190611b75565b509150611f3d565b805160401015610b025760600190565b908151811015610b02570160200190565b9060001991611f9f8382510182611f7c565b5160f81c928151908101908111610abb57611fba9082612012565b9190565b602081511115611fce5760209052565b606460405162461bcd60e51b815260206004820152601860248201527f42797465734c69623a206f6e6c7920736872696e6b696e6700000000000000006044820152fd5b8181511115611fce5752565b1561202557565b606460405162461bcd60e51b815260206004820152600960248201527f53565f5349474c454e00000000000000000000000000000000000000000000006044820152fd5b6007111561207357565b634e487b7160e01b600052602160045260246000fd5b60405190612096826108d0565b602d82527f62797465733332206861736829000000000000000000000000000000000000006040837f416d626972654f7065726174696f6e2861646472657373206163636f756e742c60208201520152565b156120ef57565b606460405162461bcd60e51b815260206004820152600f60248201527f53565f53504f4f465f4f524947494e00000000000000000000000000000000006044820152fd5b1561213a57565b606460405162461bcd60e51b815260206004820152600c60248201527f53565f53504f4f465f4c454e00000000000000000000000000000000000000006044820152fd5b1561012f57565b9081602091031261012f5751610aa981610206565b156121a157565b606460405162461bcd60e51b815260206004820152600d60248201527f53565f4c454e5f57414c4c4554000000000000000000000000000000000000006044820152fd5b9081602091031261012f5751610aa98161011d565b604090610aa9939281528160208201520190610a58565b1561221857565b606460405162461bcd60e51b815260206004820152601160248201527f53565f57414c4c45545f494e56414c49440000000000000000000000000000006044820152fd5b90602090818382031261012f57825167ffffffffffffffff9384821161012f570181601f8201121561012f57805161229381610c85565b946122a16040519687610945565b818652848087019260051b8401019380851161012f57858401925b8584106122cd575050505050505090565b835183811161012f5787916122e7848480948a0101611466565b8152019301926122bc565b919082608091031261012f578151916020810151916060604083015192015160ff8116810361012f5790565b1561232557565b606460405162461bcd60e51b815260206004820152600b60248201527f53565f5a45524f5f5349470000000000000000000000000000000000000000006044820152fd5b1561237057565b606460405162461bcd60e51b815260206004820152601160248201527f53565f5343484e4f52525f4641494c45440000000000000000000000000000006044820152fd5b156123bb57565b606460405162461bcd60e51b815260206004820152600660248201527f53565f4c454e00000000000000000000000000000000000000000000000000006044820152fd5b9092919261240f8151151561201e565b61244a610e4161242460001984510184611f7c565b517fff000000000000000000000000000000000000000000000000000000000000001690565b600660ff82161015612a8f575b60ff169361246485612069565b60009061247086612069565b85159586158781612a7a575b881561299b575b61248c83612069565b90612988575b1561253457505050806020926124b76000935160418114908115612529575b506123b4565b6125036124c383612ae5565b926124dc610e416124246124d684612b39565b93611f6c565b93604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15611735576000515b611fba6001600160a01b038216151561231e565b6042915014386124b1565b61253d81612069565b600481036126ef5750505061259c6125dc9260206125788461256a61256460009751610aac565b82612012565b8280825183010191016122f2565b978396899398949270014551231950b75fc4402da1732fc9bebe1993849109610ac0565b916125b56125ac828a8c09610ac0565b9184141561217e565b87604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa156117355761268f6126de9383926126ea96612672600051926126126001600160a01b038516151561231e565b6040519687936020850195869290605594927fff00000000000000000000000000000000000000000000000000000000000000916bffffffffffffffffffffffff199060601b16855260f81b166014840152601583015260358201520190565b0393612686601f1995868101835282610945565b51902014612369565b6126cf604051918261190e6020820195866027917f5343484e4f525200000000000000000000000000000000000000000000000000825260078201520190565b5190206001600160a01b031690565b6001600160a01b031690565b612515565b6126fe81979397959495612069565b600581036127bb5750505061271c6127168351610aac565b83612012565b61273060209283808251830101910161225c565b600080955b825187146127b057612753600061274c8986611000565b51866123ff565b6127a7575b6126de6127a192610f646126cf61279b946040519283918c83019586906028926bffffffffffffffffffffffff19809260601b16835260601b1660148201520190565b96610f9c565b95612735565b60019250612758565b935094505050612515565b6127c88197949397612069565b6002810361288657505061282e91506127e4602184511161219a565b60206001600160a01b0381198551016128106128096126de6126de6126de858b612b49565b9187612012565b169360405180948192630b135d3f60e11b95868452600484016121fa565b0381865afa918215611735576126ea926001600160e01b031991600091612858575b501614612211565b612879915060203d811161287f575b6128718183610945565b8101906121e5565b38612850565b503d612867565b600391925061289481612069565b149081612980575b501561293b57600132148015612930575b6128b6906120e8565b6128c36021835114612133565b6128cc82611fbe565b602081604051806128f481906000606060808401938281528260208201528260408201520152565b838052039060015afa15611735576126ea91612921611b396001600160a01b036126de945116141561217e565b60208082518301019101612185565b5032611b39146128ad565b60405162461bcd60e51b815260206004820152600760248201527f53565f54595045000000000000000000000000000000000000000000000000006044820152606490fd5b90503861289c565b5061299281612069565b60018114612492565b956129a4611920565b612a71612a1782516020809401206129ba611959565b805190850120604080517fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac56472818801908152602081019490945290830191909152466060830152306080830152600060a083015291829060c0830190565b0391612a2b601f1993848101835282610945565b51902093612a65611e7a612a3d612089565b8051908701206040805180890192835230602084015290820194909452929182906060850190565b03848101835282610945565b51902095612483565b9750612a8582612069565b600582149761247c565b508051604103612aa0576000612457565b60405162461bcd60e51b815260206004820152600a60248201527f53565f5349474d4f4445000000000000000000000000000000000000000000006044820152606490fd5b6020815110612af5576020015190565b606460405162461bcd60e51b815260206004820152601060248201527f42797465734c69623a206c656e677468000000000000000000000000000000006044820152fd5b6040815110612af5576040015190565b9060208101808211610abb57825110612af55701602001519056fea264697066735822122035704f3ab926712d40be663bc2adadbeef93c1909174a5e2b473d4a4de58ab6564736f6c63430008130033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.