Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60808060 | 20087646 | 638 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
AmbireAccount
Compiler Version
v0.8.19+commit.7dd6d404
Contract Source Code (Solidity Standard Json-Input format)
// 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';
/**
* @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)
address private constant FALLBACK_HANDLER_SLOT = address(0x6969);
// @dev This is how we understand if msg.sender is the entry point
bytes32 private constant ENTRY_POINT_MARKER = 0x0000000000000000000000000000000000000000000000000000000000007171;
// Externally validated signatures
uint8 private constant SIGMODE_EXTERNALLY_VALIDATED = 255;
// Variables
mapping(address => bytes32) public privileges;
uint256 public nonce;
// 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 fallback method: currently used to call the fallback handler
* which is set by the user and can be changed
* @dev this contract can accept ETH with calldata, hence payable
*/
fallback() external payable {
// We store the fallback handler at this magic slot
address fallbackHandler = address(uint160(uint(privileges[FALLBACK_HANDLER_SLOT])));
if (fallbackHandler == address(0)) return;
assembly {
// we can use addr 0 because logic is taking full control of the
// execution making sure it returns itself and does not
// rely on any further Solidity code.
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), fallbackHandler, 0, calldatasize(), 0, 0)
let size := returndatasize()
returndatacopy(0, 0, size)
if eq(result, 0) {
revert(0, size)
}
return(0, size)
}
}
/**
* @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');
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 = nonce;
// we increment the nonce here (not using `nonce++` to save some gas)
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.recoverAddr(
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 view 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
if (supported) return true;
address payable fallbackHandler = payable(address(uint160(uint256(privileges[FALLBACK_HANDLER_SLOT]))));
if (fallbackHandler == address(0)) return false;
return AmbireAccount(fallbackHandler).supportsInterface(interfaceID);
}
//
// 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.recoverAddr(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.19;
import './deployless/IAmbireAccount.sol';
import './libs/Transaction.sol';
/**
* @notice A contract used for deploying AmbireAccount.sol
* @dev We use create2 to get the AmbireAccount address. It's deterministic:
* if the same data is passed to it, the same address will pop out.
*/
contract AmbireFactory {
event LogDeployed(address addr, uint256 salt);
address public immutable allowedToDrain;
constructor(address allowed) {
allowedToDrain = allowed;
}
/**
* @notice Allows anyone to deploy any contracft with a specific code/salt
* @dev This is safe because it's CREATE2 deployment
* @param code the code to be deployed
* @param salt the salt to shuffle the computed address
* @return address the deployed address
*/
function deploy(bytes calldata code, uint256 salt) external returns(address) {
return deploySafe(code, salt);
}
/**
* @notice Call this when you want to deploy the contract and execute calls
* @dev When the relayer needs to act upon an /identity/:addr/submit call, it'll either call execute on the AmbireAccount directly
* if it's already deployed, or call `deployAndExecute` if the account is still counterfactual
* we can't have deployAndExecuteBySender, because the sender will be the factory
* @param code the code to be deployed
* @param salt the salt to shuffle the computed address
* @param txns the txns the are going to be executed
* @param signature the signature for the txns
* @return address the deployed address
*/
function deployAndExecute(
bytes calldata code,
uint256 salt,
Transaction[] calldata txns,
bytes calldata signature
) external returns (address){
address payable addr = payable(deploySafe(code, salt));
IAmbireAccount(addr).execute(txns, signature);
return addr;
}
/**
* @notice Call this when you want to deploy the contract and call executeMultiple
* @dev when the relayer needs to act upon an /identity/:addr/submit call,
* it'll either call execute on the AmbireAccount directly. If it's already
* deployed, or call `deployAndExecuteMultiple` if the account is still
* counterfactual but there are multiple accountOps to send
* @param code the code to be deployed
* @param salt the salt to shuffle the computed address
* @param toExec [txns, signature] execute parameters
* @return address the deployed address
*/
function deployAndExecuteMultiple(
bytes calldata code,
uint256 salt,
IAmbireAccount.ExecuteArgs[] calldata toExec
) external returns (address){
address payable addr = payable(deploySafe(code, salt));
IAmbireAccount(addr).executeMultiple(toExec);
return addr;
}
/**
* @notice This method can be used to withdraw stuck tokens or airdrops
* @dev Only allowedToDrain can do the call
* @param to receiver
* @param value how much to be sent
* @param data if a token has airdropped, code to send it
* @param gas maximum gas willing to spend
*/
function call(address to, uint256 value, bytes calldata data, uint256 gas) external {
require(msg.sender == allowedToDrain, 'ONLY_AUTHORIZED');
(bool success, bytes memory err) = to.call{ gas: gas, value: value }(data);
require(success, string(err));
}
/**
* @dev This is done to mitigate possible frontruns where, for example,
* where deploying the same code/salt via deploy() would make a pending
* deployAndExecute fail. The way we mitigate that is by checking if the
* contract is already deployed and if so, we continue execution
* @param code the code to be deployed
* @param salt the salt to shuffle the computed address
* @return address the deployed address
*/
function deploySafe(bytes memory code, uint256 salt) internal returns (address) {
address expectedAddr = address(
uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), salt, keccak256(code)))))
);
uint256 size;
assembly {
size := extcodesize(expectedAddr)
}
// If there is code at that address, we can assume it's the one we were about to deploy,
// because of how CREATE2 and keccak256 works
if (size == 0) {
address addr;
assembly {
addr := create2(0, add(code, 0x20), mload(code), salt)
}
require(addr != address(0), 'FAILED_DEPLOYING');
require(addr == expectedAddr, 'FAILED_MATCH');
emit LogDeployed(addr, salt);
}
return expectedAddr;
}
}// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.8.19;
import './deployless/IAmbireAccount.sol';
import './libs/erc4337/IPaymaster.sol';
import './libs/SignatureValidator.sol';
import './libs/erc4337/UserOpHelper.sol';
contract AmbirePaymaster is IPaymaster {
address immutable public relayer;
constructor(address _relayer) {
relayer = _relayer;
}
/**
* @notice This method can be used to withdraw stuck tokens or airdrops
*
* @param to The address we're calling
* @param value The value in the call
* @param data the call data
* @param gas the call gas
*/
function call(address to, uint256 value, bytes calldata data, uint256 gas) external payable {
require(msg.sender == relayer, 'call: not relayer');
(bool success, bytes memory err) = to.call{ gas: gas, value: value }(data);
require(success, string(err));
}
/**
* @notice Validate user operations the paymaster has signed
* We do not need to send funds to the EntryPoint because we rely on pre-existing deposit.
* Requests are chain specific to prevent signature reuse.
* @dev We have two use cases for the paymaster:
* - normal erc-4337. Everything is per ERC-4337 standard, the nonce is sequential.
* - an executeMultiple call. If the calldata is executeMultiple, we've hardcoded
* a 0 nonce. That's what's called a one-time hash nonce and its key is actually
* the commitment. Check EntryPoint -> NonceManager for more information.
*
* @param userOp the UserOperation we're executing
* @return context context is returned in the postOp and called by the
* EntryPoint. But we're not using postOp is context is always emtpy
* @return validationData This consists of:
* - an aggregator address: address(uint160(validationData)). This is used
* when you want an outer contract to determine whether the signature is valid.
* In our case, this is always 0 (address 0) for valid signatures and
* 1 (address 1) for invalid. This is what the entry point expects and
* in those two cases, an outer contract is obviously not called.
* - a uint48 validUntil: uint48(validationData >> 160)
* A Paymaster signature can be signed at time "x" but delayed intentionally
* until time "y" when a fee payment's price has dropped significantly or
* some other issue. validUntil sets a time validity for the signature
* - a uint48 validAfter: uint48(validationData >> (48 + 160))
* If the signature should be valid only after a period of time,
* we tweak the validAfter property.
* For more information, check EntryPoint -> _getValidationData()
*/
function validatePaymasterUserOp(PackedUserOperation calldata userOp, bytes32, uint256)
external
view
returns (bytes memory context, uint256 validationData)
{
(uint48 validUntil, uint48 validAfter, bytes memory signature) = abi.decode(
userOp.paymasterAndData[UserOpHelper.PAYMASTER_DATA_OFFSET:],
(uint48, uint48, bytes)
);
bytes memory callData = userOp.callData;
bytes32 hash = keccak256(abi.encode(
block.chainid,
address(this),
// entry point
msg.sender,
validUntil,
validAfter,
// everything except paymasterAndData and signature
userOp.sender,
// for the nonce we have an exception case: one-time nonces depend on paymasterAndData, which is generated by the relayer
// we can't have this as part of the sig cuz we create a cyclical dep
// the nonce can only be used once, so one cannot replay the gas payment
callData.length >= 4 && bytes4(userOp.callData[0:4]) == IAmbireAccount.executeMultiple.selector ? 0 : userOp.nonce,
userOp.initCode,
callData,
userOp.accountGasLimits,
userOp.preVerificationGas,
userOp.gasFees
));
(address recovered, ) = SignatureValidator.recoverAddrAllowUnprotected(hash, signature, true);
bool isValidSig = recovered == relayer;
// see _packValidationData: https://github.com/eth-infinitism/account-abstraction/blob/f2b09e60a92d5b3177c68d9f382912ccac19e8db/contracts/core/Helpers.sol#L73-L80
return ("", uint160(isValidSig ? 0 : 1) | (uint256(validUntil) << 160) | (uint256(validAfter) << 208));
}
/**
* @notice No-op, won't be used because we don't return a context
* @param mode .
* @param context .
* @param actualGasCost .
*/
function postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) external {
// No-op, won't be used because we don't return a context
}
}// 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.7;
import '../libs/Transaction.sol';
interface IAmbireAccount {
function privileges(address addr) external returns (bytes32);
function nonce() external returns (uint);
struct RecoveryInfo {
address[] keys;
uint timelock;
}
struct ExecuteArgs {
Transaction[] calls;
bytes signature;
}
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;
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 './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)) {
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;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.12;
import "./PackedUserOperation.sol";
/**
* the interface exposed by a paymaster contract, who agrees to pay the gas for user's operations.
* a paymaster must hold a stake to cover the required entrypoint stake and also the gas for the transaction.
*/
interface IPaymaster {
enum PostOpMode {
opSucceeded, // user op succeeded
opReverted, // user op reverted. still has to pay for gas.
postOpReverted //user op succeeded, but caused postOp to revert. Now it's a 2nd call, after user's op was deliberately reverted.
}
/**
* payment validation: check if paymaster agrees to pay.
* Must verify sender is the entryPoint.
* Revert to reject this request.
* Note that bundlers will reject this method if it changes the state, unless the paymaster is trusted (whitelisted)
* The paymaster pre-pays using its deposit, and receive back a refund after the postOp method returns.
* @param userOp the user operation
* @param userOpHash hash of the user's request data.
* @param maxCost the maximum cost of this transaction (based on maximum gas and gas price from userOp)
* @return context value to send to a postOp
* zero length to signify postOp is not required.
* @return validationData signature and time-range of this operation, encoded the same as the return value of validateUserOperation
* <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure,
* otherwise, an address of an "authorizer" contract.
* <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite"
* <6-byte> validAfter - first timestamp this operation is valid
* Note that the validation code cannot use block.timestamp (or block.number) directly.
*/
function validatePaymasterUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost)
external returns (bytes memory context, uint256 validationData);
/**
* post-operation handler.
* Must verify sender is the entryPoint
* @param mode enum with the following options:
* opSucceeded - user operation succeeded.
* opReverted - user op reverted. still has to pay for gas.
* postOpReverted - user op succeeded, but caused postOp (in mode=opSucceeded) to revert.
* Now this is the 2nd call, after user's op was deliberately reverted.
* @param context - the context value returned by validatePaymasterUserOp
* @param actualGasCost - actual gas used so far (without this postOp call).
*/
function postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) external;
}// 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;
}{
"remappings": [
"forge-std/=lib/forge-std/src/"
],
"optimizer": {
"enabled": true,
"runs": 1000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": true,
"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":"","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":"view","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
6080806040523461001657612550908161001c8239f35b600080fdfe6080604052600436101561001e575b361561001c5761001c6107bb565b005b60003560e01c806301ffc9a71461011e5780630d5828d414610119578063150b7a02146101145780631626ba7e1461010f57806319822f7c1461010a5780633628d042146101055780636171d1c9146101005780636769de82146100fb578063a2ea6766146100f6578063abc5345e146100f1578063affed0e0146100ec578063bc197c81146100e7578063bf1cb383146100e2578063c066a5b1146100dd578063e6a6332e146100d85763f23a6e610361000e57610748565b6106dc565b61069e565b610631565b610588565b61056a565b610527565b6104a7565b610481565b610401565b61030c565b6102c1565b610270565b610216565b61017c565b61013a565b6001600160e01b031981160361013557565b600080fd5b3461013557602036600319011261013557602061016160043561015c81610123565b61105b565b6040519015158152f35b6001600160a01b0381160361013557565b6040366003190112610135576004356101948161016b565b7f08ac40e0195c5998554e98853c23964a13a24309e127b2d016e8ec4adecf5e8360206001600160a01b03602435936101ce3033146107fe565b1692836000526000825280604060002055604051908152a2005b9181601f840112156101355782359167ffffffffffffffff8311610135576020838186019501011161013557565b346101355760803660031901126101355761023260043561016b565b61023d60243561016b565b60643567ffffffffffffffff81116101355761025d9036906004016101e8565b50506020604051630a85bd0160e11b8152f35b346101355760403660031901126101355760243567ffffffffffffffff8111610135576102af6102a660209236906004016101e8565b90600435610fcb565b6001600160e01b031960405191168152f35b600319606036820112610135576004359067ffffffffffffffff82116101355761012090823603011261013557610304602091604435906024359060040161137d565b604051908152f35b6080366003190112610135576004356103248161016b565b6024359060443567ffffffffffffffff8111610135576103489036906004016101e8565b90916103553033146107fe565b5a92600080604051858482378086810183815203908886606435f161038761037b6108da565b955a9060061c10610920565b1561038e57005b7f80c2637928bd94d0e1a90eaac1efc1553be6391d962fe5c82a01e90122c84ccc936001600160a01b03936103cb926040519586951697856109d4565b0390a2005b9181601f840112156101355782359167ffffffffffffffff8311610135576020808501948460051b01011161013557565b60403660031901126101355767ffffffffffffffff6004358181116101355761042e9036906004016103d0565b906024359283116101355761044a61001c9336906004016101e8565b929091610d4b565b6020600319820112610135576004359067ffffffffffffffff82116101355761047d916004016103d0565b9091565b61001c6104a261049036610452565b61049b3033146107fe565b3691610bf4565b610f51565b6104b036610452565b60005b8181036104bc57005b6104c7818385610ee8565b803590601e198136030182121561013557019081359167ffffffffffffffff8311610135576020809101928060051b36038413610135576105229361044a61051d9361051486898b610ee8565b90810190610f0a565b610ed9565b6104b3565b6104a261055161053636610452565b92906000933385528460205261049b60408620541515610b91565b3381528060205261056760408220541515610d00565b80f35b34610135576000366003190112610135576020600154604051908152f35b346101355760a0366003190112610135576105a460043561016b565b6105af60243561016b565b67ffffffffffffffff604435818111610135576105d09036906004016103d0565b5050606435818111610135576105ea9036906004016103d0565b5050608435908111610135576106049036906004016101e8565b50506040517fbc197c81000000000000000000000000000000000000000000000000000000008152602090f35b6060366003190112610135576004356106498161016b565b6024359060443567ffffffffffffffff81116101355761066d9036906004016101e8565b909161067a3033146107fe565b5a9260008060405185848237808681018381520390888689f161038761037b6108da565b34610135576020366003190112610135576001600160a01b036004356106c38161016b565b1660005260006020526020604060002054604051908152f35b6003196020368201126101355760043567ffffffffffffffff8111610135576060816004019282360301126101355761001c9161071a3033146107fe565b602461073f61073883359361072e8561016b565b6044860190610f0a565b3691610b5a565b92013590610faa565b346101355760a03660031901126101355761076460043561016b565b61076f60243561016b565b60843567ffffffffffffffff81116101355761078f9036906004016101e8565b505060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b6000906169698252816020526001600160a01b036040832054169081156107f95750818091368280378136915af4903d918282803e156107f757f35bfd5b915050565b1561080557565b606460405162461bcd60e51b815260206004820152601560248201527f4f4e4c595f4143434f554e545f43414e5f43414c4c00000000000000000000006044820152fd5b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff82111761087b57604052565b610849565b6040810190811067ffffffffffffffff82111761087b57604052565b90601f8019910116810190811067ffffffffffffffff82111761087b57604052565b67ffffffffffffffff811161087b57601f01601f191660200190565b3d15610905573d906108eb826108be565b916108f9604051938461089c565b82523d6000602084013e565b606090565b634e487b7160e01b600052601160045260246000fd5b1561092757565b606460405162461bcd60e51b815260206004820152600c60248201527f54525943415443485f4f4f4700000000000000000000000000000000000000006044820152fd5b908060209392818452848401376000828201840152601f01601f1916010190565b60005b83811061099f5750506000910152565b818101518382015260200161098f565b906020916109c88151809281855285808601910161098c565b601f01601f1916010190565b9291610a0094926109f292855260606020860152606085019161096b565b9160408184039101526109af565b90565b600019810191908211610a1257565b61090a565b9070014551231950b75fc4402da1732fc9bebe19918203918211610a1257565b634e487b7160e01b600052603260045260246000fd5b90821015610a59570190565b610a37565b9060018201809211610a1257565b9491909460808101936001600160a01b0380971682526020928383015260409081830152836060956080878501525260a082019060a08560051b84010197876000945b878610610ac3575050505050505050505090565b90919293949596979899609f198282030186528a35605e1984360301811215610135578301848135610af48161016b565b168252888101358983015285810135601e19823603018112156101355701888101903567ffffffffffffffff811161013557803603821361013557610b468a9283928e86818c6001990152019161096b565b9c0196019601949897969593929190610aaf565b929192610b66826108be565b91610b74604051938461089c565b829481845281830111610135578281602093846000960137010152565b15610b9857565b606460405162461bcd60e51b815260206004820152601660248201527f494e53554646494349454e545f50524956494c454745000000000000000000006044820152fd5b67ffffffffffffffff811161087b5760051b60200190565b929190610c0081610bdc565b91604091610c108351948561089c565b839581855260208095019160051b8101938385116101355781925b858410610c3b5750505050505050565b67ffffffffffffffff9084358281116101355784019160608388031261013557835192610c678461085f565b8035610c728161016b565b8452898101358a8501528481013591821161013557019086601f83011215610135578892610ca68884868096359101610b5a565b85820152815201930192610c2b565b15610cbc57565b606460405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f56414c49444154494f4e5f54494d454c4f434b0000006044820152fd5b15610d0757565b606460405162461bcd60e51b815260206004820152601860248201527f50524956494c4547455f4e4f545f444f574e47524144454400000000000000006044820152fd5b91929092610d94610d8e610d68610d6185610a03565b8585610a4d565b357fff000000000000000000000000000000000000000000000000000000000000001690565b60f81c90565b60ff8060015492610dac610da785610a5e565b600155565b1603610e5c575090610dc891610dc3368686610bf4565b611719565b9093919315610e0b575091610de86104a2610e0193610e09953691610bf4565b6001600160a01b03166000526000602052604060002090565b541515610d00565b565b610e1790421015610cb5565b60405162461bcd60e51b815260206004820152601960248201527f5349474e41545552455f56414c49444154494f4e5f4641494c000000000000006044820152606490fd5b610e0193610eab610e099694610ea5610de8956104a295604051610e9a81610e8c8c8a6020840196463089610a6c565b03601f19810183528261089c565b519020923691610b5a565b906118c4565b93610ed4610ecc866001600160a01b03166000526000602052604060002090565b541515610b91565b61049b565b6000198114610a125760010190565b9190811015610a595760051b81013590603e1981360301821215610135570190565b903590601e1981360301821215610135570180359067ffffffffffffffff82116101355760200191813603831361013557565b8051821015610a595760209160051b010190565b80519060005b828110610f6357505050565b80610f71610f8a9284610f3d565b516001600160a01b0381511680610f8f575b5050610ed9565b610f57565b8160406020610fa394015191015191610faa565b3880610f83565b916000928392602083519301915af115610fc057565b3d604051816000823efd5b6001600160a01b0392610fed91610fe760009485933691610b5a565b90611d6e565b9216815280602052604081205491600014611026575060ff60015b16101561101a57630b135d3f60e11b90565b6001600160e01b031990565b60ff90611008565b5190811515820361013557565b9081602091031261013557610a009061102e565b6040513d6000823e3d90fd5b7f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b031982168181149081156111c5575b811561119b575b8115611171575b5061116a5761696960009081526020526001600160a01b036110f96110ed807f662a30f03e82d96c1f4d254ac3d297ac2d115f4d7e55a040fee317b77fa274e7546001600160a01b031690565b6001600160a01b031690565b16918215611162576040519182526001600160e01b031916600482015290602090829060249082905afa90811561115d57600091611135575090565b610a00915060203d8111611156575b61114e818361089c565b81019061103b565b503d611144565b61104f565b505050600090565b5050600190565b7f0a41763200000000000000000000000000000000000000000000000000000000915014386110a0565b7f4e2312e00000000000000000000000000000000000000000000000000000000081149150611099565b630a85bd0160e11b81149150611092565b906004116101355790600490565b906014116101355790601490565b6001600160e01b0319903581811693926004811061120f57505050565b60040360031b82901b16169150565b6bffffffffffffffffffffffff19903581811693926014811061124057505050565b60140360031b82901b16169150565b1561125657565b608460405162461bcd60e51b815260206004820152603460248201527f76616c6964617465557365724f703a207061796d61737465722072657175697260448201527f656420696e20657865637574652829206d6f64650000000000000000000000006064820152fd5b9497959290936112e1610a009a98956112ef9460c0895260c089019161096b565b91868303602088015261096b565b9560408401526060830152608082015260a081850391015261096b565b1561131357565b608460405162461bcd60e51b815260206004820152602360248201527f76616c6964617465557365724f703a206e6f742066726f6d20656e747279506f60448201527f696e7400000000000000000000000000000000000000000000000000000000006064820152fd5b9160608301600461138e8286610f0a565b90501015806114ef575b611411575090610ea56107386113e894610de8946113d66171716113cf336001600160a01b03166000526000602052604060002090565b541461130c565b806113f8575b50610100810190610f0a565b54156113f357600090565b600190565b600080808093335af15061140a6108da565b50386113dc565b915050611422610100830183610f0a565b905061116a576114a960209160e0840190603461143f8387610f0a565b90501015806114b6575b6114529061124f565b6114a061147d610e8c61147461146b60408a018a610f0a565b9190958a610f0a565b9390968a610f0a565b918a6040519788968c88019a60c084013594608060a0860135950135938d6112c0565b51902060401b90565b910135036113f357600090565b506114526114e56114d06114ca8589610f0a565b906111e4565b6bffffffffffffffffffffffff19929161121e565b1615159050611449565b507fa2ea6766000000000000000000000000000000000000000000000000000000006001600160e01b031961153661153061152a8589610f0a565b906111d6565b906111f2565b1614611398565b81601f82011215610135578051611553816108be565b92611561604051948561089c565b8184526020828401011161013557610a00916020808501910161098c565b906080828203126101355781516115958161016b565b9260208301516115a48161016b565b9260408101519267ffffffffffffffff9384811161013557816115c891840161153d565b93606083015190811161013557610a00920161153d565b6040906001600160a01b03610a00949316815281602082015201906109af565b1561160657565b606460405162461bcd60e51b815260206004820152601b60248201527f45585445524e414c5f56414c49444154494f4e5f4e4f545f53455400000000006044820152fd5b91908260409103126101355760206116618361102e565b92015190565b9061168c61167d606092838552838501906109af565b602094848203868601526109af565b926040928381860391015284519182855281850182808560051b8801019701946000925b8584106116c257505050505050505090565b90919293949596989785806117056001938d601f1990820301885285878d516001600160a01b0381511684528581015186850152015191818982015201906109af565b9a9b990197969591909101930191906116b0565b6040906117496117396117346117d095600098973691610b5a565b611833565b506020808251830101910161157f565b916001600160a01b0398919880911693169761179b61177b8a6001600160a01b03166000526000602052604060002090565b548751602081019061179281610e8c878b866115df565b519020146115ff565b8551968795869485937ffcfbba4d00000000000000000000000000000000000000000000000000000000855260048501611667565b03925af1801561115d5760009182916117e857509091565b905061047d915060403d811161180b575b611803818361089c565b81019061164a565b503d6117f9565b805160401015610a595760600190565b908151811015610a59570160200190565b90600019916118458382510182611822565b5160f81c928151908101908111610a125761186090826118b8565b9190565b6020815111156118745760209052565b606460405162461bcd60e51b815260206004820152601860248201527f42797465734c69623a206f6e6c7920736872696e6b696e6700000000000000006044820152fd5b81815111156118745752565b6118d091600191611d6e565b6118d75790565b606460405162461bcd60e51b815260206004820152600f60248201527f53565f555345445f554e424f554e4400000000000000000000000000000000006044820152fd5b1561192257565b606460405162461bcd60e51b815260206004820152600960248201527f53565f5349474c454e00000000000000000000000000000000000000000000006044820152fd5b6007111561197057565b634e487b7160e01b600052602160045260246000fd5b6040519061199382610880565b600682527f416d6269726500000000000000000000000000000000000000000000000000006020830152565b604051906119cc82610880565b600182527f31000000000000000000000000000000000000000000000000000000000000006020830152565b60405190611a058261085f565b602d82527f62797465733332206861736829000000000000000000000000000000000000006040837f416d626972654f7065726174696f6e2861646472657373206163636f756e742c60208201520152565b15611a5e57565b606460405162461bcd60e51b815260206004820152600f60248201527f53565f53504f4f465f4f524947494e00000000000000000000000000000000006044820152fd5b15611aa957565b606460405162461bcd60e51b815260206004820152600c60248201527f53565f53504f4f465f4c454e00000000000000000000000000000000000000006044820152fd5b1561013557565b908160209103126101355751610a008161016b565b15611b1057565b606460405162461bcd60e51b815260206004820152600d60248201527f53565f4c454e5f57414c4c4554000000000000000000000000000000000000006044820152fd5b908160209103126101355751610a0081610123565b604090610a009392815281602082015201906109af565b15611b8757565b606460405162461bcd60e51b815260206004820152601160248201527f53565f57414c4c45545f494e56414c49440000000000000000000000000000006044820152fd5b90602090818382031261013557825167ffffffffffffffff93848211610135570181601f82011215610135578051611c0281610bdc565b94611c10604051968761089c565b818652848087019260051b8401019380851161013557858401925b858410611c3c575050505050505090565b8351838111610135578791611c56848480948a010161153d565b815201930192611c2b565b9190826080910312610135578151916020810151916060604083015192015160ff811681036101355790565b15611c9457565b606460405162461bcd60e51b815260206004820152600b60248201527f53565f5a45524f5f5349470000000000000000000000000000000000000000006044820152fd5b15611cdf57565b606460405162461bcd60e51b815260206004820152601160248201527f53565f5343484e4f52525f4641494c45440000000000000000000000000000006044820152fd5b15611d2a57565b606460405162461bcd60e51b815260206004820152600660248201527f53565f4c454e00000000000000000000000000000000000000000000000000006044820152fd5b90929192611d7e8151151561191b565b611db9610d8e611d9360001984510184611822565b517fff000000000000000000000000000000000000000000000000000000000000001690565b600660ff82161015612445575b60ff1693611dd385611966565b600090611ddf86611966565b85159586158781612430575b881561230a575b611dfb83611966565b906122f7575b15611ea35750505080602092611e266000935160418114908115611e98575b50611d23565b611e72611e328361249b565b92611e4b610d8e611d93611e45846124ef565b93611812565b93604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa1561115d576000515b6118606001600160a01b0382161515611c8d565b604291501438611e20565b611eac81611966565b6004810361205e57505050611f0b611f4b926020611ee784611ed9611ed360009751610a03565b826118b8565b828082518301019101611c61565b978396899398949270014551231950b75fc4402da1732fc9bebe1993849109610a17565b91611f24611f1b828a8c09610a17565b91841415611aed565b87604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa1561115d57611ffe6110ed93839261205996611fe160005192611f816001600160a01b0385161515611c8d565b6040519687936020850195869290605594927fff00000000000000000000000000000000000000000000000000000000000000916bffffffffffffffffffffffff199060601b16855260f81b166014840152601583015260358201520190565b0393611ff5601f199586810183528261089c565b51902014611cd8565b61204a604051918261203e6020820195866027917f5343484e4f525200000000000000000000000000000000000000000000000000825260078201520190565b0390810183528261089c565b5190206001600160a01b031690565b611e84565b61206d81979397959495611966565b6005810361212a5750505061208b6120858351610a03565b836118b8565b61209f602092838082518301019101611bcb565b600080955b8251871461211f576120c260006120bb8986610f3d565b5186611d6e565b612116575b6110ed61211092610e8c61204a61210a946040519283918c83019586906028926bffffffffffffffffffffffff19809260601b16835260601b1660148201520190565b96610ed9565b956120a4565b600192506120c7565b935094505050611e84565b6121378197949397611966565b600281036121f557505061219d91506121536021845111611b09565b60206001600160a01b03811985510161217f6121786110ed6110ed6110ed858b6124ff565b91876118b8565b169360405180948192630b135d3f60e11b9586845260048401611b69565b0381865afa91821561115d57612059926001600160e01b0319916000916121c7575b501614611b80565b6121e8915060203d81116121ee575b6121e0818361089c565b810190611b54565b386121bf565b503d6121d6565b600391925061220381611966565b1490816122ef575b50156122aa5760013214801561229f575b61222590611a57565b6122326021835114611aa2565b61223b82611864565b6020816040518061226381906000606060808401938281528260208201528260408201520152565b838052039060015afa1561115d5761205991612290611b396001600160a01b036110ed9451161415611aed565b60208082518301019101611af4565b5032611b391461221c565b60405162461bcd60e51b815260206004820152600760248201527f53565f54595045000000000000000000000000000000000000000000000000006044820152606490fd5b90503861220b565b5061230181611966565b60018114611e01565b95612313611986565b61242761238682516020809401206123296119bf565b805190850120604080517fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac56472818801908152602081019490945290830191909152466060830152306080830152600060a083015291829060c0830190565b039161239a601f199384810183528261089c565b519020936123d46123e06123ac6119f8565b8051908701206040805180890192835230602084015290820194909452929182906060850190565b0384810183528261089c565b5190209261203e6040519485928301968790916042927f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201520190565b51902095611df2565b975061243b82611966565b6005821497611deb565b508051604103612456576000611dc6565b60405162461bcd60e51b815260206004820152600a60248201527f53565f5349474d4f4445000000000000000000000000000000000000000000006044820152606490fd5b60208151106124ab576020015190565b606460405162461bcd60e51b815260206004820152601060248201527f42797465734c69623a206c656e677468000000000000000000000000000000006044820152fd5b60408151106124ab576040015190565b9060208101808211610a12578251106124ab5701602001519056fea2646970667358221220a8465bc3156b7c18a1559d2cc13b7ec13f67e50d2c6eff2767a7be12ae36c2d464736f6c63430008130033
Deployed Bytecode
0x6080604052600436101561001e575b361561001c5761001c6107bb565b005b60003560e01c806301ffc9a71461011e5780630d5828d414610119578063150b7a02146101145780631626ba7e1461010f57806319822f7c1461010a5780633628d042146101055780636171d1c9146101005780636769de82146100fb578063a2ea6766146100f6578063abc5345e146100f1578063affed0e0146100ec578063bc197c81146100e7578063bf1cb383146100e2578063c066a5b1146100dd578063e6a6332e146100d85763f23a6e610361000e57610748565b6106dc565b61069e565b610631565b610588565b61056a565b610527565b6104a7565b610481565b610401565b61030c565b6102c1565b610270565b610216565b61017c565b61013a565b6001600160e01b031981160361013557565b600080fd5b3461013557602036600319011261013557602061016160043561015c81610123565b61105b565b6040519015158152f35b6001600160a01b0381160361013557565b6040366003190112610135576004356101948161016b565b7f08ac40e0195c5998554e98853c23964a13a24309e127b2d016e8ec4adecf5e8360206001600160a01b03602435936101ce3033146107fe565b1692836000526000825280604060002055604051908152a2005b9181601f840112156101355782359167ffffffffffffffff8311610135576020838186019501011161013557565b346101355760803660031901126101355761023260043561016b565b61023d60243561016b565b60643567ffffffffffffffff81116101355761025d9036906004016101e8565b50506020604051630a85bd0160e11b8152f35b346101355760403660031901126101355760243567ffffffffffffffff8111610135576102af6102a660209236906004016101e8565b90600435610fcb565b6001600160e01b031960405191168152f35b600319606036820112610135576004359067ffffffffffffffff82116101355761012090823603011261013557610304602091604435906024359060040161137d565b604051908152f35b6080366003190112610135576004356103248161016b565b6024359060443567ffffffffffffffff8111610135576103489036906004016101e8565b90916103553033146107fe565b5a92600080604051858482378086810183815203908886606435f161038761037b6108da565b955a9060061c10610920565b1561038e57005b7f80c2637928bd94d0e1a90eaac1efc1553be6391d962fe5c82a01e90122c84ccc936001600160a01b03936103cb926040519586951697856109d4565b0390a2005b9181601f840112156101355782359167ffffffffffffffff8311610135576020808501948460051b01011161013557565b60403660031901126101355767ffffffffffffffff6004358181116101355761042e9036906004016103d0565b906024359283116101355761044a61001c9336906004016101e8565b929091610d4b565b6020600319820112610135576004359067ffffffffffffffff82116101355761047d916004016103d0565b9091565b61001c6104a261049036610452565b61049b3033146107fe565b3691610bf4565b610f51565b6104b036610452565b60005b8181036104bc57005b6104c7818385610ee8565b803590601e198136030182121561013557019081359167ffffffffffffffff8311610135576020809101928060051b36038413610135576105229361044a61051d9361051486898b610ee8565b90810190610f0a565b610ed9565b6104b3565b6104a261055161053636610452565b92906000933385528460205261049b60408620541515610b91565b3381528060205261056760408220541515610d00565b80f35b34610135576000366003190112610135576020600154604051908152f35b346101355760a0366003190112610135576105a460043561016b565b6105af60243561016b565b67ffffffffffffffff604435818111610135576105d09036906004016103d0565b5050606435818111610135576105ea9036906004016103d0565b5050608435908111610135576106049036906004016101e8565b50506040517fbc197c81000000000000000000000000000000000000000000000000000000008152602090f35b6060366003190112610135576004356106498161016b565b6024359060443567ffffffffffffffff81116101355761066d9036906004016101e8565b909161067a3033146107fe565b5a9260008060405185848237808681018381520390888689f161038761037b6108da565b34610135576020366003190112610135576001600160a01b036004356106c38161016b565b1660005260006020526020604060002054604051908152f35b6003196020368201126101355760043567ffffffffffffffff8111610135576060816004019282360301126101355761001c9161071a3033146107fe565b602461073f61073883359361072e8561016b565b6044860190610f0a565b3691610b5a565b92013590610faa565b346101355760a03660031901126101355761076460043561016b565b61076f60243561016b565b60843567ffffffffffffffff81116101355761078f9036906004016101e8565b505060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b6000906169698252816020526001600160a01b036040832054169081156107f95750818091368280378136915af4903d918282803e156107f757f35bfd5b915050565b1561080557565b606460405162461bcd60e51b815260206004820152601560248201527f4f4e4c595f4143434f554e545f43414e5f43414c4c00000000000000000000006044820152fd5b634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff82111761087b57604052565b610849565b6040810190811067ffffffffffffffff82111761087b57604052565b90601f8019910116810190811067ffffffffffffffff82111761087b57604052565b67ffffffffffffffff811161087b57601f01601f191660200190565b3d15610905573d906108eb826108be565b916108f9604051938461089c565b82523d6000602084013e565b606090565b634e487b7160e01b600052601160045260246000fd5b1561092757565b606460405162461bcd60e51b815260206004820152600c60248201527f54525943415443485f4f4f4700000000000000000000000000000000000000006044820152fd5b908060209392818452848401376000828201840152601f01601f1916010190565b60005b83811061099f5750506000910152565b818101518382015260200161098f565b906020916109c88151809281855285808601910161098c565b601f01601f1916010190565b9291610a0094926109f292855260606020860152606085019161096b565b9160408184039101526109af565b90565b600019810191908211610a1257565b61090a565b9070014551231950b75fc4402da1732fc9bebe19918203918211610a1257565b634e487b7160e01b600052603260045260246000fd5b90821015610a59570190565b610a37565b9060018201809211610a1257565b9491909460808101936001600160a01b0380971682526020928383015260409081830152836060956080878501525260a082019060a08560051b84010197876000945b878610610ac3575050505050505050505090565b90919293949596979899609f198282030186528a35605e1984360301811215610135578301848135610af48161016b565b168252888101358983015285810135601e19823603018112156101355701888101903567ffffffffffffffff811161013557803603821361013557610b468a9283928e86818c6001990152019161096b565b9c0196019601949897969593929190610aaf565b929192610b66826108be565b91610b74604051938461089c565b829481845281830111610135578281602093846000960137010152565b15610b9857565b606460405162461bcd60e51b815260206004820152601660248201527f494e53554646494349454e545f50524956494c454745000000000000000000006044820152fd5b67ffffffffffffffff811161087b5760051b60200190565b929190610c0081610bdc565b91604091610c108351948561089c565b839581855260208095019160051b8101938385116101355781925b858410610c3b5750505050505050565b67ffffffffffffffff9084358281116101355784019160608388031261013557835192610c678461085f565b8035610c728161016b565b8452898101358a8501528481013591821161013557019086601f83011215610135578892610ca68884868096359101610b5a565b85820152815201930192610c2b565b15610cbc57565b606460405162461bcd60e51b815260206004820152601d60248201527f5349474e41545552455f56414c49444154494f4e5f54494d454c4f434b0000006044820152fd5b15610d0757565b606460405162461bcd60e51b815260206004820152601860248201527f50524956494c4547455f4e4f545f444f574e47524144454400000000000000006044820152fd5b91929092610d94610d8e610d68610d6185610a03565b8585610a4d565b357fff000000000000000000000000000000000000000000000000000000000000001690565b60f81c90565b60ff8060015492610dac610da785610a5e565b600155565b1603610e5c575090610dc891610dc3368686610bf4565b611719565b9093919315610e0b575091610de86104a2610e0193610e09953691610bf4565b6001600160a01b03166000526000602052604060002090565b541515610d00565b565b610e1790421015610cb5565b60405162461bcd60e51b815260206004820152601960248201527f5349474e41545552455f56414c49444154494f4e5f4641494c000000000000006044820152606490fd5b610e0193610eab610e099694610ea5610de8956104a295604051610e9a81610e8c8c8a6020840196463089610a6c565b03601f19810183528261089c565b519020923691610b5a565b906118c4565b93610ed4610ecc866001600160a01b03166000526000602052604060002090565b541515610b91565b61049b565b6000198114610a125760010190565b9190811015610a595760051b81013590603e1981360301821215610135570190565b903590601e1981360301821215610135570180359067ffffffffffffffff82116101355760200191813603831361013557565b8051821015610a595760209160051b010190565b80519060005b828110610f6357505050565b80610f71610f8a9284610f3d565b516001600160a01b0381511680610f8f575b5050610ed9565b610f57565b8160406020610fa394015191015191610faa565b3880610f83565b916000928392602083519301915af115610fc057565b3d604051816000823efd5b6001600160a01b0392610fed91610fe760009485933691610b5a565b90611d6e565b9216815280602052604081205491600014611026575060ff60015b16101561101a57630b135d3f60e11b90565b6001600160e01b031990565b60ff90611008565b5190811515820361013557565b9081602091031261013557610a009061102e565b6040513d6000823e3d90fd5b7f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b031982168181149081156111c5575b811561119b575b8115611171575b5061116a5761696960009081526020526001600160a01b036110f96110ed807f662a30f03e82d96c1f4d254ac3d297ac2d115f4d7e55a040fee317b77fa274e7546001600160a01b031690565b6001600160a01b031690565b16918215611162576040519182526001600160e01b031916600482015290602090829060249082905afa90811561115d57600091611135575090565b610a00915060203d8111611156575b61114e818361089c565b81019061103b565b503d611144565b61104f565b505050600090565b5050600190565b7f0a41763200000000000000000000000000000000000000000000000000000000915014386110a0565b7f4e2312e00000000000000000000000000000000000000000000000000000000081149150611099565b630a85bd0160e11b81149150611092565b906004116101355790600490565b906014116101355790601490565b6001600160e01b0319903581811693926004811061120f57505050565b60040360031b82901b16169150565b6bffffffffffffffffffffffff19903581811693926014811061124057505050565b60140360031b82901b16169150565b1561125657565b608460405162461bcd60e51b815260206004820152603460248201527f76616c6964617465557365724f703a207061796d61737465722072657175697260448201527f656420696e20657865637574652829206d6f64650000000000000000000000006064820152fd5b9497959290936112e1610a009a98956112ef9460c0895260c089019161096b565b91868303602088015261096b565b9560408401526060830152608082015260a081850391015261096b565b1561131357565b608460405162461bcd60e51b815260206004820152602360248201527f76616c6964617465557365724f703a206e6f742066726f6d20656e747279506f60448201527f696e7400000000000000000000000000000000000000000000000000000000006064820152fd5b9160608301600461138e8286610f0a565b90501015806114ef575b611411575090610ea56107386113e894610de8946113d66171716113cf336001600160a01b03166000526000602052604060002090565b541461130c565b806113f8575b50610100810190610f0a565b54156113f357600090565b600190565b600080808093335af15061140a6108da565b50386113dc565b915050611422610100830183610f0a565b905061116a576114a960209160e0840190603461143f8387610f0a565b90501015806114b6575b6114529061124f565b6114a061147d610e8c61147461146b60408a018a610f0a565b9190958a610f0a565b9390968a610f0a565b918a6040519788968c88019a60c084013594608060a0860135950135938d6112c0565b51902060401b90565b910135036113f357600090565b506114526114e56114d06114ca8589610f0a565b906111e4565b6bffffffffffffffffffffffff19929161121e565b1615159050611449565b507fa2ea6766000000000000000000000000000000000000000000000000000000006001600160e01b031961153661153061152a8589610f0a565b906111d6565b906111f2565b1614611398565b81601f82011215610135578051611553816108be565b92611561604051948561089c565b8184526020828401011161013557610a00916020808501910161098c565b906080828203126101355781516115958161016b565b9260208301516115a48161016b565b9260408101519267ffffffffffffffff9384811161013557816115c891840161153d565b93606083015190811161013557610a00920161153d565b6040906001600160a01b03610a00949316815281602082015201906109af565b1561160657565b606460405162461bcd60e51b815260206004820152601b60248201527f45585445524e414c5f56414c49444154494f4e5f4e4f545f53455400000000006044820152fd5b91908260409103126101355760206116618361102e565b92015190565b9061168c61167d606092838552838501906109af565b602094848203868601526109af565b926040928381860391015284519182855281850182808560051b8801019701946000925b8584106116c257505050505050505090565b90919293949596989785806117056001938d601f1990820301885285878d516001600160a01b0381511684528581015186850152015191818982015201906109af565b9a9b990197969591909101930191906116b0565b6040906117496117396117346117d095600098973691610b5a565b611833565b506020808251830101910161157f565b916001600160a01b0398919880911693169761179b61177b8a6001600160a01b03166000526000602052604060002090565b548751602081019061179281610e8c878b866115df565b519020146115ff565b8551968795869485937ffcfbba4d00000000000000000000000000000000000000000000000000000000855260048501611667565b03925af1801561115d5760009182916117e857509091565b905061047d915060403d811161180b575b611803818361089c565b81019061164a565b503d6117f9565b805160401015610a595760600190565b908151811015610a59570160200190565b90600019916118458382510182611822565b5160f81c928151908101908111610a125761186090826118b8565b9190565b6020815111156118745760209052565b606460405162461bcd60e51b815260206004820152601860248201527f42797465734c69623a206f6e6c7920736872696e6b696e6700000000000000006044820152fd5b81815111156118745752565b6118d091600191611d6e565b6118d75790565b606460405162461bcd60e51b815260206004820152600f60248201527f53565f555345445f554e424f554e4400000000000000000000000000000000006044820152fd5b1561192257565b606460405162461bcd60e51b815260206004820152600960248201527f53565f5349474c454e00000000000000000000000000000000000000000000006044820152fd5b6007111561197057565b634e487b7160e01b600052602160045260246000fd5b6040519061199382610880565b600682527f416d6269726500000000000000000000000000000000000000000000000000006020830152565b604051906119cc82610880565b600182527f31000000000000000000000000000000000000000000000000000000000000006020830152565b60405190611a058261085f565b602d82527f62797465733332206861736829000000000000000000000000000000000000006040837f416d626972654f7065726174696f6e2861646472657373206163636f756e742c60208201520152565b15611a5e57565b606460405162461bcd60e51b815260206004820152600f60248201527f53565f53504f4f465f4f524947494e00000000000000000000000000000000006044820152fd5b15611aa957565b606460405162461bcd60e51b815260206004820152600c60248201527f53565f53504f4f465f4c454e00000000000000000000000000000000000000006044820152fd5b1561013557565b908160209103126101355751610a008161016b565b15611b1057565b606460405162461bcd60e51b815260206004820152600d60248201527f53565f4c454e5f57414c4c4554000000000000000000000000000000000000006044820152fd5b908160209103126101355751610a0081610123565b604090610a009392815281602082015201906109af565b15611b8757565b606460405162461bcd60e51b815260206004820152601160248201527f53565f57414c4c45545f494e56414c49440000000000000000000000000000006044820152fd5b90602090818382031261013557825167ffffffffffffffff93848211610135570181601f82011215610135578051611c0281610bdc565b94611c10604051968761089c565b818652848087019260051b8401019380851161013557858401925b858410611c3c575050505050505090565b8351838111610135578791611c56848480948a010161153d565b815201930192611c2b565b9190826080910312610135578151916020810151916060604083015192015160ff811681036101355790565b15611c9457565b606460405162461bcd60e51b815260206004820152600b60248201527f53565f5a45524f5f5349470000000000000000000000000000000000000000006044820152fd5b15611cdf57565b606460405162461bcd60e51b815260206004820152601160248201527f53565f5343484e4f52525f4641494c45440000000000000000000000000000006044820152fd5b15611d2a57565b606460405162461bcd60e51b815260206004820152600660248201527f53565f4c454e00000000000000000000000000000000000000000000000000006044820152fd5b90929192611d7e8151151561191b565b611db9610d8e611d9360001984510184611822565b517fff000000000000000000000000000000000000000000000000000000000000001690565b600660ff82161015612445575b60ff1693611dd385611966565b600090611ddf86611966565b85159586158781612430575b881561230a575b611dfb83611966565b906122f7575b15611ea35750505080602092611e266000935160418114908115611e98575b50611d23565b611e72611e328361249b565b92611e4b610d8e611d93611e45846124ef565b93611812565b93604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa1561115d576000515b6118606001600160a01b0382161515611c8d565b604291501438611e20565b611eac81611966565b6004810361205e57505050611f0b611f4b926020611ee784611ed9611ed360009751610a03565b826118b8565b828082518301019101611c61565b978396899398949270014551231950b75fc4402da1732fc9bebe1993849109610a17565b91611f24611f1b828a8c09610a17565b91841415611aed565b87604051948594859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa1561115d57611ffe6110ed93839261205996611fe160005192611f816001600160a01b0385161515611c8d565b6040519687936020850195869290605594927fff00000000000000000000000000000000000000000000000000000000000000916bffffffffffffffffffffffff199060601b16855260f81b166014840152601583015260358201520190565b0393611ff5601f199586810183528261089c565b51902014611cd8565b61204a604051918261203e6020820195866027917f5343484e4f525200000000000000000000000000000000000000000000000000825260078201520190565b0390810183528261089c565b5190206001600160a01b031690565b611e84565b61206d81979397959495611966565b6005810361212a5750505061208b6120858351610a03565b836118b8565b61209f602092838082518301019101611bcb565b600080955b8251871461211f576120c260006120bb8986610f3d565b5186611d6e565b612116575b6110ed61211092610e8c61204a61210a946040519283918c83019586906028926bffffffffffffffffffffffff19809260601b16835260601b1660148201520190565b96610ed9565b956120a4565b600192506120c7565b935094505050611e84565b6121378197949397611966565b600281036121f557505061219d91506121536021845111611b09565b60206001600160a01b03811985510161217f6121786110ed6110ed6110ed858b6124ff565b91876118b8565b169360405180948192630b135d3f60e11b9586845260048401611b69565b0381865afa91821561115d57612059926001600160e01b0319916000916121c7575b501614611b80565b6121e8915060203d81116121ee575b6121e0818361089c565b810190611b54565b386121bf565b503d6121d6565b600391925061220381611966565b1490816122ef575b50156122aa5760013214801561229f575b61222590611a57565b6122326021835114611aa2565b61223b82611864565b6020816040518061226381906000606060808401938281528260208201528260408201520152565b838052039060015afa1561115d5761205991612290611b396001600160a01b036110ed9451161415611aed565b60208082518301019101611af4565b5032611b391461221c565b60405162461bcd60e51b815260206004820152600760248201527f53565f54595045000000000000000000000000000000000000000000000000006044820152606490fd5b90503861220b565b5061230181611966565b60018114611e01565b95612313611986565b61242761238682516020809401206123296119bf565b805190850120604080517fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac56472818801908152602081019490945290830191909152466060830152306080830152600060a083015291829060c0830190565b039161239a601f199384810183528261089c565b519020936123d46123e06123ac6119f8565b8051908701206040805180890192835230602084015290820194909452929182906060850190565b0384810183528261089c565b5190209261203e6040519485928301968790916042927f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201520190565b51902095611df2565b975061243b82611966565b6005821497611deb565b508051604103612456576000611dc6565b60405162461bcd60e51b815260206004820152600a60248201527f53565f5349474d4f4445000000000000000000000000000000000000000000006044820152606490fd5b60208151106124ab576020015190565b606460405162461bcd60e51b815260206004820152601060248201527f42797465734c69623a206c656e677468000000000000000000000000000000006044820152fd5b60408151106124ab576040015190565b9060208101808211610a12578251106124ab5701602001519056fea2646970667358221220a8465bc3156b7c18a1559d2cc13b7ec13f67e50d2c6eff2767a7be12ae36c2d464736f6c63430008130033
Deployed Bytecode Sourcemap
650:16137:0:-:0;;;;;;;;;-1:-1:-1;650:16137:0;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;;:::i;:::-;-1:-1:-1;;;;;;650:16137:0;;;;;:::o;:::-;;;;;;;;;;-1:-1:-1;;650:16137:0;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;;;-1:-1:-1;;;;;650:16137:0;;;;;:::o;:::-;;;-1:-1:-1;;650:16137:0;;;;;;;;;:::i;:::-;4294:31;650:16137;-1:-1:-1;;;;;650:16137:0;;4227:4;4197:61;4227:4;4205:10;:27;4197:61;:::i;:::-;650:16137;;;-1:-1:-1;650:16137:0;-1:-1:-1;650:16137:0;;;;-1:-1:-1;650:16137:0;;;;;;;4294:31;650:16137;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;-1:-1:-1;;650:16137:0;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;-1:-1:-1;;;650:16137:0;;;;;;;;;-1:-1:-1;;650:16137:0;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;-1:-1:-1;;;;;;650:16137:0;;;;;;;;-1:-1:-1;;650:16137:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;-1:-1:-1;;650:16137:0;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;5293:4;;5263:61;5293:4;5271:10;:27;5263:61;:::i;:::-;5348:9;650:16137;-1:-1:-1;650:16137:0;;;;;;;;;;;;;;5403:44;650:16137;;;;;5403:44;5451:51;5403:44;;:::i;:::-;5459:9;;650:16137;;;-1:-1:-1;5451:51:0;:::i;:::-;5510:8;5506:54;;650:16137;5506:54;5525:35;650:16137;-1:-1:-1;;;;;650:16137:0;5525:35;650:16137;;;;;;;5525:35;;;:::i;:::-;;;;650:16137;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;-1:-1:-1;;650:16137:0;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;-1:-1:-1;;650:16137:0;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;8316:19;1440:3;650:16137;;;:::i;:::-;8251:61;8281:4;8259:10;:27;8251:61;:::i;:::-;650:16137;1440:3;;:::i;:::-;8316:19;:::i;650:16137::-;;;;:::i;:::-;7389:1;7392:18;;;;;;650:16137;7412:3;7425:9;;;;;:::i;:::-;650:16137;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7412:3;7442:9;:19;;:9;;;;;;:::i;:::-;:19;;;;;:::i;:::-;7412:3;:::i;:::-;7377:13;;650:16137;1440:3;7834:19;650:16137;;;:::i;:::-;7767:10;;;7778;;650:16137;;;;;7759:71;650:16137;;;1147:15;7767:36;;7759:71;:::i;7834:19::-;7778:10;650:16137;;;;;7883:73;650:16137;;;1147:15;7891:36;;7883:73;:::i;:::-;650:16137;;;;;;;;-1:-1:-1;;650:16137:0;;;;;1509:20;650:16137;;;;;;;;;;;;;-1:-1:-1;;650:16137:0;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;;650:16137:0;;;;;;;;;;;-1:-1:-1;;650:16137:0;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;:::i;:::-;4661:4;;4631:61;4661:4;4639:10;:27;4631:61;:::i;:::-;4716:9;650:16137;-1:-1:-1;650:16137:0;;;;;;;;;;;;;;4771:45;;;;;;4820:51;4771:45;;:::i;650:16137::-;;;;;;-1:-1:-1;;650:16137:0;;;;-1:-1:-1;;;;;650:16137:0;;;;;:::i;:::-;;-1:-1:-1;650:16137:0;-1:-1:-1;650:16137:0;;;;-1:-1:-1;650:16137:0;;;;;;;;;-1:-1:-1;;650:16137:0;;;;;;;;;;;;;;;;;;;;;;;;;;8730:43;8695:4;8665:61;8695:4;8673:10;:27;8665:61;:::i;:::-;8751:10;1440:3;8763:9;650:16137;;;;;;:::i;:::-;8763:9;;;;;:::i;:::-;650:16137;1440:3;;:::i;:::-;8751:10;;650:16137;8730:43;;:::i;650:16137::-;;;;;;-1:-1:-1;;650:16137:0;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;3052:648;3185:10;650:16137;1155:6;650:16137;;;;;-1:-1:-1;;;;;650:16137:0;;;1147:15;650:16137;3229:29;;;3225:42;;3270:427;;;;;;;;;;;;;;;;;;;;;;;;;;3225:42;3260:7;;;:::o;650:16137::-;;;;:::o;:::-;;;;-1:-1:-1;;;650:16137:0;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;650:16137:0;;;;;;;;;1440:3;650:16137;;;;;;;;;;;;;:::o;:::-;;:::i;:::-;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;-1:-1:-1;;650:16137:0;;;;:::o;:::-;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;-1:-1:-1;650:16137:0;;;;:::o;:::-;;;:::o;:::-;-1:-1:-1;;;650:16137:0;;;;;;;;;;;;:::o;:::-;;;;-1:-1:-1;;;650:16137:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;650:16137:0;;;;;;;;-1:-1:-1;;650:16137:0;;;;:::o;:::-;;;;;;;;-1:-1:-1;;650:16137:0;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;650:16137:0;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;:::o;:::-;-1:-1:-1;;650:16137:0;;;;;;;;:::o;:::-;;:::i;:::-;;-1:-1:-1;;650:16137:0;;;;;;;;:::o;:::-;-1:-1:-1;;;650:16137:0;;;;;;;;;;;;;;;;;:::o;:::-;;:::i;:::-;;6204:1;650:16137;;;;;;;:::o;1440:3::-;;;;;;;;650:16137;-1:-1:-1;;;;;650:16137:0;;;1440:3;;;;;;;650:16137;1440:3;;;;;650:16137;1440:3;;;;;;;;650:16137;;;;1440:3;650:16137;1440:3;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;650:16137;;;;;;:::i;:::-;;1440:3;;;;;650:16137;1440:3;;;650:16137;1440:3;;;;650:16137;;1440:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;650:16137;;;;;;;:::i;:::-;1440:3;;;;;;;;;;;;;;;;-1:-1:-1;1440:3:0;;650:16137;;;;1440:3::o;:::-;;;;:::o;:::-;;650:16137;;-1:-1:-1;;;1440:3:0;;;;;;;;;;;650:16137;1440:3;650:16137;;;1440:3;;;;;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;650:16137;;;;;;;;;:::i;:::-;1440:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;650:16137;;;;;;:::i;:::-;;;;;;:::i;:::-;1440:3;;;;;650:16137;1440:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::o;:::-;;650:16137;;-1:-1:-1;;;1440:3:0;;;;;;;;;;;650:16137;1440:3;650:16137;;;1440:3;;;;;;:::o;:::-;;650:16137;;-1:-1:-1;;;1440:3:0;;;;;;;;;;;650:16137;1440:3;650:16137;;;1440:3;;6040:1090;;;;;6169:38;6175:31;;6185:20;;;:::i;:::-;6175:31;;;:::i;:::-;;650:16137;;;;6175:31;650:16137;;;;6169:38;650:16137;;6204:1;650:16137;6323:16;6315:24;6323:16;;;:::i;:::-;6204:1;650:16137;;6315:24;650:16137;6348:39;650:16137;;1440:3;;6493:37;1440:3;;;;;;:::i;:::-;6493:37;:::i;:::-;6446:84;;;6539:11;;6535:150;;6344:586;;6934:19;1440:3;7062:21;6344:586;7054:72;6344:586;1440:3;;;:::i;6934:19::-;-1:-1:-1;;;;;650:16137:0;-1:-1:-1;650:16137:0;-1:-1:-1;650:16137:0;;;-1:-1:-1;650:16137:0;;;7062:21;1147:15;7062:35;;7054:72;:::i;:::-;6040:1090::o;6535:150::-;6558:80;6566:15;;:38;;6558:80;:::i;:::-;650:16137;;-1:-1:-1;;;6644:35:0;;1440:3;6644:35;;;1440:3;;;;;650:16137;1440:3;650:16137;;;1440:3;;;6644:35;6344:586;7062:21;650:16137;6712:138;7054:72;650:16137;;1440:3;6934:19;650:16137;1440:3;650:16137;;;6758:61;;;;;;;;6784:13;;6777:4;6758:61;;:::i;:::-;;650:16137;;6758:61;;;;;;:::i;:::-;650:16137;6748:72;;1440:3;;;;:::i;:::-;6712:138;;:::i;:::-;6863:21;6855:70;6863:21;;-1:-1:-1;;;;;650:16137:0;-1:-1:-1;650:16137:0;-1:-1:-1;650:16137:0;;;-1:-1:-1;650:16137:0;;;6863:21;1147:15;6863:35;;6855:70;:::i;:::-;6344:586;;650:16137;-1:-1:-1;;650:16137:0;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;:::o;8887:249::-;650:16137;;8985:13;8997:1;9000:7;;;;;;8887:249;;;:::o;9009:3::-;9045:8;;9009:3;9045:8;;;:::i;:::-;;-1:-1:-1;;;;;650:16137:0;;;9062:21;9058:70;;9009:3;;;;:::i;:::-;8985:13;;9058:70;9106:10;9118:9;9106:10;9118:9;9106:10;;650:16137;9118:9;;;;;:::i;:::-;9058:70;;;;9412:316;;9492:233;9412:316;;;9492:233;;;;;;;;;;;9412:316::o;9492:233::-;;;;;;;;;9978:404;-1:-1:-1;;;;;9978:404:0;10123:70;9978:404;1440:3;10187:5;1440:3;;;;;;:::i;:::-;10123:70;;:::i;:::-;650:16137;;;;;;;;;;1147:15;10235:23;;;;;;650:16137;10253:1;10235:23;650:16137;-1:-1:-1;650:16137:0;;;-1:-1:-1;;;10324:17:0;:::o;10197:182::-;-1:-1:-1;;;;;;10357:17:0;:::o;10235:23::-;650:16137;10235:23;;;650:16137;;;;;;;;;;:::o;:::-;;;;;;;;;;;;:::i;:::-;;;;;;;;;;10680:855;650:16137;-1:-1:-1;;;;;;650:16137:0;;10777:25;;;;:133;;;;10680:855;10777:188;;;;10680:855;10777:440;;;;10680:855;11275:26;;;650:16137;11371:10;650:16137;;;;;-1:-1:-1;;;;;11339:69:0;11347:60;;650:16137;1147:15;-1:-1:-1;;;;;650:16137:0;;;11355:51;-1:-1:-1;;;;;650:16137:0;;;11339:69;650:16137;11416:29;;;11412:47;;650:16137;;11470:61;;;-1:-1:-1;;;;;;650:16137:0;11470:61;;;650:16137;;11470:61;;650:16137;;;;;;11470:61;;;;;;;11371:10;11470:61;;;11463:68;10680:855;:::o;11470:61::-;;;;;;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;:::i;11412:47::-;11447:12;;;11371:10;11447:12;:::o;11275:26::-;11290:11;;11297:4;11290:11;:::o;10777:440::-;650:16137;11192:25;;;10777:440;;;:188;650:16137;10940:25;;;-1:-1:-1;10777:188:0;;:133;-1:-1:-1;;;10885:25:0;;;-1:-1:-1;10777:133:0;;650:16137;;13317:1;650:16137;;;;13317:1;650:16137;:::o;:::-;;134:2:10;650:16137:0;;;;134:2:10;650:16137:0;:::o;:::-;-1:-1:-1;;;;;;650:16137:0;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;-1:-1:-1;650:16137:0:o;134:2:10:-;-1:-1:-1;;134:2:10;;;;;;;;;;;;;;;:::o;:::-;;;;;650:16137:0;;;134:2:10;;;-1:-1:-1;134:2:10:o;:::-;;;;:::o;:::-;;650:16137:0;;-1:-1:-1;;;134:2:10;;;;;;;;;;;650:16137:0;134:2:10;650:16137:0;;;134:2:10;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;:::i;:::-;;;;;650:16137:0;134:2:10;;;650:16137:0;134:2:10;;;650:16137:0;134:2:10;;;;;;;;:::i;1280:66:0:-;;;;:::o;:::-;;650:16137;;-1:-1:-1;;;1280:66:0;;;;;;;;;;;650:16137;1280:66;650:16137;;;1280:66;;;;;;;12601:2388;;13295:11;;;13317:1;13295:11;;;;:::i;:::-;:23;;;;:84;;;12601:2388;13291:928;;14242:10;;1440:3;14862:12;14889:18;14242:10;14819:62;14242:10;14223:92;1280:66;14231:22;14242:10;-1:-1:-1;;;;;650:16137:0;-1:-1:-1;650:16137:0;-1:-1:-1;650:16137:0;;;-1:-1:-1;650:16137:0;;;14231:22;1147:15;14231:44;14223:92;:::i;:::-;14402:23;14398:265;;12601:2388;14862:12;;;;;;:::i;14889:18::-;1147:15;14889:32;14885:66;;14231:10;12601:2388;:::o;14885:66::-;14876:4;14923:28;:::o;14398:265::-;14231:10;14242;;;;;14528:48;;;;;:::i;:::-;;14398:265;;;13291:928;13526:12;;;;;;;;;:::i;:::-;:24;;13522:58;;13940:148;13963:113;13599:19;;;;;273:2:10;13599:19:0;;;;:::i;:::-;:64;;;;:151;;;13291:928;13586:229;;;:::i;:::-;13963:113;14056:19;13963:113;13987:11;13974;;;;;;:::i;:::-;13987;;;;;:::i;:::-;14056:19;;;;;:::i;:::-;650:16137;;13974:11;650:16137;13963:113;;;;;;14044:10;;;;134:2:10;14021:21:0;14000:19;14021:21;;;650:16137;14000:19;;134:2:10;13963:113:0;;;:::i;:::-;650:16137;13948:133;;650:16137;;134:2:10;;13940:148:0;14126:8;;650:16137;14126:23;14122:57;;13549:1;14185:29;:::o;13599:151::-;13679:19;13586:229;13671:65;13679:56;:19;;;;:::i;:::-;:56;;:::i;:::-;-1:-1:-1;;134:2:10;;13671:65:0;:::i;:::-;134:2:10;13671:79:0;;13599:151;;;;13295:84;13329:11;650:16137;-1:-1:-1;;;;;;13322:24:0;13329:16;:11;;;;:::i;:::-;:16;;:::i;:::-;13322:24;;:::i;:::-;650:16137;13322:57;13295:84;;650:16137;;;;;;;;;;;;;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;:::i;:::-;;;-1:-1:-1;;;;;650:16137:0;;;;1440:3;;650:16137;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;-1:-1:-1;;;650:16137:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::o;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;1440:3;;650:16137;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;650:16137:0;;;1440:3;;650:16137;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;1440:3;;650:16137;;;;;;;;;;;;14992:1793;650:16137;14992:1793;16311:49;15185:44;1440:3;16702:79;14992:1793;-1:-1:-1;14992:1793:0;;1440:3;;;:::i;:::-;15185:44;:::i;:::-;650:16137;16311:49;650:16137;;;16311:49;;;;;;:::i;:::-;650:16137;-1:-1:-1;;;;;650:16137:0;;;;;;;;16376:21;16364:126;16376:21;;-1:-1:-1;;;;;650:16137:0;-1:-1:-1;650:16137:0;-1:-1:-1;650:16137:0;;;-1:-1:-1;650:16137:0;;;16376:21;1147:15;650:16137;;16311:49;16411:40;;;;;;;;;;:::i;:::-;650:16137;16401:51;;16376:76;16364:126;:::i;:::-;650:16137;;16702:79;;;;;;;650:16137;16702:79;;;;;;:::i;:::-;;;;;;;;;-1:-1:-1;;;16702:79:0;;;16666:115;;14992:1793;:::o;16702:79::-;;;;;;650:16137;16702:79;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;650:16137;;;4019:2:6;650:16137:0;;;;;;;:::o;:::-;;;;;;;;;;;;;:::o;1787:225:6:-;;650:16137:0;;;1925:19:6;650:16137:0;;;;1925:19:6;;:::i;:::-;650:16137:0;;;;;;;;;;;;;;1968:14:6;;;;:::i;:::-;1987:21;1787:225;:::o;79:166:5:-;6970:2:6;650:16137:0;;157:17:5;650:16137:0;;;6970:2:6;207:35:5;;79:166::o;650:16137:0:-;;;;-1:-1:-1;;;650:16137:0;;6970:2:6;650:16137:0;;;;;;;;;;;;;;;79:166:5;650:16137:0;;;157:17:5;650:16137:0;;;207:35:5;79:166::o;2015:278:6:-;2168:53;2015:278;6204:1:0;2015:278:6;2168:53;:::i;:::-;650:16137:0;;2015:278:6;:::o;650:16137:0:-;;;;-1:-1:-1;;;650:16137:0;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;-1:-1:-1;;;650:16137:0;;;;;;;;;;;;;;;;;;;;-1:-1:-1;650:16137:0;;;:::o;:::-;-1:-1:-1;;;650:16137:0;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;;:::o;:::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;:::o;:::-;;;;:::o;:::-;;;;-1:-1:-1;;;650:16137:0;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;-1:-1:-1;;;650:16137:0;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;-1:-1:-1;;;650:16137:0;;;;;;;;;;;;;;;;;;1648:10:6;;;;;;;;;;;;;:::i;:::-;;;;;;650:16137:0;;1648:10:6;;;;;;;;:::i;:::-;;;;:::o;:::-;;650:16137:0;;-1:-1:-1;;;1648:10:6;;;;;;;;;;;650:16137:0;1648:10:6;650:16137:0;;;1648:10:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;650:16137:0;;;;;;;:::i;:::-;1648:10:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;650:16137:0;;;1648:10:6;;;;;:::o;1717:66::-;;;;:::o;:::-;;650:16137:0;;-1:-1:-1;;;1717:66:6;;;;;;;;;;;650:16137:0;1717:66:6;650:16137:0;;;1717:66:6;;;;;;:::o;:::-;;650:16137:0;;-1:-1:-1;;;1717:66:6;;;;;;;;;;;650:16137:0;1717:66:6;650:16137:0;;;1717:66:6;;;;;;:::o;:::-;;650:16137:0;;-1:-1:-1;;;1717:66:6;;;;;;;;;;;650:16137:0;1717:66:6;650:16137:0;;;1717:66:6;;2296:4974;;;;;2427:37;650:16137:0;;2435:15:6;;2427:37;:::i;:::-;2511:26;2517:19;;650:16137:0;;;;;2517:19:6;;:::i;:::-;650:16137:0;;;;;2511:26:6;2700:24;650:16137:0;;;2683:42:6;;2679:152;;2296:4974;650:16137:0;;;;;;:::i;:::-;;;;;;:::i;:::-;3166:33:6;;;:67;;:33;:67;;;2296:4974;3145:88;3241:14;3237:528;;2296:4974;650:16137:0;;;:::i;:::-;3794:67:6;;;2296:4974;3790:3389;;;650:16137:0;;;;3991:2:6;650:16137:0;3868:55:6;650:16137:0;;;3890:2:6;3876:16;;:36;;;;;3790:3389;3868:55;;:::i;:::-;4040:24;3940:18;;;:::i;:::-;3975:19;4009:14;4015:7;;3975:19;;;:::i;:::-;4015:7;;:::i;4009:14::-;650:16137:0;4019:2:6;650:16137:0;4040:24:6;;;;1717:66;;;;650:16137:0;1717:66:6;;;;;650:16137:0;;;;1717:66:6;;;650:16137:0;1717:66:6;;;650:16137:0;1717:66:6;650:16137:0;1717:66:6;4040:24;;;;;;2534:1;4040:24;;;;;650:16137:0;4040:24:6;3790:3389;7182:47;-1:-1:-1;;;;;650:16137:0;;7190:23:6;;7182:47;:::i;3876:36::-;3910:2;3896:16;;;3876:36;;;3790:3389;650:16137:0;;;:::i;:::-;4114:21:6;4106:29;;4114:21;;650:16137:0;;;4718:38:6;5052:29;650:16137:0;4609:51:6;;650:16137:0;4538:14:6;;650:16137:0;;;4538:14:6;:::i;:::-;;;:::i;:::-;650:16137:0;;;;4609:51:6;;;;;;:::i;:::-;1717:66;;;;;;;;-1:-1:-1;;4722:34:6;;;;4718:38;:::i;:::-;4787:34;4828:25;4783:38;4787:34;;;;4783:38;:::i;:::-;4836:16;;;;4828:25;:::i;:::-;650:16137:0;;;5052:29:6;;;;1717:66;;;;650:16137:0;1717:66:6;;;;;650:16137:0;;;;1717:66:6;;;650:16137:0;1717:66:6;;;650:16137:0;1717:66:6;650:16137:0;1717:66:6;5052:29;;;;;;2534:1;5052:29;;;;;5130:90;5245:60;5052:29;;;5237:69;5052:29;5153:44;650:16137:0;5052:29:6;650:16137:0;5086:39:6;-1:-1:-1;;;;;650:16137:0;;5094:15:6;;5086:39;:::i;:::-;650:16137:0;;5153:44:6;;;4609:51;5153:44;;;;1717:66;;;;;;;134:2:10;;;;;;1648:10:6;;1717:66;;;;;;;;;;650:16137:0;1717:66:6;;;650:16137:0;1717:66:6;;;5153:44;;650:16137:0;5153:44:6;650:16137:0;;5153:44:6;;;;;;;;:::i;:::-;650:16137:0;5143:55:6;;5138:60;5130:90;:::i;:::-;5271:31;650:16137:0;;5271:31:6;;;4609:51;5271:31;;;;1717:66;;;;;;;;650:16137:0;1717:66:6;;;5271:31;;;;;;;;;:::i;:::-;650:16137:0;5261:42:6;;-1:-1:-1;;;;;650:16137:0;;;5237:69:6;3790:3389;;4102:3077;650:16137:0;;;;;;;;;:::i;:::-;5329:22:6;5321:30;;5329:22;;650:16137:0;;;5373:14:6;;650:16137:0;;5373:14:6;:::i;:::-;;;:::i;:::-;5421:26;;650:16137:0;;;;;5421:26:6;;;;;;:::i;:::-;650:16137:0;5561:13:6;5556:310;5600:3;650:16137:0;;5576:22:6;;;;5654:55;650:16137:0;5688:13:6;;;;:::i;:::-;;5654:55;;:::i;:::-;5715:44;;5600:3;5791:63;5600:3;650:16137:0;5817:34:6;;5777:83;650:16137:0;;;5817:34:6;;;;;;;;1648:10;;;134:2:10;;;;;;;1648:10:6;;134:2:10;;;1648:10:6;;;;;;;5777:83;5600:3;;:::i;:::-;5561:13;;;5715:44;2534:1;;-1:-1:-1;5715:44:6;;5576:22;;;;;;;3790:3389;;5317:1862;650:16137:0;;;;;;;:::i;:::-;5888:25:6;5880:33;;5888:25;;650:16137:0;;6249:34:6;650:16137:0;;5974:41:6;5995:2;650:16137:0;;5982:15:6;5974:41;:::i;:::-;650:16137:0;-1:-1:-1;;;;;650:16137:0;;;;;6199:6:6;6113:66;6128:50;6136:41;6152:23;;;;:::i;6113:66::-;6199:6;;;:::i;:::-;650:16137:0;;;;;;;;-1:-1:-1;;;6249:34:6;;;;4114:21;6249:34;;;:::i;:::-;;;;;;;;;;;6211:94;6249:34;-1:-1:-1;;;;;;6249:34:6;650:16137:0;6249:34:6;;;5876:1303;650:16137:0;;6219:64:6;6211:94;:::i;6249:34::-;;;;650:16137:0;6249:34:6;;;;;;;;;;:::i;:::-;;;;;:::i;:::-;;;;;;;;;5876:1303;6427:19;650:16137:0;;;;;;:::i;:::-;6419:27:6;:44;;;;5876:1303;-1:-1:-1;6415:764:6;;;2534:1;6831:9;:23;:53;;;;6415:764;6823:81;;;:::i;:::-;6909:41;6931:2;650:16137:0;;6917:16:6;6909:41;:::i;:::-;6955:18;;;:::i;:::-;6970:2;650:16137:0;;;7059:21:6;;;650:16137:0;;;;;;;;;;;;;;;;;;;;;;;7059:21:6;;;;;;2534:1;7059:21;;;;;7103:38;7059:21;7051:47;7092:4;-1:-1:-1;;;;;7115:26:6;7059:21;;650:16137:0;7059:38:6;;7051:47;:::i;:::-;6970:2;650:16137:0;;;7115:26:6;;;;;;:::i;6831:53::-;-1:-1:-1;6831:9:6;6879:4;6858:26;6831:53;;6415:764;650:16137:0;;-1:-1:-1;;;7157:17:6;;650:16137:0;4114:21:6;7157:17;;650:16137:0;;;;;;;;;;;;;6644:35;6419:44:6;;;;;;3794:67;650:16137:0;;;;:::i;:::-;2534:1:6;3831:30;;3794:67;;3237:528;650:16137:0;;;:::i;:::-;3564:195:6;3299:242;650:16137:0;;1440:3;;;;3429:26:6;650:16137:0;;:::i;:::-;;;1440:3;;;3461:21:6;650:16137:0;;;3315:108:6;3299:242;;;650:16137:0;;;;;;;;;;;;;;;;;3488:13:6;650:16137:0;;;;3515:4:6;650:16137:0;;;1440:3;650:16137;;;;;;;;;;;;;3299:242:6;;650:16137:0;3299:242:6;650:16137:0;;3299:242:6;;;;;;;;:::i;:::-;650:16137:0;3289:253:6;;650:16137:0;3634:119:6;;650:16137:0;;:::i;:::-;;;1440:3;;;3651:65:6;650:16137:0;;;3634:119:6;;;650:16137:0;;;3515:4:6;650:16137:0;;;1440:3;650:16137;;;;;;;3634:119:6;650:16137:0;;;;;;;;3634:119:6;;;;;;;;;:::i;:::-;650:16137:0;3624:130:6;;650:16137:0;3564:195:6;650:16137:0;;3564:195:6;;;;;;;650:16137:0;;;;;;;;;;;;;;;;;;3564:195:6;650:16137:0;3554:206:6;;3237:528;;;3166:67;650:16137:0;;;;;:::i;:::-;3211:22:6;3203:30;;3166:67;;;2679:152;-1:-1:-1;650:16137:0;;2750:2:6;2736:16;2750:2;;650:16137:0;2679:152:6;;2732:94;650:16137:0;;-1:-1:-1;;;2806:20:6;;650:16137:0;2806:20:6;;;650:16137:0;;;;;;;;;;;;;6644:35;597:325:5;756:2;650:16137:0;;771:17:5;650:16137:0;;756:2:5;854:48;;597:325;:::o;650:16137:0:-;;;;-1:-1:-1;;;650:16137:0;;756:2:5;650:16137:0;;;;;;;;;;;;;;;597:325:5;650:16137:0;;;771:17:5;650:16137:0;;;854:48:5;;597:325;:::o;:::-;;756:2;650:16137:0;;;;;;;;;771:17:5;650:16137:0;;854:48:5;756:2;854:48;;;597:325::o
Swarm Source
ipfs://a8465bc3156b7c18a1559d2cc13b7ec13f67e50d2c6eff2767a7be12ae36c2d4
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Token Allocations
FRAX
100.00%
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| FRAXTAL | 100.00% | $0.602398 | 0.000000002514 | <$0.000001 |
Loading...
Loading
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.