Overview
S Balance
0 S
S Value
-More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
411015 | 15 days ago | Contract Creation | 0 S |
Loading...
Loading
Contract Name:
AvoForwarder
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 10000000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity >=0.8.18; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import { IAvoFactory } from "./interfaces/IAvoFactory.sol"; import { IAvoForwarder } from "./interfaces/IAvoForwarder.sol"; import { IAvocadoMultisigV1 } from "./interfaces/IAvocadoMultisigV1.sol"; // empty interface used for Natspec docs for nice layout in automatically generated docs: // /// @title AvoForwarder v1.1.0 /// @notice Handles executing authorized actions (through signatures) at Avocados, triggered by allow-listed broadcasters. /// @dev Only compatible with forwarding `cast` calls to Avocado smart wallet contracts. /// This is not a generic forwarder. /// This is NOT a "TrustedForwarder" as proposed in EIP-2770, see info in Avocado smart wallet contracts. /// /// Does not validate the EIP712 signature (instead this is done in the smart wallet itself). /// /// Upgradeable through AvoForwarderProxy interface AvoForwarder_V1 {} abstract contract AvoForwarderConstants is IAvoForwarder { /// @notice AvoFactory (proxy) used to deploy new Avocado smart wallets. // // @dev If this changes then the deployment addresses for Avocado smart wallets change too. A more complex // system with versioning would have to be implemented then for most methods. IAvoFactory public immutable avoFactory; /// @notice cached Avocado Bytecode to directly compute address in this contract to optimize gas usage. // // @dev If this changes because of an Avocado change (and AvoFactory upgrade), // then this variable must be updated through an upgrade, deploying a new AvoForwarder! bytes32 public constant avocadoBytecode = 0x6b106ae0e3afae21508569f62d81c7d826b900a2e9ccc973ba97abfae026fc54; /// @dev amount of gas to keep in cast caller method as reserve for emitting Executed / ExecuteFailed event. /// ~6920 gas + buffer. the dynamic part is covered with EMIT_EVENT_COST_PER_BYTE (for metadata). uint256 internal constant EVENTS_RESERVE_GAS = 8_500; /// @dev emitting one byte in an event costs 8 byte see https://github.com/wolflo/evm-opcodes/blob/main/gas.md#a8-log-operations uint256 internal constant EMIT_EVENT_COST_PER_BYTE = 8; constructor(IAvoFactory avoFactory_) { avoFactory = avoFactory_; } } abstract contract AvoForwarderVariables is AvoForwarderConstants, Initializable, OwnableUpgradeable { // @dev variables here start at storage slot 101, before is: // - Initializable with storage slot 0: // uint8 private _initialized; // bool private _initializing; // - OwnableUpgradeable with slots 1 to 100: // uint256[50] private __gap; (from ContextUpgradeable, slot 1 until slot 50) // address private _owner; (at slot 51) // uint256[49] private __gap; (slot 52 until slot 100) // ---------------- slot 101 ----------------- /// @notice allowed broadcasters that can call `execute()` methods. allowed if set to `1` mapping(address => uint256) internal _broadcasters; // ---------------- slot 102 ----------------- /// @notice allowed auths. allowed if set to `1` mapping(address => uint256) internal _auths; } abstract contract AvoForwarderErrors { /// @notice thrown when a method is called with invalid params (e.g. zero address) error AvoForwarder__InvalidParams(); /// @notice thrown when a caller is not authorized to execute a certain action error AvoForwarder__Unauthorized(); /// @notice thrown when trying to execute legacy methods for a not yet deployed Avocado smart wallet error AvoForwarder__LegacyVersionNotDeployed(); /// @notice thrown when an unsupported method is called (e.g. renounceOwnership) error AvoForwarder__Unsupported(); } abstract contract AvoForwarderStructs { /// @notice struct mapping an address value to a boolean flag. // // @dev when used as input param, removes need to make sure two input arrays are of same length etc. struct AddressBool { address addr; bool value; } struct ExecuteBatchParams { address from; uint32 index; IAvocadoMultisigV1.CastChainAgnosticParams params; IAvocadoMultisigV1.SignatureParams[] signaturesParams; IAvocadoMultisigV1.ChainAgnosticHash[] chainAgnosticHashes; } struct SimulateBatchResult { uint256 castGasUsed; bool success; string revertReason; } } abstract contract AvoForwarderEvents is AvoForwarderStructs { /// @notice emitted when all actions for `cast()` in an `execute()` method are executed successfully event Executed( address indexed avocadoOwner, uint32 index, address indexed avocadoAddress, address indexed source, bytes metadata ); /// @notice emitted if one of the actions for `cast()` in an `execute()` method fails event ExecuteFailed( address indexed avocadoOwner, uint32 index, address indexed avocadoAddress, address indexed source, bytes metadata, string reason ); /// @notice emitted if a broadcaster's allowed status is updated event BroadcasterUpdated(address indexed broadcaster, bool indexed status); /// @notice emitted if an auth's allowed status is updated event AuthUpdated(address indexed auth, bool indexed status); } abstract contract AvoForwarderCore is AvoForwarderConstants, AvoForwarderVariables, AvoForwarderStructs, AvoForwarderEvents, AvoForwarderErrors { /***********************************| | MODIFIERS | |__________________________________*/ /// @dev checks if `msg.sender` is an allowed broadcaster modifier onlyBroadcaster() { if (_broadcasters[msg.sender] != 1) { revert AvoForwarder__Unauthorized(); } _; } /// @dev checks if an address is not the zero address modifier validAddress(address _address) { if (_address == address(0)) { revert AvoForwarder__InvalidParams(); } _; } /***********************************| | CONSTRUCTOR | |__________________________________*/ constructor(IAvoFactory avoFactory_) validAddress(address(avoFactory_)) AvoForwarderConstants(avoFactory_) { // Ensure logic contract initializer is not abused by disabling initializing // see https://forum.openzeppelin.com/t/security-advisory-initialize-uups-implementation-contracts/15301 // and https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#initializing_the_implementation_contract _disableInitializers(); } /***********************************| | INTERNAL | |__________________________________*/ /// @dev gets or if necessary deploys an Avocado for owner `from_` and `index_` and returns the address function _getDeployedAvocado(address from_, uint32 index_) internal returns (address) { address computedAvocadoAddress_ = _computeAvocado(from_, index_); if (Address.isContract(computedAvocadoAddress_)) { return computedAvocadoAddress_; } else { return avoFactory.deploy(from_, index_); } } /// @dev executes `_getDeployedAvocado` with gas measurements function _getSimulateDeployedAvocado( address from_, uint32 index_ ) internal returns (IAvocadoMultisigV1 avocado_, uint256 deploymentGasUsed_, bool isDeployed_) { if (msg.sender != 0x000000000000000000000000000000000000dEaD) { revert AvoForwarder__Unauthorized(); } uint256 gasSnapshotBefore_ = gasleft(); // `_getDeployedAvocado()` automatically checks if Avocado has to be deployed // or if it already exists and simply returns the address in that case avocado_ = IAvocadoMultisigV1(_getDeployedAvocado(from_, index_)); deploymentGasUsed_ = gasSnapshotBefore_ - gasleft(); isDeployed_ = deploymentGasUsed_ < 100_000; // avocado for sure not yet deployed if gas used > 100k // (deployment costs > 200k) } /// @dev computes the deterministic contract address for an Avocado deployment for `owner_` and `index_` function _computeAvocado(address owner_, uint32 index_) internal view returns (address computedAddress_) { // replicate Create2 address determination logic bytes32 hash = keccak256( abi.encodePacked(bytes1(0xff), address(avoFactory), _getSalt(owner_, index_), avocadoBytecode) ); // cast last 20 bytes of hash to address via low level assembly assembly { computedAddress_ := and(hash, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) } } /// @dev gets the bytes32 salt used for deterministic Avocado deployment for `owner_` and `index_`, same as on AvoFactory function _getSalt(address owner_, uint32 index_) internal pure returns (bytes32) { // use owner + index of avocado nr per EOA (plus "type", currently always 0) // Note CREATE2 deployments take into account the deployers address (i.e. this factory address) return keccak256(abi.encode(owner_, index_, 0)); } /// @dev returns the dynamic reserve gas to be kept back for emitting the Executed or ExecuteFailed event function _dynamicReserveGas(uint256 metadataLength_) internal pure returns (uint256 reserveGas_) { unchecked { // the gas usage for the emitting the CastExecuted/CastFailed events depends on the metadata bytes length, // dynamically calculated with cost per byte for emit event reserveGas_ = EVENTS_RESERVE_GAS + (EMIT_EVENT_COST_PER_BYTE * metadataLength_); } } /// @dev Deploys Avocado for owner if necessary and calls `cast()` on it with given input params. function _executeV1( address from_, uint32 index_, IAvocadoMultisigV1.CastParams calldata params_, IAvocadoMultisigV1.CastForwardParams calldata forwardParams_, IAvocadoMultisigV1.SignatureParams[] calldata signaturesParams_ ) internal returns (bool success_) { // `_getDeployedAvocado()` automatically checks if Avocado has to be deployed // or if it already exists and simply returns the address in that case IAvocadoMultisigV1 avocadoMultisig_ = IAvocadoMultisigV1(_getDeployedAvocado(from_, index_)); string memory revertReason_; (success_, revertReason_) = avocadoMultisig_.cast{ value: forwardParams_.value, // keep back at least enough gas to ensure we can emit events logic below. either calculated reserve gas amount // will be kept back or 1/64th according to EIP150 (whichever is bigger). gas: gasleft() - _dynamicReserveGas(params_.metadata.length) }(params_, forwardParams_, signaturesParams_); // @dev on changes in the code below this point, measure the needed reserve gas via `gasleft()` anew // and update the reserve gas constant amount. // gas measurement currently: ~6920 gas for emit event with max revertReason length if (success_) { emit Executed(from_, index_, address(avocadoMultisig_), params_.source, params_.metadata); } else { emit ExecuteFailed( from_, index_, address(avocadoMultisig_), params_.source, params_.metadata, revertReason_ ); } // @dev ending point for measuring reserve gas should be here. } /// @dev Deploys Avocado for owner if necessary and calls `castChainAgnostic()` on it with given input params. function _executeChainAgnosticV1( address from_, uint32 index_, IAvocadoMultisigV1.CastChainAgnosticParams calldata params_, IAvocadoMultisigV1.SignatureParams[] calldata signaturesParams_, IAvocadoMultisigV1.ChainAgnosticHash[] calldata chainAgnosticHashes_ ) internal returns (bool success_) { // `_getDeployedAvocado()` automatically checks if Avocado has to be deployed // or if it already exists and simply returns the address in that case IAvocadoMultisigV1 avocadoMultisig_ = IAvocadoMultisigV1(_getDeployedAvocado(from_, index_)); string memory revertReason_; (success_, revertReason_) = avocadoMultisig_.castChainAgnostic{ value: params_.forwardParams.value, // keep back at least enough gas to ensure we can emit events logic below. either calculated reserve gas amount // will be kept back or 1/64th according to EIP150 (whichever is bigger). gas: gasleft() - _dynamicReserveGas(params_.params.metadata.length) }( params_, signaturesParams_, chainAgnosticHashes_ ); // @dev on changes below, reserve gas must be updated. see _executeV1. if (success_) { emit Executed(from_, index_, address(avocadoMultisig_), params_.params.source, params_.params.metadata); } else { emit ExecuteFailed( from_, index_, address(avocadoMultisig_), params_.params.source, params_.params.metadata, revertReason_ ); } } } abstract contract AvoForwarderViews is AvoForwarderCore { /// @notice checks if a `broadcaster_` address is an allowed broadcaster function isBroadcaster(address broadcaster_) external view returns (bool) { return _broadcasters[broadcaster_] == 1; } /// @notice checks if an `auth_` address is an allowed auth function isAuth(address auth_) external view returns (bool) { return _auths[auth_] == 1; } } abstract contract AvoForwarderViewsAvocado is AvoForwarderCore { /// @notice Retrieves the current avoNonce of AvocadoMultisig for `owner_` address. /// Needed for building signatures. /// @param owner_ Avocado owner to retrieve the nonce for. /// @param index_ index number of Avocado for `owner_` EOA /// @return returns the avoNonce for the `owner_` necessary to sign a meta transaction function avoNonce(address owner_, uint32 index_) external view returns (uint256) { address avoAddress_ = _computeAvocado(owner_, index_); if (Address.isContract(avoAddress_)) { return IAvocadoMultisigV1(avoAddress_).avoNonce(); } return 0; } /// @notice Retrieves the current AvocadoMultisig implementation name for `owner_` address. /// Needed for building signatures. /// @param owner_ Avocado owner to retrieve the name for. /// @param index_ index number of Avocado for `owner_` EOA /// @return returns the domain separator name for the `owner_` necessary to sign a meta transaction function avocadoVersionName(address owner_, uint32 index_) external view returns (string memory) { address avoAddress_ = _computeAvocado(owner_, index_); if (Address.isContract(avoAddress_)) { // if AvocadoMultisig is deployed, return value from deployed contract return IAvocadoMultisigV1(avoAddress_).DOMAIN_SEPARATOR_NAME(); } // otherwise return default value for current implementation that will be deployed return IAvocadoMultisigV1(avoFactory.avoImpl()).DOMAIN_SEPARATOR_NAME(); } /// @notice Retrieves the current AvocadoMultisig implementation version for `owner_` address. /// Needed for building signatures. /// @param owner_ Avocado owner to retrieve the version for. /// @param index_ index number of Avocado for `owner_` EOA /// @return returns the domain separator version for the `owner_` necessary to sign a meta transaction function avocadoVersion(address owner_, uint32 index_) external view returns (string memory) { address avoAddress_ = _computeAvocado(owner_, index_); if (Address.isContract(avoAddress_)) { // if AvocadoMultisig is deployed, return value from deployed contract return IAvocadoMultisigV1(avoAddress_).DOMAIN_SEPARATOR_VERSION(); } // otherwise return default value for current implementation that will be deployed return IAvocadoMultisigV1(avoFactory.avoImpl()).DOMAIN_SEPARATOR_VERSION(); } /// @notice Computes the deterministic Avocado address for `owner_` and `index_` function computeAvocado(address owner_, uint32 index_) external view returns (address) { if (Address.isContract(owner_)) { // owner of a Avocado must be an EOA, if it's a contract return zero address return address(0); } return _computeAvocado(owner_, index_); } /// @notice returns the hashes struct for each `CastChainAgnosticParams` element of `params_`. The returned array must be /// passed into `castChainAgnostic()` as the param `chainAgnosticHashes_` there (order must be the same). /// The returned hash for each element is the EIP712 type hash for `CAST_CHAIN_AGNOSTIC_PARAMS_TYPE_HASH`, /// as used when the signature digest is built. /// @dev Deploys the Avocado if necessary. Expected to be called with callStatic. function getAvocadoChainAgnosticHashes( address from_, uint32 index_, IAvocadoMultisigV1.CastChainAgnosticParams[] calldata params_ ) external returns (IAvocadoMultisigV1.ChainAgnosticHash[] memory chainAgnosticHashes_) { // `_getDeployedAvocado()` automatically checks if Avocado has to be deployed // or if it already exists and simply returns the address in that case IAvocadoMultisigV1 avocadoMultisig_ = IAvocadoMultisigV1(_getDeployedAvocado(from_, index_)); return avocadoMultisig_.getChainAgnosticHashes(params_); } } abstract contract AvoForwarderV1 is AvoForwarderCore { /// @notice Deploys Avocado for owner if necessary and calls `cast()` on it. /// For Avocado v1. /// Only callable by allowed broadcasters. /// @param from_ Avocado owner /// @param index_ index number of Avocado for `owner_` EOA /// @param params_ Cast params such as id, avoNonce and actions to execute /// @param forwardParams_ Cast params related to validity of forwarding as instructed and signed /// @param signaturesParams_ SignatureParams structs array for signature and signer: /// - signature: the EIP712 signature, 65 bytes ECDSA signature for a default EOA. /// For smart contract signatures it must fulfill the requirements for the relevant /// smart contract `.isValidSignature()` EIP1271 logic /// - signer: address of the signature signer. /// Must match the actual signature signer or refer to the smart contract /// that must be an allowed signer and validates signature via EIP1271 function executeV1( address from_, uint32 index_, IAvocadoMultisigV1.CastParams calldata params_, IAvocadoMultisigV1.CastForwardParams calldata forwardParams_, IAvocadoMultisigV1.SignatureParams[] calldata signaturesParams_ ) external payable onlyBroadcaster { _executeV1(from_, index_, params_, forwardParams_, signaturesParams_); } /// @notice Verify the transaction is valid and can be executed. /// IMPORTANT: Expected to be called via callStatic. /// /// Returns true if valid, reverts otherwise: /// e.g. if input params, signature or avoNonce etc. are invalid. /// @param from_ Avocado owner /// @param index_ index number of Avocado for `owner_` EOA /// @param params_ Cast params such as id, avoNonce and actions to execute /// @param forwardParams_ Cast params related to validity of forwarding as instructed and signed /// @param signaturesParams_ SignatureParams structs array for signature and signer: /// - signature: the EIP712 signature, 65 bytes ECDSA signature for a default EOA. /// For smart contract signatures it must fulfill the requirements for the relevant /// smart contract `.isValidSignature()` EIP1271 logic /// - signer: address of the signature signer. /// Must match the actual signature signer or refer to the smart contract /// that must be an allowed signer and validates signature via EIP1271 /// @return returns true if everything is valid, otherwise reverts. // // @dev can not be marked as view because it does potentially modify state by deploying the // AvocadoMultisig for `from_` if it does not exist yet. Thus expected to be called via callStatic function verifyV1( address from_, uint32 index_, IAvocadoMultisigV1.CastParams calldata params_, IAvocadoMultisigV1.CastForwardParams calldata forwardParams_, IAvocadoMultisigV1.SignatureParams[] calldata signaturesParams_ ) external returns (bool) { // `_getDeployedAvocado()` automatically checks if Avocado has to be deployed // or if it already exists and simply returns the address in that case IAvocadoMultisigV1 avocadoMultisig_ = IAvocadoMultisigV1(_getDeployedAvocado(from_, index_)); return avocadoMultisig_.verify(params_, forwardParams_, signaturesParams_); } } abstract contract AvoForwarderChainAgnosticV1 is AvoForwarderCore { /// @notice Deploys Avocado for owner if necessary and calls `castChainAgnostic()` on it. /// For Avocado v1. /// Only callable by allowed broadcasters. /// @param from_ Avocado owner /// @param index_ index number of Avocado for `owner_` EOA /// @param params_ Chain agnostic params containing CastParams, ForwardParams and chain id. /// Note chain id must match block.chainid. /// @param signaturesParams_ SignatureParams structs array for signature and signer: /// - signature: the EIP712 signature, 65 bytes ECDSA signature for a default EOA. /// For smart contract signatures it must fulfill the requirements for the relevant /// smart contract `.isValidSignature()` EIP1271 logic /// - signer: address of the signature signer. /// Must match the actual signature signer or refer to the smart contract /// that must be an allowed signer and validates signature via EIP1271 /// @param chainAgnosticHashes_ hashes struct for each original `CastChainAgnosticParams` struct as used when signing the /// txs to be executed. Result of `.getChainAgnosticHashes()`. function executeChainAgnosticV1( address from_, uint32 index_, IAvocadoMultisigV1.CastChainAgnosticParams calldata params_, IAvocadoMultisigV1.SignatureParams[] calldata signaturesParams_, IAvocadoMultisigV1.ChainAgnosticHash[] calldata chainAgnosticHashes_ ) external payable onlyBroadcaster { _executeChainAgnosticV1(from_, index_, params_, signaturesParams_, chainAgnosticHashes_); } /// @notice Verify the transaction is a valid chain agnostic tx and can be executed. /// IMPORTANT: Expected to be called via callStatic. /// /// Returns true if valid, reverts otherwise: /// e.g. if input params, signature or avoNonce etc. are invalid. /// @param from_ Avocado owner /// @param index_ index number of Avocado for `owner_` EOA /// @param params_ Chain agnostic params containing CastParams, ForwardParams and chain id. /// Note chain id must match block.chainid. /// @param signaturesParams_ SignatureParams structs array for signature and signer: /// - signature: the EIP712 signature, 65 bytes ECDSA signature for a default EOA. /// For smart contract signatures it must fulfill the requirements for the relevant /// smart contract `.isValidSignature()` EIP1271 logic /// - signer: address of the signature signer. /// Must match the actual signature signer or refer to the smart contract /// that must be an allowed signer and validates signature via EIP1271 /// @param chainAgnosticHashes_ hashes struct for each original `CastChainAgnosticParams` struct as used when signing the /// txs to be executed. Result of `.getChainAgnosticHashes()`. /// @return returns true if everything is valid, otherwise reverts. // // @dev can not be marked as view because it does potentially modify state by deploying the // AvocadoMultisig for `from_` if it does not exist yet. Thus expected to be called via callStatic function verifyChainAgnosticV1( address from_, uint32 index_, IAvocadoMultisigV1.CastChainAgnosticParams calldata params_, IAvocadoMultisigV1.SignatureParams[] calldata signaturesParams_, IAvocadoMultisigV1.ChainAgnosticHash[] calldata chainAgnosticHashes_ ) external returns (bool) { // `_getDeployedAvocado()` automatically checks if Avocado has to be deployed // or if it already exists and simply returns the address in that case IAvocadoMultisigV1 avocadoMultisig_ = IAvocadoMultisigV1(_getDeployedAvocado(from_, index_)); return avocadoMultisig_.verifyChainAgnostic(params_, signaturesParams_, chainAgnosticHashes_); } } abstract contract AvoForwarderBatchV1 is AvoForwarderCore { /// @notice Executes multiple txs as batch. /// For Avocado v1. /// Only callable by allowed broadcasters. /// @param batches_ Execute batch txs array, same as inputs for `executeChainAgnosticV1()` just as struct array. /// If `chainAgnosticHashes` is set (length > 0), then `executeChainAgnosticV1()` is executed, /// otherwise `executeV1()` is executed with the given array element. /// @param continueOnRevert_ flag to signal if one `ExecuteBatchParams` in `batches_` fails, should the rest of them /// still continue to be executed. function executeBatchV1( ExecuteBatchParams[] calldata batches_, bool continueOnRevert_ ) external payable onlyBroadcaster { uint256 length_ = batches_.length; if (length_ < 2) { revert AvoForwarder__InvalidParams(); } bool success_; for (uint256 i; i < length_; ) { if (batches_[i].chainAgnosticHashes.length > 0) { success_ = _executeChainAgnosticV1( batches_[i].from, batches_[i].index, batches_[i].params, batches_[i].signaturesParams, batches_[i].chainAgnosticHashes ); } else { success_ = _executeV1( batches_[i].from, batches_[i].index, batches_[i].params.params, batches_[i].params.forwardParams, batches_[i].signaturesParams ); } if (!success_ && !continueOnRevert_) { break; } unchecked { ++i; } } } } abstract contract AvoForwarderSimulateV1 is AvoForwarderCore { uint256 internal constant SIMULATE_WASTE_GAS_MARGIN = 10; // 10% added in used gas for simulations // @dev helper struct to work around Stack too deep Errors struct SimulationVars { IAvocadoMultisigV1 avocadoMultisig; uint256 initialGas; } /// @dev see `simulateV1()`. Reverts on `success_` = false for accurate .estimateGas() usage. /// Helpful to estimate gas for an Avocado tx. Note: resulting gas usage will usually be /// with at least ~10k gas buffer compared to actual execution. /// For Avocado v1. /// Deploys the Avocado smart wallet if necessary. /// @dev Expected use with `.estimateGas()`. User signed `CastForwardParams.gas` should be set to the estimated /// amount minus gas used in AvoForwarder (until AvocadoMultisig logic where the gas param is validated). function estimateV1( address from_, uint32 index_, IAvocadoMultisigV1.CastParams calldata params_, IAvocadoMultisigV1.CastForwardParams calldata forwardParams_, IAvocadoMultisigV1.SignatureParams[] calldata signaturesParams_ ) external payable { (, , , bool success_, string memory revertReason_) = simulateV1( from_, index_, params_, forwardParams_, signaturesParams_ ); if (!success_) { revert(revertReason_); } } /// @notice Simulates a `executeV1()` tx, callable only by msg.sender = dead address /// (0x000000000000000000000000000000000000dEaD). Useful to determine success / error /// and other return values of `executeV1()` with a `.callstatic`. /// For Avocado v1. /// @dev - set `signaturesParams_` to empty to automatically simulate with required signers length. /// - if `signaturesParams_` first element signature is not set, or if first signer is set to /// 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF, then gas usage burn is simulated /// for verify signature functionality. DO NOT set signature to non-empty for subsequent /// elements then; set all signatures to empty! /// - if `signaturesParams_` is set normally, signatures are verified as in actual execute /// - buffer amounts for mock smart contract signers signature verification must be added /// off-chain as this varies on a case per case basis. /// @param from_ AvocadoMultisig owner /// @param index_ index number of Avocado for `owner_` EOA /// @param params_ Cast params such as id, avoNonce and actions to execute /// @param forwardParams_ Cast params related to validity of forwarding as instructed and signed /// @param signaturesParams_ SignatureParams structs array for signature and signer: /// - signature: the EIP712 signature, 65 bytes ECDSA signature for a default EOA. /// For smart contract signatures it must fulfill the requirements for the relevant /// smart contract `.isValidSignature()` EIP1271 logic /// - signer: address of the signature signer. /// Must match the actual signature signer or refer to the smart contract /// that must be an allowed signer and validates signature via EIP1271 /// @return castGasUsed_ amount of gas used for executing `cast` /// @return deploymentGasUsed_ amount of gas used for deployment (or for getting the contract if already deployed) /// @return isDeployed_ boolean flag indicating if Avocado is already deployed /// @return success_ boolean flag indicating whether executing actions reverts or not /// @return revertReason_ revert reason original error in default format "<action_index>_error" function simulateV1( address from_, uint32 index_, IAvocadoMultisigV1.CastParams calldata params_, IAvocadoMultisigV1.CastForwardParams calldata forwardParams_, IAvocadoMultisigV1.SignatureParams[] calldata signaturesParams_ ) public payable returns ( uint256 castGasUsed_, uint256 deploymentGasUsed_, bool isDeployed_, bool success_, string memory revertReason_ ) { SimulationVars memory vars_; vars_.initialGas = gasleft(); (vars_.avocadoMultisig, deploymentGasUsed_, isDeployed_) = _getSimulateDeployedAvocado(from_, index_); { uint256 gasSnapshotBefore_; bytes32 avoVersion_ = keccak256(bytes(vars_.avocadoMultisig.DOMAIN_SEPARATOR_VERSION())); if (avoVersion_ == keccak256(bytes("1.0.0")) || avoVersion_ == keccak256(bytes("1.0.1"))) { gasSnapshotBefore_ = gasleft(); (success_, revertReason_) = vars_.avocadoMultisig.cast{ value: forwardParams_.value, // keep back at least enough gas to ensure we can emit events logic below. either calculated reserve gas amount // will be kept back or 1/64th according to EIP150 (whichever is bigger). gas: gasleft() - _dynamicReserveGas(params_.metadata.length) }( params_, forwardParams_, signaturesParams_ ); } else { gasSnapshotBefore_ = gasleft(); (success_, revertReason_) = vars_.avocadoMultisig.simulateCast{ value: forwardParams_.value, // keep back at least enough gas to ensure we can emit events logic below. either calculated reserve gas amount // will be kept back or 1/64th according to EIP150 (whichever is bigger). gas: gasleft() - _dynamicReserveGas(params_.metadata.length) }( params_, forwardParams_, signaturesParams_ ); } castGasUsed_ = gasSnapshotBefore_ - gasleft(); } if (success_) { emit Executed(from_, index_, address(vars_.avocadoMultisig), params_.source, params_.metadata); } else { emit ExecuteFailed( from_, index_, address(vars_.avocadoMultisig), params_.source, params_.metadata, revertReason_ ); } _wasteGas(((vars_.initialGas - gasleft()) * SIMULATE_WASTE_GAS_MARGIN) / 100); // e.g. 10% of used gas } /// @dev see `simulateChainAgnosticV1()`. Reverts on `success_` = false for accurate .estimateGas() usage. /// Helpful to estimate gas for an Avocado tx. Note: resulting gas usage will usually be /// with at least ~10k gas buffer compared to actual execution. /// For Avocado v1. /// Deploys the Avocado smart wallet if necessary. /// @dev Expected use with `.estimateGas()`. User signed `CastForwardParams.gas` should be set to the estimated /// amount minus gas used in AvoForwarder (until AvocadoMultisig logic where the gas param is validated). function estimateChainAgnosticV1( address from_, uint32 index_, IAvocadoMultisigV1.CastChainAgnosticParams calldata params_, IAvocadoMultisigV1.SignatureParams[] calldata signaturesParams_, IAvocadoMultisigV1.ChainAgnosticHash[] calldata chainAgnosticHashes_ ) external payable { (, , , bool success_, string memory revertReason_) = simulateChainAgnosticV1( from_, index_, params_, signaturesParams_, chainAgnosticHashes_ ); if (!success_) { revert(revertReason_); } } /// @notice Simulates a `executeChainAgnosticV1()` tx, callable only by msg.sender = dead address /// (0x000000000000000000000000000000000000dEaD). Useful to determine success / error /// and other return values of `executeV1()` with a `.callstatic`. /// For Avocado v1. /// Deploys the Avocado smart wallet if necessary. /// @dev - set `signaturesParams_` to empty to automatically simulate with required signers length. /// - if `signaturesParams_` first element signature is not set, or if first signer is set to /// 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF, then gas usage burn is simulated /// for verify signature functionality. DO NOT set signature to non-empty for subsequent /// elements then; set all signatures to empty! /// - if `signaturesParams_` is set normally, signatures are verified as in actual execute /// - buffer amounts for mock smart contract signers signature verification must be added /// off-chain as this varies on a case per case basis. /// @param from_ Avocado owner /// @param index_ index number of Avocado for `owner_` EOA /// @param params_ Chain agnostic params containing CastParams, ForwardParams and chain id. /// Note chain id must match block.chainid. /// @param signaturesParams_ SignatureParams structs array for signature and signer: /// - signature: the EIP712 signature, 65 bytes ECDSA signature for a default EOA. /// For smart contract signatures it must fulfill the requirements for the relevant /// smart contract `.isValidSignature()` EIP1271 logic /// - signer: address of the signature signer. /// Must match the actual signature signer or refer to the smart contract /// that must be an allowed signer and validates signature via EIP1271 /// @param chainAgnosticHashes_ hashes struct for each original `CastChainAgnosticParams` struct as used when signing the /// txs to be executed. Result of `.getChainAgnosticHashes()`. /// @return castGasUsed_ amount of gas used for executing `cast` /// @return deploymentGasUsed_ amount of gas used for deployment (or for getting the contract if already deployed) /// @return isDeployed_ boolean flag indicating if Avocado is already deployed /// @return success_ boolean flag indicating whether executing actions reverts or not /// @return revertReason_ revert reason original error in default format "<action_index>_error" function simulateChainAgnosticV1( address from_, uint32 index_, IAvocadoMultisigV1.CastChainAgnosticParams calldata params_, IAvocadoMultisigV1.SignatureParams[] calldata signaturesParams_, IAvocadoMultisigV1.ChainAgnosticHash[] calldata chainAgnosticHashes_ ) public payable returns ( uint256 castGasUsed_, uint256 deploymentGasUsed_, bool isDeployed_, bool success_, string memory revertReason_ ) { SimulationVars memory vars_; vars_.initialGas = gasleft(); (vars_.avocadoMultisig, deploymentGasUsed_, isDeployed_) = _getSimulateDeployedAvocado(from_, index_); { uint256 gasSnapshotBefore_ = gasleft(); (success_, revertReason_) = vars_.avocadoMultisig.simulateCastChainAgnostic{ value: params_.forwardParams.value, // keep back at least enough gas to ensure we can emit events logic below. either calculated reserve gas amount // will be kept back or 1/64th according to EIP150 (whichever is bigger). gas: gasleft() - _dynamicReserveGas(params_.params.metadata.length) }(params_, signaturesParams_, chainAgnosticHashes_); castGasUsed_ = gasSnapshotBefore_ - gasleft(); } if (success_) { emit Executed(from_, index_, address(vars_.avocadoMultisig), params_.params.source, params_.params.metadata); } else { emit ExecuteFailed( from_, index_, address(vars_.avocadoMultisig), params_.params.source, params_.params.metadata, revertReason_ ); } _wasteGas(((vars_.initialGas - gasleft()) * SIMULATE_WASTE_GAS_MARGIN) / 100); // e.g. 10% of used gas } /// @notice Simulates a `executeBatchV1()` tx, callable only by msg.sender = dead address /// (0x000000000000000000000000000000000000dEaD) /// Helpful to estimate gas for an Avocado tx. Note: resulting gas usage will usually be /// with at least ~10k gas buffer compared to actual execution. /// For Avocado v1. /// Deploys the Avocado smart wallet if necessary. /// @dev Expected use with `.estimateGas()`. /// Best to combine with a `.callstatic` to determine success / error and other return values of `executeV1()`. /// For indidividual measurements of each `ExecuteBatchParams` execute the respective simulate() single method for it. /// @param batches_ Execute batch txs array, same as inputs for `simulateChainAgnosticV1()` just as struct array. /// @param continueOnRevert_ flag to signal if one `ExecuteBatchParams` in `batches_` fails, should the rest of them /// still continue to be executed. function simulateBatchV1(ExecuteBatchParams[] calldata batches_, bool continueOnRevert_) external payable returns(SimulateBatchResult[] memory results_){ uint256 initialGas_ = gasleft(); uint256 length_ = batches_.length; if (length_ < 2) { revert AvoForwarder__InvalidParams(); } results_ = new SimulateBatchResult[](length_); IAvocadoMultisigV1 avocadoMultisig_; uint256 gasSnapshotBefore_; for (uint256 i; i < length_; ) { (avocadoMultisig_ , , ) = _getSimulateDeployedAvocado(batches_[i].from, batches_[i].index); gasSnapshotBefore_ = gasleft(); if (batches_[i].chainAgnosticHashes.length > 0) { (results_[i].success, results_[i].revertReason) = avocadoMultisig_.simulateCastChainAgnostic{ value: batches_[i].params.forwardParams.value, // keep back at least enough gas to ensure we can emit events logic below. either calculated reserve gas amount // will be kept back or 1/64th according to EIP150 (whichever is bigger). gas: gasleft() - _dynamicReserveGas(batches_[i].params.params.metadata.length) }(batches_[i].params, batches_[i].signaturesParams, batches_[i].chainAgnosticHashes); } else { (results_[i].success, results_[i].revertReason) = avocadoMultisig_.simulateCast{ value: batches_[i].params.forwardParams.value, // keep back at least enough gas to ensure we can emit events logic below. either calculated reserve gas amount // will be kept back or 1/64th according to EIP150 (whichever is bigger). gas: gasleft() - _dynamicReserveGas(batches_[i].params.params.metadata.length) }(batches_[i].params.params, batches_[i].params.forwardParams, batches_[i].signaturesParams); } results_[i].castGasUsed = gasSnapshotBefore_ - gasleft(); if (results_[i].success) { emit Executed( batches_[i].from, batches_[i].index, address(avocadoMultisig_), batches_[i].params.params.source, batches_[i].params.params.metadata ); } else { emit ExecuteFailed( batches_[i].from, batches_[i].index, address(avocadoMultisig_), batches_[i].params.params.source, batches_[i].params.params.metadata, results_[i].revertReason ); } if (!results_[i].success && !continueOnRevert_) { break; } unchecked { ++i; } } _wasteGas(((initialGas_ - gasleft()) * SIMULATE_WASTE_GAS_MARGIN) / 100); // e.g. 10% of used gas } /// @dev uses up `wasteGasAmount_` of gas function _wasteGas(uint256 wasteGasAmount_) internal view { uint256 gasLeft_ = gasleft(); uint256 wasteGasCounter_; while (gasLeft_ - gasleft() < wasteGasAmount_) wasteGasCounter_++; } } abstract contract AvoForwarderOwnerActions is AvoForwarderCore { /// @dev modifier checks if `msg.sender` is either owner or allowed auth, reverts if not. modifier onlyAuthOrOwner() { if (!(msg.sender == owner() || _auths[msg.sender] == 1)) { revert AvoForwarder__Unauthorized(); } _; } /// @notice updates allowed status for broadcasters based on `broadcastersStatus_` and emits `BroadcastersUpdated`. /// Executable by allowed auths or owner only. function updateBroadcasters(AddressBool[] calldata broadcastersStatus_) external onlyAuthOrOwner { uint256 length_ = broadcastersStatus_.length; for (uint256 i; i < length_; ) { if (broadcastersStatus_[i].addr == address(0)) { revert AvoForwarder__InvalidParams(); } _broadcasters[broadcastersStatus_[i].addr] = broadcastersStatus_[i].value ? 1 : 0; emit BroadcasterUpdated(broadcastersStatus_[i].addr, broadcastersStatus_[i].value); unchecked { ++i; } } } /// @notice updates allowed status for a auths based on `authsStatus_` and emits `AuthsUpdated`. /// Executable by allowed auths or owner only (auths can only remove themselves). function updateAuths(AddressBool[] calldata authsStatus_) external onlyAuthOrOwner { uint256 length_ = authsStatus_.length; bool isMsgSenderOwner = msg.sender == owner(); for (uint256 i; i < length_; ) { if (authsStatus_[i].addr == address(0)) { revert AvoForwarder__InvalidParams(); } uint256 setStatus_ = authsStatus_[i].value ? 1 : 0; // if `msg.sender` is auth, then operation must be remove and address to be removed must be auth itself if (!(isMsgSenderOwner || (setStatus_ == 0 && msg.sender == authsStatus_[i].addr))) { revert AvoForwarder__Unauthorized(); } _auths[authsStatus_[i].addr] = setStatus_; emit AuthUpdated(authsStatus_[i].addr, authsStatus_[i].value); unchecked { ++i; } } } } contract AvoForwarder is AvoForwarderCore, AvoForwarderViews, AvoForwarderViewsAvocado, AvoForwarderV1, AvoForwarderChainAgnosticV1, AvoForwarderBatchV1, AvoForwarderSimulateV1, AvoForwarderOwnerActions { /// @notice constructor sets the immutable `avoFactory` (proxy) address and cached bytecodes derived from it constructor(IAvoFactory avoFactory_) AvoForwarderCore(avoFactory_) {} /// @notice initializes the contract, setting `owner_` and initial `allowedBroadcasters_` /// @param owner_ address of owner_ allowed to executed auth limited methods /// @param allowedBroadcasters_ initial list of allowed broadcasters to be enabled right away function initialize( address owner_, address[] calldata allowedBroadcasters_ ) public validAddress(owner_) initializer { _transferOwnership(owner_); // set initial allowed broadcasters uint256 length_ = allowedBroadcasters_.length; for (uint256 i; i < length_; ) { if (allowedBroadcasters_[i] == address(0)) { revert AvoForwarder__InvalidParams(); } _broadcasters[allowedBroadcasters_[i]] = 1; emit BroadcasterUpdated(allowedBroadcasters_[i], true); unchecked { ++i; } } } /// @notice override renounce ownership as it could leave the contract in an unwanted state if called by mistake. function renounceOwnership() public view override onlyOwner { revert AvoForwarder__Unsupported(); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ``` * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized < type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Internal function that returns the initialized version. Returns `_initialized` */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Internal function that returns the initialized version. Returns `_initializing` */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.18; interface AvocadoMultisigStructs { /// @notice a combination of a bytes signature and its signer. struct SignatureParams { /// /// @param signature ECDSA signature of `getSigDigest()` for default flow or EIP1271 smart contract signature bytes signature; /// /// @param signer signer of the signature. Can be set to smart contract address that supports EIP1271 address signer; } /// @notice an arbitrary executable action struct Action { /// /// @param target the target address to execute the action on address target; /// /// @param data the calldata to be passed to the call for each target bytes data; /// /// @param value the msg.value to be passed to the call for each target. set to 0 if none uint256 value; /// /// @param operation type of operation to execute: /// 0 -> .call; 1 -> .delegateCall, 2 -> flashloan (via .call) uint256 operation; } /// @notice common params for both `cast()` and `castAuthorized()` struct CastParams { Action[] actions; /// /// @param id Required: /// id for actions, e.g. 0 = CALL, 1 = MIXED (call and delegatecall), /// 20 = FLASHLOAN_CALL, 21 = FLASHLOAN_MIXED uint256 id; /// /// @param avoNonce Required: /// avoNonce to be used for this tx. Must equal the avoNonce value on smart /// wallet or alternatively it must be set to -1 to use a non-sequential nonce instead int256 avoNonce; /// /// @param salt Optional: /// Salt to customize non-sequential nonce (if `avoNonce` is set to -1) bytes32 salt; /// /// @param source Optional: /// Source / referral for this tx address source; /// /// @param metadata Optional: /// metadata for any potential additional data to be tracked in the tx bytes metadata; } /// @notice `cast()` input params related to forwarding validity struct CastForwardParams { /// /// @param gas Optional: /// As EIP-2770: user instructed minimum amount of gas that the relayer (AvoForwarder) /// must send for the execution. Sending less gas will fail the tx at the cost of the relayer. /// Also protects against potential gas griefing attacks /// See https://ronan.eth.limo/blog/ethereum-gas-dangers/ uint256 gas; /// /// @param gasPrice Optional: /// Not implemented / used yet uint256 gasPrice; /// /// @param validAfter Optional: /// the earliest block timestamp that the request can be forwarded in, /// or 0 if the request is not time-limited to occur after a certain time. /// Protects against relayers executing a certain transaction at an earlier moment /// not intended by the user, where it might have a completely different effect. uint256 validAfter; /// /// @param validUntil Optional: /// Similar to EIP-2770: the latest block timestamp (instead of block number) the request /// can be forwarded, or 0 if request should be valid forever. /// Protects against relayers executing a certain transaction at a later moment /// not intended by the user, where it might have a completely different effect. uint256 validUntil; /// /// @param value Optional: /// Not implemented / used yet (`msg.value` amount the broadcaster should send along) uint256 value; } /// @notice `castAuthorized()` input params struct CastAuthorizedParams { /// /// @param maxFee Optional: /// the maximum Avocado charge-up allowed to be paid for tx execution uint256 maxFee; /// /// @param gasPrice Optional: /// Not implemented / used yet uint256 gasPrice; /// /// @param validAfter Optional: /// the earliest block timestamp that the request can be forwarded in, /// or 0 if the request is not time-limited to occur after a certain time. /// Protects against relayers executing a certain transaction at an earlier moment /// not intended by the user, where it might have a completely different effect. uint256 validAfter; /// /// @param validUntil Optional: /// Similar to EIP-2770: the latest block timestamp (instead of block number) the request /// can be forwarded, or 0 if request should be valid forever. /// Protects against relayers executing a certain transaction at a later moment /// not intended by the user, where it might have a completely different effect. uint256 validUntil; } /// @notice params for `castChainAgnostic()` to be used when casting txs on multiple chains with one signature struct CastChainAgnosticParams { /// /// @param params cast params containing actions to be executed etc. CastParams params; /// /// @param forwardParams params related to forwarding validity CastForwardParams forwardParams; /// /// @param chainId chainId where these actions are valid uint256 chainId; } /// @notice unique chain agnostic hash with chain id to be used for chain agnostic interactions struct ChainAgnosticHash { /// /// @param hash EIP712 type `CAST_CHAIN_AGNOSTIC_PARAMS_TYPE_HASH` hash for one specific `CastChainAgnosticParams` struct bytes32 hash; /// /// @param chainId chainId where this `hash` is for uint256 chainId; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.18; import { AvocadoMultisigStructs } from "../AvocadoMultisig/AvocadoMultisigStructs.sol"; // @dev base interface without getters for storage variables (to avoid overloads issues) interface IAvocadoMultisigV1Base is AvocadoMultisigStructs { /// @notice initializer called by AvoFactory after deployment, sets the `owner_` as the only signer function initialize() external; /// @notice returns the domainSeparator for EIP712 signature function domainSeparatorV4() external view returns (bytes32); /// @notice returns the domainSeparator for EIP712 signature for `castChainAgnostic` function domainSeparatorV4ChainAgnostic() external view returns (bytes32); /// @notice gets the digest (hash) used to verify an EIP712 signature for `cast()`. /// /// This is also used as the non-sequential nonce that will be marked as used when the /// request with the matching `params_` and `forwardParams_` is executed via `cast()`. /// @param params_ Cast params such as id, avoNonce and actions to execute /// @param forwardParams_ Cast params related to validity of forwarding as instructed and signed /// @return bytes32 digest to verify signature (or used as non-sequential nonce) function getSigDigest( CastParams calldata params_, CastForwardParams calldata forwardParams_ ) external view returns (bytes32); /// @notice gets the digest (hash) used to verify an EIP712 signature for `castAuthorized()`. /// /// This is also the non-sequential nonce that will be marked as used when the request /// with the matching `params_` and `authorizedParams_` is executed via `castAuthorized()`. /// @param params_ Cast params such as id, avoNonce and actions to execute /// @param authorizedParams_ Cast params related to authorized execution such as maxFee, as signed /// @return bytes32 digest to verify signature (or used as non-sequential nonce) function getSigDigestAuthorized( CastParams calldata params_, CastAuthorizedParams calldata authorizedParams_ ) external view returns (bytes32); /// @notice Verify the signatures for a `cast()' call are valid and can be executed. /// This does not guarantuee that the tx will not revert, simply that the params are valid. /// Does not revert and returns successfully if the input is valid. /// Reverts if input params, signature or avoNonce etc. are invalid. /// @param params_ Cast params such as id, avoNonce and actions to execute /// @param forwardParams_ Cast params related to validity of forwarding as instructed and signed /// @param signaturesParams_ SignatureParams structs array for signature and signer: /// - signature: the EIP712 signature, 65 bytes ECDSA signature for a default EOA. /// For smart contract signatures it must fulfill the requirements for the relevant /// smart contract `.isValidSignature()` EIP1271 logic /// - signer: address of the signature signer. /// Must match the actual signature signer or refer to the smart contract /// that must be an allowed signer and validates signature via EIP1271 /// @return returns true if everything is valid, otherwise reverts function verify( CastParams calldata params_, CastForwardParams calldata forwardParams_, SignatureParams[] calldata signaturesParams_ ) external view returns (bool); /// @notice Verify the signatures for a `castAuthorized()' call are valid and can be executed. /// This does not guarantuee that the tx will not revert, simply that the params are valid. /// Does not revert and returns successfully if the input is valid. /// Reverts if input params, signature or avoNonce etc. are invalid. /// @param params_ Cast params such as id, avoNonce and actions to execute /// @param authorizedParams_ Cast params related to authorized execution such as maxFee, as signed /// @param signaturesParams_ SignatureParams structs array for signature and signer: /// - signature: the EIP712 signature, 65 bytes ECDSA signature for a default EOA. /// For smart contract signatures it must fulfill the requirements for the relevant /// smart contract `.isValidSignature()` EIP1271 logic /// - signer: address of the signature signer. /// Must match the actual signature signer or refer to the smart contract /// that must be an allowed signer and validates signature via EIP1271 /// @return returns true if everything is valid, otherwise reverts function verifyAuthorized( CastParams calldata params_, CastAuthorizedParams calldata authorizedParams_, SignatureParams[] calldata signaturesParams_ ) external view returns (bool); /// @notice Executes arbitrary actions with valid signatures. Only executable by AvoForwarder. /// If one action fails, the transaction doesn't revert, instead emits the `CastFailed` event. /// In that case, all previous actions are reverted. /// On success, emits CastExecuted event. /// @dev validates EIP712 signature then executes each action via .call or .delegatecall /// @param params_ Cast params such as id, avoNonce and actions to execute /// @param forwardParams_ Cast params related to validity of forwarding as instructed and signed /// @param signaturesParams_ SignatureParams structs array for signature and signer: /// - signature: the EIP712 signature, 65 bytes ECDSA signature for a default EOA. /// For smart contract signatures it must fulfill the requirements for the relevant /// smart contract `.isValidSignature()` EIP1271 logic /// - signer: address of the signature signer. /// Must match the actual signature signer or refer to the smart contract /// that must be an allowed signer and validates signature via EIP1271 /// @return success true if all actions were executed succesfully, false otherwise. /// @return revertReason revert reason if one of the actions fails in the following format: /// The revert reason will be prefixed with the index of the action. /// e.g. if action 1 fails, then the reason will be "1_reason". /// if an action in the flashloan callback fails (or an otherwise nested action), /// it will be prefixed with with two numbers: "1_2_reason". /// e.g. if action 1 is the flashloan, and action 2 of flashloan actions fails, /// the reason will be 1_2_reason. function cast( CastParams calldata params_, CastForwardParams calldata forwardParams_, SignatureParams[] calldata signaturesParams_ ) external payable returns (bool success, string memory revertReason); /// @notice Simulates a `cast()` call with exact same params and execution logic except for: /// - any `gasleft()` use removed to remove potential problems when estimating gas. /// - reverts on param validations removed (verify validity with `verify` instead). /// - signature validation is skipped (must be manually added to gas estimations). /// @dev tx.origin must be dead address, msg.sender must be AvoForwarder. /// @dev - set `signaturesParams_` to empty to automatically simulate with required signers length. /// - if `signaturesParams_` first element signature is not set, or if first signer is set to /// 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF, then gas usage burn is simulated /// for verify signature functionality. DO NOT set signature to non-empty for subsequent /// elements then; set all signatures to empty! /// - if `signaturesParams_` is set normally, signatures are verified as in actual execute /// - buffer amounts for mock smart contract signers signature verification must be added /// off-chain as this varies on a case per case basis. function simulateCast( CastParams calldata params_, CastForwardParams calldata forwardParams_, SignatureParams[] memory signaturesParams_ ) external payable returns (bool success_, string memory revertReason_); /// @notice Exact same as `simulateCast`, just reverts in case of `success_` = false to optimize /// for use with .estimateGas(). function estimateCast( CastParams calldata params_, CastForwardParams calldata forwardParams_, SignatureParams[] memory signaturesParams_ ) external payable returns (bool success_, string memory revertReason_); /// @notice Executes arbitrary actions through authorized transaction sent with valid signatures. /// Includes a fee in native network gas token, amount depends on registry `calcFee()`. /// If one action fails, the transaction doesn't revert, instead emits the `CastFailed` event. /// In that case, all previous actions are reverted. /// On success, emits CastExecuted event. /// @dev executes a .call or .delegateCall for every action (depending on params) /// @param params_ Cast params such as id, avoNonce and actions to execute /// @param authorizedParams_ Cast params related to authorized execution such as maxFee, as signed /// @param signaturesParams_ SignatureParams structs array for signature and signer: /// - signature: the EIP712 signature, 65 bytes ECDSA signature for a default EOA. /// For smart contract signatures it must fulfill the requirements for the relevant /// smart contract `.isValidSignature()` EIP1271 logic /// - signer: address of the signature signer. /// Must match the actual signature signer or refer to the smart contract /// that must be an allowed signer and validates signature via EIP1271 /// @return success true if all actions were executed succesfully, false otherwise. /// @return revertReason revert reason if one of the actions fails in the following format: /// The revert reason will be prefixed with the index of the action. /// e.g. if action 1 fails, then the reason will be "1_reason". /// if an action in the flashloan callback fails (or an otherwise nested action), /// it will be prefixed with with two numbers: "1_2_reason". /// e.g. if action 1 is the flashloan, and action 2 of flashloan actions fails, /// the reason will be 1_2_reason. function castAuthorized( CastParams calldata params_, CastAuthorizedParams calldata authorizedParams_, SignatureParams[] calldata signaturesParams_ ) external payable returns (bool success, string memory revertReason); /// @notice returns the hashes struct for each `CastChainAgnosticParams` element of `params_`. The returned array must be /// passed into `castChainAgnostic()` as the param `chainAgnosticHashes_` there (order must be the same). /// The returned hash for each element is the EIP712 type hash for `CAST_CHAIN_AGNOSTIC_PARAMS_TYPE_HASH`, /// as used when the signature digest is built. function getChainAgnosticHashes( CastChainAgnosticParams[] calldata params_ ) external pure returns (ChainAgnosticHash[] memory chainAgnosticHashes_); /// @notice gets the digest (hash) used to verify an EIP712 signature for `castChainAgnostic()`, /// built from the `CastChainAgnosticParams`. /// /// This is also the non-sequential nonce that will be marked as used when the request /// with the matching `params_` is executed via `castChainAgnostic()`. /// @param params_ Cast params such as id, avoNonce and actions to execute /// @return bytes32 digest to verify signature (or used as non-sequential nonce) function getSigDigestChainAgnostic(CastChainAgnosticParams[] calldata params_) external view returns (bytes32); /// @notice gets the digest (hash) used to verify an EIP712 signature for `castChainAgnostic()`, /// built from the chain agnostic hashes (result of `getChainAgnosticHashes()`). /// /// This is also the non-sequential nonce that will be marked as used when the request /// with the matching `params_` is executed via `castChainAgnostic()`. /// @param chainAgnosticHashes_ EIP712 type hashes of `CAST_CHAIN_AGNOSTIC_PARAMS_TYPE_HASH` for all `CastChainAgnosticParams` /// struct array elements as used when creating the signature. Result of `getChainAgnosticHashes()`. /// must be set in the same order as when creating the signature. /// @return bytes32 digest to verify signature (or used as non-sequential nonce) function getSigDigestChainAgnosticFromHashes( ChainAgnosticHash[] calldata chainAgnosticHashes_ ) external view returns (bytes32); /// @notice Executes arbitrary actions with valid signatures. Only executable by AvoForwarder. /// If one action fails, the transaction doesn't revert, instead emits the `CastFailed` event. /// In that case, all previous actions are reverted. /// On success, emits CastExecuted event. /// @dev validates EIP712 signature then executes each action via .call or .delegatecall /// @param params_ params containing info and intents regarding actions to be executed. Made up of /// same params as for `cast()` plus chain id. /// @param signaturesParams_ SignatureParams structs array for signature and signer: /// - signature: the EIP712 signature, 65 bytes ECDSA signature for a default EOA. /// For smart contract signatures it must fulfill the requirements for the relevant /// smart contract `.isValidSignature()` EIP1271 logic /// - signer: address of the signature signer. /// Must match the actual signature signer or refer to the smart contract /// that must be an allowed signer and validates signature via EIP1271 /// @param chainAgnosticHashes_ EIP712 type hashes of `CAST_CHAIN_AGNOSTIC_PARAMS_TYPE_HASH` for all `CastChainAgnosticParams` /// struct array elements as used when creating the signature. Result of `getChainAgnosticHashes()`. /// must be set in the same order as when creating the signature. /// @return success true if all actions were executed succesfully, false otherwise. /// @return revertReason revert reason if one of the actions fails in the following format: /// The revert reason will be prefixed with the index of the action. /// e.g. if action 1 fails, then the reason will be "1_reason". /// if an action in the flashloan callback fails (or an otherwise nested action), /// it will be prefixed with with two numbers: "1_2_reason". /// e.g. if action 1 is the flashloan, and action 2 of flashloan actions fails, /// the reason will be 1_2_reason. function castChainAgnostic( CastChainAgnosticParams calldata params_, SignatureParams[] memory signaturesParams_, ChainAgnosticHash[] calldata chainAgnosticHashes_ ) external payable returns (bool success, string memory revertReason); /// @notice Simulates a `castChainAgnostic()` call with exact same params and execution logic except for: /// - any `gasleft()` use removed to remove potential problems when estimating gas. /// - reverts on param validations removed (verify validity with `verify` instead). /// - signature validation is skipped (must be manually added to gas estimations). /// @dev tx.origin must be dead address, msg.sender must be AvoForwarder. /// @dev - set `signaturesParams_` to empty to automatically simulate with required signers length. /// - if `signaturesParams_` first element signature is not set, or if first signer is set to /// 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF, then gas usage burn is simulated /// for verify signature functionality. DO NOT set signature to non-empty for subsequent /// elements then; set all signatures to empty! /// - if `signaturesParams_` is set normally, signatures are verified as in actual execute /// - buffer amounts for mock smart contract signers signature verification must be added /// off-chain as this varies on a case per case basis. function simulateCastChainAgnostic( CastChainAgnosticParams calldata params_, SignatureParams[] memory signaturesParams_, ChainAgnosticHash[] calldata chainAgnosticHashes_ ) external payable returns (bool success_, string memory revertReason_); /// @notice Exact same as `simulateCastChainAgnostic`, just reverts in case of `success_` = false to /// optimize for use with .estimateGas(). function estimateCastChainAgnostic( CastChainAgnosticParams calldata params_, SignatureParams[] memory signaturesParams_, ChainAgnosticHash[] calldata chainAgnosticHashes_ ) external payable returns (bool success_, string memory revertReason_); /// @notice Verify the signatures for a `castChainAgnostic()' call are valid and can be executed. /// This does not guarantuee that the tx will not revert, simply that the params are valid. /// Does not revert and returns successfully if the input is valid. /// Reverts if input params, signature or avoNonce etc. are invalid. /// @param params_ params containing info and intents regarding actions to be executed. Made up of /// same params as for `cast()` plus chain id. /// @param signaturesParams_ SignatureParams structs array for signature and signer: /// - signature: the EIP712 signature, 65 bytes ECDSA signature for a default EOA. /// For smart contract signatures it must fulfill the requirements for the relevant /// smart contract `.isValidSignature()` EIP1271 logic /// - signer: address of the signature signer. /// Must match the actual signature signer or refer to the smart contract /// that must be an allowed signer and validates signature via EIP1271 /// @param chainAgnosticHashes_ EIP712 type hashes of `CAST_CHAIN_AGNOSTIC_PARAMS_TYPE_HASH` for all `CastChainAgnosticParams` /// struct array elements as used when creating the signature. Result of `getChainAgnosticHashes()`. /// must be set in the same order as when creating the signature. /// @return returns true if everything is valid, otherwise reverts function verifyChainAgnostic( CastChainAgnosticParams calldata params_, SignatureParams[] calldata signaturesParams_, ChainAgnosticHash[] calldata chainAgnosticHashes_ ) external view returns (bool); /// @notice checks if an address `signer_` is an allowed signer (returns true if allowed) function isSigner(address signer_) external view returns (bool); /// @notice returns allowed signers on Avocado wich can trigger actions if reaching quorum `requiredSigners`. /// signers automatically include owner. function signers() external view returns (address[] memory signers_); /// @notice returns the number of required signers function requiredSigners() external view returns (uint8); /// @notice returns the number of allowed signers function signersCount() external view returns (uint8); /// @notice Avocado owner function owner() external view returns (address); /// @notice Avocado index (number of Avocado for EOA owner) function index() external view returns (uint32); } // @dev full interface with some getters for storage variables interface IAvocadoMultisigV1 is IAvocadoMultisigV1Base { /// @notice Domain separator name for signatures function DOMAIN_SEPARATOR_NAME() external view returns (string memory); /// @notice Domain separator version for signatures function DOMAIN_SEPARATOR_VERSION() external view returns (string memory); /// @notice incrementing nonce for each valid tx executed (to ensure uniqueness) function avoNonce() external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.18; import { IAvoRegistry } from "./IAvoRegistry.sol"; interface IAvoFactory { /// @notice returns AvoRegistry (proxy) address function avoRegistry() external view returns (IAvoRegistry); /// @notice returns Avocado logic contract address that new Avocado deployments point to function avoImpl() external view returns (address); /// @notice Checks if a certain address is an Avocado smart wallet. /// Only works for already deployed wallets. /// @param avoSmartWallet_ address to check /// @return true if address is an Avocado function isAvocado(address avoSmartWallet_) external view returns (bool); /// @notice Computes the deterministic Avocado address for `owner_` based on Create2 /// @param owner_ Avocado owner /// @param index_ index number of Avocado for `owner_` EOA /// @return computedAddress_ computed address for the Avocado contract function computeAvocado(address owner_, uint32 index_) external view returns (address computedAddress_); /// @notice Deploys an Avocado for a certain `owner_` deterministcally using Create2. /// Does not check if contract at address already exists (AvoForwarder does that) /// @param owner_ Avocado owner /// @param index_ index number of Avocado for `owner_` EOA /// @return deployed address for the Avocado contract function deploy(address owner_, uint32 index_) external returns (address); /// @notice Deploys an Avocado with non-default version for an `owner_` /// deterministcally using Create2. /// Does not check if contract at address already exists (AvoForwarder does that) /// @param owner_ Avocado owner /// @param index_ index number of Avocado for `owner_` EOA /// @param avoVersion_ Version of Avocado logic contract to deploy /// @return deployed address for the Avocado contract function deployWithVersion(address owner_, uint32 index_, address avoVersion_) external returns (address); /// @notice registry can update the current Avocado implementation contract set as default /// `_avoImpl` logic contract address for new deployments /// @param avoImpl_ the new avoImpl address function setAvoImpl(address avoImpl_) external; /// @notice returns the bytecode (hash) for the Avocado contract used for Create2 address computation function avocadoBytecode() external view returns (bytes32); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.18; import { IAvoFactory } from "./IAvoFactory.sol"; interface IAvoForwarder { /// @notice returns the AvoFactory (proxy) address function avoFactory() external view returns (IAvoFactory); }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.18; interface IAvoFeeCollector { /// @notice fee config params used to determine the fee for Avocado smart wallet `castAuthorized()` calls struct FeeConfig { /// /// @param feeCollector address that the fee should be paid to address payable feeCollector; /// /// @param mode current fee mode: 0 = percentage fee (gas cost markup); 1 = static fee (better for L2) uint8 mode; /// /// @param fee current fee amount: /// - for mode percentage: fee in 1e6 percentage (1e8 = 100%, 1e6 = 1%) /// - for static mode: absolute amount in native gas token to charge /// (max value 30_9485_009,821345068724781055 in 1e18) uint88 fee; } /// @notice calculates the `feeAmount_` for an Avocado (`msg.sender`) transaction `gasUsed_` based on /// fee configuration present on the contract /// @param gasUsed_ amount of gas used, required if mode is percentage. not used if mode is static fee. /// @return feeAmount_ calculated fee amount to be paid /// @return feeCollector_ address to send the fee to function calcFee(uint256 gasUsed_) external view returns (uint256 feeAmount_, address payable feeCollector_); } interface IAvoRegistry is IAvoFeeCollector { /// @notice checks if an address is listed as allowed AvoForwarder version, reverts if not. /// @param avoForwarderVersion_ address of the AvoForwarder logic contract to check function requireValidAvoForwarderVersion(address avoForwarderVersion_) external view; /// @notice checks if an address is listed as allowed Avocado version, reverts if not. /// @param avoVersion_ address of the Avocado logic contract to check function requireValidAvoVersion(address avoVersion_) external view; }
{ "optimizer": { "enabled": true, "runs": 10000000 }, "libraries": {}, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IAvoFactory","name":"avoFactory_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AvoForwarder__InvalidParams","type":"error"},{"inputs":[],"name":"AvoForwarder__LegacyVersionNotDeployed","type":"error"},{"inputs":[],"name":"AvoForwarder__Unauthorized","type":"error"},{"inputs":[],"name":"AvoForwarder__Unsupported","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"auth","type":"address"},{"indexed":true,"internalType":"bool","name":"status","type":"bool"}],"name":"AuthUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"broadcaster","type":"address"},{"indexed":true,"internalType":"bool","name":"status","type":"bool"}],"name":"BroadcasterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"avocadoOwner","type":"address"},{"indexed":false,"internalType":"uint32","name":"index","type":"uint32"},{"indexed":true,"internalType":"address","name":"avocadoAddress","type":"address"},{"indexed":true,"internalType":"address","name":"source","type":"address"},{"indexed":false,"internalType":"bytes","name":"metadata","type":"bytes"},{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"ExecuteFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"avocadoOwner","type":"address"},{"indexed":false,"internalType":"uint32","name":"index","type":"uint32"},{"indexed":true,"internalType":"address","name":"avocadoAddress","type":"address"},{"indexed":true,"internalType":"address","name":"source","type":"address"},{"indexed":false,"internalType":"bytes","name":"metadata","type":"bytes"}],"name":"Executed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"avoFactory","outputs":[{"internalType":"contract IAvoFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"}],"name":"avoNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"avocadoBytecode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"}],"name":"avocadoVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"}],"name":"avocadoVersionName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"}],"name":"computeAvocado","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"},{"components":[{"components":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"operation","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.Action[]","name":"actions","type":"tuple[]"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"int256","name":"avoNonce","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"source","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"internalType":"struct AvocadoMultisigStructs.CastParams","name":"params","type":"tuple"},{"components":[{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastForwardParams","name":"forwardParams","type":"tuple"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastChainAgnosticParams","name":"params_","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct AvocadoMultisigStructs.SignatureParams[]","name":"signaturesParams_","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.ChainAgnosticHash[]","name":"chainAgnosticHashes_","type":"tuple[]"}],"name":"estimateChainAgnosticV1","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"},{"components":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"operation","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.Action[]","name":"actions","type":"tuple[]"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"int256","name":"avoNonce","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"source","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"internalType":"struct AvocadoMultisigStructs.CastParams","name":"params_","type":"tuple"},{"components":[{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastForwardParams","name":"forwardParams_","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct AvocadoMultisigStructs.SignatureParams[]","name":"signaturesParams_","type":"tuple[]"}],"name":"estimateV1","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint32","name":"index","type":"uint32"},{"components":[{"components":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"operation","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.Action[]","name":"actions","type":"tuple[]"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"int256","name":"avoNonce","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"source","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"internalType":"struct AvocadoMultisigStructs.CastParams","name":"params","type":"tuple"},{"components":[{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastForwardParams","name":"forwardParams","type":"tuple"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastChainAgnosticParams","name":"params","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct AvocadoMultisigStructs.SignatureParams[]","name":"signaturesParams","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.ChainAgnosticHash[]","name":"chainAgnosticHashes","type":"tuple[]"}],"internalType":"struct AvoForwarderStructs.ExecuteBatchParams[]","name":"batches_","type":"tuple[]"},{"internalType":"bool","name":"continueOnRevert_","type":"bool"}],"name":"executeBatchV1","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"},{"components":[{"components":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"operation","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.Action[]","name":"actions","type":"tuple[]"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"int256","name":"avoNonce","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"source","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"internalType":"struct AvocadoMultisigStructs.CastParams","name":"params","type":"tuple"},{"components":[{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastForwardParams","name":"forwardParams","type":"tuple"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastChainAgnosticParams","name":"params_","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct AvocadoMultisigStructs.SignatureParams[]","name":"signaturesParams_","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.ChainAgnosticHash[]","name":"chainAgnosticHashes_","type":"tuple[]"}],"name":"executeChainAgnosticV1","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"},{"components":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"operation","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.Action[]","name":"actions","type":"tuple[]"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"int256","name":"avoNonce","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"source","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"internalType":"struct AvocadoMultisigStructs.CastParams","name":"params_","type":"tuple"},{"components":[{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastForwardParams","name":"forwardParams_","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct AvocadoMultisigStructs.SignatureParams[]","name":"signaturesParams_","type":"tuple[]"}],"name":"executeV1","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"},{"components":[{"components":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"operation","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.Action[]","name":"actions","type":"tuple[]"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"int256","name":"avoNonce","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"source","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"internalType":"struct AvocadoMultisigStructs.CastParams","name":"params","type":"tuple"},{"components":[{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastForwardParams","name":"forwardParams","type":"tuple"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastChainAgnosticParams[]","name":"params_","type":"tuple[]"}],"name":"getAvocadoChainAgnosticHashes","outputs":[{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.ChainAgnosticHash[]","name":"chainAgnosticHashes_","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address[]","name":"allowedBroadcasters_","type":"address[]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"auth_","type":"address"}],"name":"isAuth","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"broadcaster_","type":"address"}],"name":"isBroadcaster","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint32","name":"index","type":"uint32"},{"components":[{"components":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"operation","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.Action[]","name":"actions","type":"tuple[]"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"int256","name":"avoNonce","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"source","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"internalType":"struct AvocadoMultisigStructs.CastParams","name":"params","type":"tuple"},{"components":[{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastForwardParams","name":"forwardParams","type":"tuple"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastChainAgnosticParams","name":"params","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct AvocadoMultisigStructs.SignatureParams[]","name":"signaturesParams","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.ChainAgnosticHash[]","name":"chainAgnosticHashes","type":"tuple[]"}],"internalType":"struct AvoForwarderStructs.ExecuteBatchParams[]","name":"batches_","type":"tuple[]"},{"internalType":"bool","name":"continueOnRevert_","type":"bool"}],"name":"simulateBatchV1","outputs":[{"components":[{"internalType":"uint256","name":"castGasUsed","type":"uint256"},{"internalType":"bool","name":"success","type":"bool"},{"internalType":"string","name":"revertReason","type":"string"}],"internalType":"struct AvoForwarderStructs.SimulateBatchResult[]","name":"results_","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"},{"components":[{"components":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"operation","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.Action[]","name":"actions","type":"tuple[]"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"int256","name":"avoNonce","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"source","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"internalType":"struct AvocadoMultisigStructs.CastParams","name":"params","type":"tuple"},{"components":[{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastForwardParams","name":"forwardParams","type":"tuple"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastChainAgnosticParams","name":"params_","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct AvocadoMultisigStructs.SignatureParams[]","name":"signaturesParams_","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.ChainAgnosticHash[]","name":"chainAgnosticHashes_","type":"tuple[]"}],"name":"simulateChainAgnosticV1","outputs":[{"internalType":"uint256","name":"castGasUsed_","type":"uint256"},{"internalType":"uint256","name":"deploymentGasUsed_","type":"uint256"},{"internalType":"bool","name":"isDeployed_","type":"bool"},{"internalType":"bool","name":"success_","type":"bool"},{"internalType":"string","name":"revertReason_","type":"string"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"},{"components":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"operation","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.Action[]","name":"actions","type":"tuple[]"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"int256","name":"avoNonce","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"source","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"internalType":"struct AvocadoMultisigStructs.CastParams","name":"params_","type":"tuple"},{"components":[{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastForwardParams","name":"forwardParams_","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct AvocadoMultisigStructs.SignatureParams[]","name":"signaturesParams_","type":"tuple[]"}],"name":"simulateV1","outputs":[{"internalType":"uint256","name":"castGasUsed_","type":"uint256"},{"internalType":"uint256","name":"deploymentGasUsed_","type":"uint256"},{"internalType":"bool","name":"isDeployed_","type":"bool"},{"internalType":"bool","name":"success_","type":"bool"},{"internalType":"string","name":"revertReason_","type":"string"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bool","name":"value","type":"bool"}],"internalType":"struct AvoForwarderStructs.AddressBool[]","name":"authsStatus_","type":"tuple[]"}],"name":"updateAuths","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"bool","name":"value","type":"bool"}],"internalType":"struct AvoForwarderStructs.AddressBool[]","name":"broadcastersStatus_","type":"tuple[]"}],"name":"updateBroadcasters","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"},{"components":[{"components":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"operation","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.Action[]","name":"actions","type":"tuple[]"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"int256","name":"avoNonce","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"source","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"internalType":"struct AvocadoMultisigStructs.CastParams","name":"params","type":"tuple"},{"components":[{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastForwardParams","name":"forwardParams","type":"tuple"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastChainAgnosticParams","name":"params_","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct AvocadoMultisigStructs.SignatureParams[]","name":"signaturesParams_","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint256","name":"chainId","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.ChainAgnosticHash[]","name":"chainAgnosticHashes_","type":"tuple[]"}],"name":"verifyChainAgnosticV1","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"},{"components":[{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"operation","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.Action[]","name":"actions","type":"tuple[]"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"int256","name":"avoNonce","type":"int256"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"source","type":"address"},{"internalType":"bytes","name":"metadata","type":"bytes"}],"internalType":"struct AvocadoMultisigStructs.CastParams","name":"params_","type":"tuple"},{"components":[{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"gasPrice","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validUntil","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct AvocadoMultisigStructs.CastForwardParams","name":"forwardParams_","type":"tuple"},{"components":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address","name":"signer","type":"address"}],"internalType":"struct AvocadoMultisigStructs.SignatureParams[]","name":"signaturesParams_","type":"tuple[]"}],"name":"verifyV1","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b506040516200492d3803806200492d83398101604081905262000034916200013a565b6001600160a01b0381166080819052819081906200006557604051637bb8c4fb60e01b815260040160405180910390fd5b6200006f62000078565b5050506200016c565b600054610100900460ff1615620000e55760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116101562000138576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6000602082840312156200014d57600080fd5b81516001600160a01b03811681146200016557600080fd5b9392505050565b60805161476d620001c06000396000818161048001528181610a7e01528181610b9101528181610db101528181610e7601528181610fc40152818161241201528181612ee90152612fdb015261476d6000f3fe6080604052600436106101965760003560e01c8063700742eb116100e1578063ad9ddf171161008a578063d817a8c911610064578063d817a8c9146104b5578063d99f5d3a146104d5578063db421487146104f5578063f2fde38b1461052957600080fd5b8063ad9ddf171461045b578063b0c5ea881461046e578063c5e15557146104a257600080fd5b806378853bb5116100bb57806378853bb5146103a95780638da5cb5b146103ef578063946d92041461043b57600080fd5b8063700742eb14610361578063715018a614610381578063715b9fdc1461039657600080fd5b806355ecef671161014357806368626d8f1161011d57806368626d8f1461030a57806369d12c3a1461032e5780636d85c65f1461034e57600080fd5b806355ecef67146102a95780635868e124146102c957806359e727eb146102f757600080fd5b80633f66feff116101745780633f66feff1461024757806340be24e9146102695780634ad446881461029657600080fd5b8063139203eb1461019b57806322917a0c146101d15780632520e7ff14610201575b600080fd5b3480156101a757600080fd5b506101bb6101b63660046136ae565b610549565b6040516101c89190613711565b60405180910390f35b3480156101dd57600080fd5b506101f16101ec366004613760565b61061b565b60405190151581526020016101c8565b34801561020d57600080fd5b506101f161021c366004613833565b73ffffffffffffffffffffffffffffffffffffffff1660009081526066602052604090205460011490565b34801561025357600080fd5b50610267610262366004613895565b6106d0565b005b34801561027557600080fd5b506102896102843660046138d7565b6109e5565b6040516101c8919061397a565b6102676102a4366004613760565b610cb8565b3480156102b557600080fd5b506102896102c43660046138d7565b610d18565b3480156102d557600080fd5b506102e96102e43660046138d7565b610f4d565b6040519081526020016101c8565b610267610305366004613760565b6110d7565b61031d610318366004613760565b61113b565b6040516101c895949392919061398d565b34801561033a57600080fd5b506101f16103493660046139c7565b611665565b61026761035c3660046139c7565b61171d565b34801561036d57600080fd5b5061026761037c366004613895565b61177a565b34801561038d57600080fd5b5061026761199a565b6102676103a4366004613a95565b6119d4565b3480156103b557600080fd5b506101f16103c4366004613833565b73ffffffffffffffffffffffffffffffffffffffff1660009081526065602052604090205460011490565b3480156103fb57600080fd5b5060335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c8565b34801561044757600080fd5b50610267610456366004613aec565b611ce2565b61031d6104693660046139c7565b612011565b34801561047a57600080fd5b506104167f000000000000000000000000000000000000000000000000000000000000000081565b6102676104b03660046139c7565b61231b565b3480156104c157600080fd5b506104166104d03660046138d7565b612373565b6104e86104e3366004613a95565b6124ac565b6040516101c89190613b41565b34801561050157600080fd5b506102e97f6b106ae0e3afae21508569f62d81c7d826b900a2e9ccc973ba97abfae026fc5481565b34801561053557600080fd5b50610267610544366004613833565b612dbb565b606060006105578686612e72565b6040517f8449b2c900000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690638449b2c9906105ae9087908790600401613ed9565b600060405180830381865afa1580156105cb573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610611919081019061401f565b9695505050505050565b6000806106288888612e72565b6040517f2a4bf79400000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690632a4bf7949061068390899089908990899060040161419b565b602060405180830381865afa1580156106a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106c491906141f9565b98975050505050505050565b60335473ffffffffffffffffffffffffffffffffffffffff163314806107055750336000908152606660205260409020546001145b61073b576040517f7a3acd8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600061075d60335473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905060005b828110156109de5760008585838181106107ac576107ac614216565b6107c29260206040909202019081019150613833565b73ffffffffffffffffffffffffffffffffffffffff160361080f576040517f7bb8c4fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085858381811061082357610823614216565b905060400201602001602081019061083b9190614245565b610846576000610849565b60015b60ff16905082806108b55750801580156108b5575085858381811061087057610870614216565b6108869260206040909202019081019150613833565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b6108eb576040517f7a3acd8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806066600088888681811061090257610902614216565b6109189260206040909202019081019150613833565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205585858381811061095157610951614216565b90506040020160200160208101906109699190614245565b151586868481811061097d5761097d614216565b6109939260206040909202019081019150613833565b73ffffffffffffffffffffffffffffffffffffffff167fbce29f3c87027a39c8405b00ac40728d467fc8f800c6bbfbb37db8f3380400be60405160405180910390a350600101610790565b5050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff84811660208084019190915263ffffffff85168385015260006060808501919091528451808503820181526080850186528051908301207fff0000000000000000000000000000000000000000000000000000000000000060a08601527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000831b1660a186015260b58501527f6b106ae0e3afae21508569f62d81c7d826b900a2e9ccc973ba97abfae026fc5460d5808601919091528551808603909101815260f5909401909452825192019190912016803b15610b8f578073ffffffffffffffffffffffffffffffffffffffff166387265c956040518163ffffffff1660e01b8152600401600060405180830381865afa158015610b41573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610b8791908101906142ec565b915050610cb2565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166328807b8b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1e9190614321565b73ffffffffffffffffffffffffffffffffffffffff166387265c956040518163ffffffff1660e01b8152600401600060405180830381865afa158015610c68573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610cae91908101906142ec565b9150505b92915050565b33600090815260656020526040902054600114610d01576040517f7a3acd8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d0f868686868686613048565b50505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff84811660208084019190915263ffffffff85168385015260006060808501919091528451808503820181526080850186528051908301207fff0000000000000000000000000000000000000000000000000000000000000060a08601527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000831b1660a186015260b58501527f6b106ae0e3afae21508569f62d81c7d826b900a2e9ccc973ba97abfae026fc5460d5808601919091528551808603909101815260f5909401909452825192019190912016803b15610e74578073ffffffffffffffffffffffffffffffffffffffff1663b4907ddc6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610b41573d6000803e3d6000fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166328807b8b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610edf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f039190614321565b73ffffffffffffffffffffffffffffffffffffffff1663b4907ddc6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610c68573d6000803e3d6000fd5b6040805173ffffffffffffffffffffffffffffffffffffffff84811660208084019190915263ffffffff851683850152600060608085018290528551808603820181526080860187528051908401207fff0000000000000000000000000000000000000000000000000000000000000060a08701527f000000000000000000000000000000000000000000000000000000000000000090911b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a186015260b58501527f6b106ae0e3afae21508569f62d81c7d826b900a2e9ccc973ba97abfae026fc5460d5808601919091528551808603909101815260f5909401909452825192019190912016803b156110cd578073ffffffffffffffffffffffffffffffffffffffff1663bda443316040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110a9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b87919061433e565b5060009392505050565b6000806110e888888888888861113b565b945094505050508161113157806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611128919061397a565b60405180910390fd5b5050505050505050565b60008060008060606111766040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b5a60208201526111868c8c613278565b73ffffffffffffffffffffffffffffffffffffffff909216808452604080517fb4907ddc0000000000000000000000000000000000000000000000000000000081529051929850929650600092839263b4907ddc9160048082019286929091908290030181865afa1580156111ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261124591908101906142ec565b805160209182012060408051808201909152600581527f312e302e3000000000000000000000000000000000000000000000000000000092019190915290507f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c811480611306575060408051808201909152600581527f312e302e310000000000000000000000000000000000000000000000000000006020909101527ffc7f6d936935ae6385924f29da7af79e941070dafe46831a51595892abc1b97a81145b156113f1575a9150826000015173ffffffffffffffffffffffffffffffffffffffff16639428ae4e8c608001356113528f8060a001906113469190614357565b60080261213401919050565b5a61135d91906143eb565b908f8f8f8f6040518763ffffffff1660e01b8152600401611381949392919061419b565b600060405180830381858988f115801561139f573d6000803e3d6000fd5b5050505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526113e791908101906143fe565b90955093506114c7565b5a9150826000015173ffffffffffffffffffffffffffffffffffffffff16638142d4018c6080013561142c8f8060a001906113469190614357565b5a61143791906143eb565b908f8f8f8f6040518763ffffffff1660e01b815260040161145b949392919061419b565b600060405180830381858988f1158015611479573d6000803e3d6000fd5b5050505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114c191908101906143fe565b90955093505b5a6114d290836143eb565b975050508215611582576114ec60a08b0160808c01613833565b73ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff167fdaf1e6e151973de199f3ea25b9c6a7c3d94299dc85e269cfd20e48e517ecf7048e8e8060a001906115669190614357565b6040516115759392919061444f565b60405180910390a4611626565b61159260a08b0160808c01613833565b73ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff167f5350e8e0c8cacf19dd5334174c3d5a3e8b7d7e00fdb5457d7ddec04b5e4a1af38e8e8060a0019061160c9190614357565b8860405161161d9493929190614478565b60405180910390a45b6116566064600a5a846020015161163d91906143eb565b61164791906144aa565b61165191906144c1565b6132e5565b50965096509650965096915050565b6000806116728989612e72565b6040517f0f0bc51500000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690630f0bc515906116cf908a908a908a908a908a906004016144fc565b602060405180830381865afa1580156116ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171091906141f9565b9998505050505050505050565b60008061172f89898989898989612011565b945094505050508161176f57806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611128919061397a565b505050505050505050565b60335473ffffffffffffffffffffffffffffffffffffffff163314806117af5750336000908152606660205260409020546001145b6117e5576040517f7a3acd8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060005b8181101561199457600084848381811061180557611805614216565b61181b9260206040909202019081019150613833565b73ffffffffffffffffffffffffffffffffffffffff1603611868576040517f7bb8c4fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83838281811061187a5761187a614216565b90506040020160200160208101906118929190614245565b61189d5760006118a0565b60015b60ff16606560008686858181106118b9576118b9614216565b6118cf9260206040909202019081019150613833565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205583838281811061190857611908614216565b90506040020160200160208101906119209190614245565b151584848381811061193457611934614216565b61194a9260206040909202019081019150613833565b73ffffffffffffffffffffffffffffffffffffffff167f8e37ce4bd982978769e6e23562ee5a1c223c57e867089adf19509e1e4c6e8eed60405160405180910390a36001016117e9565b50505050565b6119a2613316565b6040517f956cbbf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260656020526040902054600114611a1d576040517f7a3acd8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816002811015611a59576040517f7bb8c4fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b82811015611cda576000868683818110611a7957611a79614216565b9050602002810190611a8b919061456e565b611a999060808101906145ac565b90501115611bad57611ba6868683818110611ab657611ab6614216565b9050602002810190611ac8919061456e565b611ad6906020810190613833565b878784818110611ae857611ae8614216565b9050602002810190611afa919061456e565b611b0b906040810190602001614614565b888885818110611b1d57611b1d614216565b9050602002810190611b2f919061456e565b611b3d90604081019061462f565b898986818110611b4f57611b4f614216565b9050602002810190611b61919061456e565b611b6f906060810190614663565b8b8b88818110611b8157611b81614216565b9050602002810190611b93919061456e565b611ba19060808101906145ac565b613399565b9150611cc2565b611cbf868683818110611bc257611bc2614216565b9050602002810190611bd4919061456e565b611be2906020810190613833565b878784818110611bf457611bf4614216565b9050602002810190611c06919061456e565b611c17906040810190602001614614565b888885818110611c2957611c29614216565b9050602002810190611c3b919061456e565b611c4990604081019061462f565b611c5390806146cb565b898986818110611c6557611c65614216565b9050602002810190611c77919061456e565b611c8590604081019061462f565b6020018a8a87818110611c9a57611c9a614216565b9050602002810190611cac919061456e565b611cba906060810190614663565b613048565b91505b81158015611cce575083155b611cda57600101611a5d565b505050505050565b8273ffffffffffffffffffffffffffffffffffffffff8116611d30576040517f7bb8c4fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff1615808015611d505750600054600160ff909116105b80611d6a5750303b158015611d6a575060005460ff166001145b611df6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401611128565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611e5457600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b611e5d856135a5565b8260005b81811015611fa6576000868683818110611e7d57611e7d614216565b9050602002016020810190611e929190613833565b73ffffffffffffffffffffffffffffffffffffffff1603611edf576040517f7bb8c4fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160656000888885818110611ef757611ef7614216565b9050602002016020810190611f0c9190613833565b73ffffffffffffffffffffffffffffffffffffffff1681526020810191909152604001600020556001868683818110611f4757611f47614216565b9050602002016020810190611f5c9190613833565b73ffffffffffffffffffffffffffffffffffffffff167f8e37ce4bd982978769e6e23562ee5a1c223c57e867089adf19509e1e4c6e8eed60405160405180910390a3600101611e61565b505080156109de57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050565b600080600080606061204c6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b5a602082015261205c8d8d613278565b73ffffffffffffffffffffffffffffffffffffffff90921683529550935060005a9050816000015173ffffffffffffffffffffffffffffffffffffffff1663aecd4fb48d602001608001356120c88f80600001906120ba91906146cb565b6113469060a0810190614357565b5a6120d391906143eb565b908f8f8f8f8f6040518863ffffffff1660e01b81526004016120f99594939291906144fc565b600060405180830381858988f1158015612117573d6000803e3d6000fd5b5050505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261215f91908101906143fe565b90945092505a61216f90826143eb565b9650508215612237576121828b806146cb565b6121939060a0810190608001613833565b73ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff167fdaf1e6e151973de199f3ea25b9c6a7c3d94299dc85e269cfd20e48e517ecf7048f8f806000019061220d91906146cb565b61221b9060a0810190614357565b60405161222a9392919061444f565b60405180910390a46122f4565b6122418b806146cb565b6122529060a0810190608001613833565b73ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff167f5350e8e0c8cacf19dd5334174c3d5a3e8b7d7e00fdb5457d7ddec04b5e4a1af38f8f80600001906122cc91906146cb565b6122da9060a0810190614357565b886040516122eb9493929190614478565b60405180910390a45b61230b6064600a5a846020015161163d91906143eb565b5097509750975097509792505050565b33600090815260656020526040902054600114612364576040517f7a3acd8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61113187878787878787613399565b600073ffffffffffffffffffffffffffffffffffffffff83163b1561239a57506000610cb2565b6040805173ffffffffffffffffffffffffffffffffffffffff80861660208084019190915263ffffffff86168385015260006060808501919091528451808503820181526080850186528051908301207fff0000000000000000000000000000000000000000000000000000000000000060a08601527f000000000000000000000000000000000000000000000000000000000000000090911b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a185015260b58401527f6b106ae0e3afae21508569f62d81c7d826b900a2e9ccc973ba97abfae026fc5460d5808501919091528451808503909101815260f590930190935281519190920120165b9392505050565b606060005a90508360028110156124ef576040517f7bb8c4fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff81111561250857612508613f78565b60405190808252806020026020018201604052801561255557816020015b604080516060808201835260008083526020830152918101919091528152602001906001900390816125265790505b50925060008060005b83811015612d9d576125d589898381811061257b5761257b614216565b905060200281019061258d919061456e565b61259b906020810190613833565b8a8a848181106125ad576125ad614216565b90506020028101906125bf919061456e565b6125d0906040810190602001614614565b613278565b50909350505a915060008989838181106125f1576125f1614216565b9050602002810190612603919061456e565b6126119060808101906145ac565b9050111561281e578273ffffffffffffffffffffffffffffffffffffffff1663aecd4fb48a8a8481811061264757612647614216565b9050602002810190612659919061456e565b61266790604081019061462f565b60a001356126aa8c8c8681811061268057612680614216565b9050602002810190612692919061456e565b6126a090604081019061462f565b6120ba90806146cb565b5a6126b591906143eb565b908c8c868181106126c8576126c8614216565b90506020028101906126da919061456e565b6126e890604081019061462f565b8d8d878181106126fa576126fa614216565b905060200281019061270c919061456e565b61271a906060810190614663565b8f8f8981811061272c5761272c614216565b905060200281019061273e919061456e565b61274c9060808101906145ac565b6040518863ffffffff1660e01b815260040161276c9594939291906144fc565b600060405180830381858988f115801561278a573d6000803e3d6000fd5b5050505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526127d291908101906143fe565b8783815181106127e4576127e4614216565b602002602001015160200188848151811061280157612801614216565b602002602001015160400182905282151515158152505050612a01565b8273ffffffffffffffffffffffffffffffffffffffff16638142d4018a8a8481811061284c5761284c614216565b905060200281019061285e919061456e565b61286c90604081019061462f565b60a001356128858c8c8681811061268057612680614216565b5a61289091906143eb565b908c8c868181106128a3576128a3614216565b90506020028101906128b5919061456e565b6128c390604081019061462f565b6128cd90806146cb565b8d8d878181106128df576128df614216565b90506020028101906128f1919061456e565b6128ff90604081019061462f565b6020018e8e8881811061291457612914614216565b9050602002810190612926919061456e565b612934906060810190614663565b6040518763ffffffff1660e01b8152600401612953949392919061419b565b600060405180830381858988f1158015612971573d6000803e3d6000fd5b5050505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526129b991908101906143fe565b8783815181106129cb576129cb614216565b60200260200101516020018884815181106129e8576129e8614216565b6020026020010151604001829052821515151581525050505b5a612a0c90836143eb565b868281518110612a1e57612a1e614216565b60200260200101516000018181525050858181518110612a4057612a40614216565b60200260200101516020015115612bcf57888882818110612a6357612a63614216565b9050602002810190612a75919061456e565b612a8390604081019061462f565b612a8d90806146cb565b612a9e9060a0810190608001613833565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff168a8a84818110612add57612add614216565b9050602002810190612aef919061456e565b612afd906020810190613833565b73ffffffffffffffffffffffffffffffffffffffff167fdaf1e6e151973de199f3ea25b9c6a7c3d94299dc85e269cfd20e48e517ecf7048c8c86818110612b4657612b46614216565b9050602002810190612b58919061456e565b612b69906040810190602001614614565b8d8d87818110612b7b57612b7b614216565b9050602002810190612b8d919061456e565b612b9b90604081019061462f565b612ba590806146cb565b612bb39060a0810190614357565b604051612bc29392919061444f565b60405180910390a4612d68565b888882818110612be157612be1614216565b9050602002810190612bf3919061456e565b612c0190604081019061462f565b612c0b90806146cb565b612c1c9060a0810190608001613833565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff168a8a84818110612c5b57612c5b614216565b9050602002810190612c6d919061456e565b612c7b906020810190613833565b73ffffffffffffffffffffffffffffffffffffffff167f5350e8e0c8cacf19dd5334174c3d5a3e8b7d7e00fdb5457d7ddec04b5e4a1af38c8c86818110612cc457612cc4614216565b9050602002810190612cd6919061456e565b612ce7906040810190602001614614565b8d8d87818110612cf957612cf9614216565b9050602002810190612d0b919061456e565b612d1990604081019061462f565b612d2390806146cb565b612d319060a0810190614357565b8c8881518110612d4357612d43614216565b602002602001015160400151604051612d5f9493929190614478565b60405180910390a45b858181518110612d7a57612d7a614216565b602002602001015160200151158015612d91575086155b612d9d5760010161255e565b50612db06064600a5a61163d90886143eb565b505050509392505050565b612dc3613316565b73ffffffffffffffffffffffffffffffffffffffff8116612e66576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401611128565b612e6f816135a5565b50565b6040805173ffffffffffffffffffffffffffffffffffffffff84811660208084019190915263ffffffff851683850152600060608085018290528551808603820181526080860187528051908401207fff0000000000000000000000000000000000000000000000000000000000000060a08701527f000000000000000000000000000000000000000000000000000000000000000090911b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a186015260b58501527f6b106ae0e3afae21508569f62d81c7d826b900a2e9ccc973ba97abfae026fc5460d5808601919091528551808603909101815260f5909401909452825192019190912016803b15612f8a579050610cb2565b6040517f2adc4cf700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015263ffffffff851660248301527f00000000000000000000000000000000000000000000000000000000000000001690632adc4cf7906044016020604051808303816000875af1158015613024573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b879190614321565b6000806130558888612e72565b9050606073ffffffffffffffffffffffffffffffffffffffff8216639428ae4e608088013561308a61134660a08c018c614357565b5a61309591906143eb565b908a8a8a8a6040518763ffffffff1660e01b81526004016130b9949392919061419b565b600060405180830381858988f11580156130d7573d6000803e3d6000fd5b5050505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261311f91908101906143fe565b909350905082156131cc5761313a60a0880160808901613833565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff167fdaf1e6e151973de199f3ea25b9c6a7c3d94299dc85e269cfd20e48e517ecf7048b8b8060a001906131b09190614357565b6040516131bf9392919061444f565b60405180910390a461326c565b6131dc60a0880160808901613833565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff167f5350e8e0c8cacf19dd5334174c3d5a3e8b7d7e00fdb5457d7ddec04b5e4a1af38b8b8060a001906132529190614357565b876040516132639493929190614478565b60405180910390a45b50509695505050505050565b6000808061dead33146132b7576040517f7a3acd8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a90506132c68686612e72565b93505a6132d390826143eb565b9250620186a083109150509250925092565b60005a905060005b825a6132f990846143eb565b10156133115780613309816146ff565b9150506132ed565b505050565b60335473ffffffffffffffffffffffffffffffffffffffff163314613397576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611128565b565b6000806133a68989612e72565b9050606073ffffffffffffffffffffffffffffffffffffffff82166333a2d58460a08a01356133d86120ba8c806146cb565b5a6133e391906143eb565b908b8b8b8b8b6040518863ffffffff1660e01b81526004016134099594939291906144fc565b600060405180830381858988f1158015613427573d6000803e3d6000fd5b5050505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261346f91908101906143fe565b9093509050821561350a5761348488806146cb565b6134959060a0810190608001613833565b73ffffffffffffffffffffffffffffffffffffffff90811690838116908c167fdaf1e6e151973de199f3ea25b9c6a7c3d94299dc85e269cfd20e48e517ecf7048c6134e08d806146cb565b6134ee9060a0810190614357565b6040516134fd9392919061444f565b60405180910390a4613598565b61351488806146cb565b6135259060a0810190608001613833565b73ffffffffffffffffffffffffffffffffffffffff90811690838116908c167f5350e8e0c8cacf19dd5334174c3d5a3e8b7d7e00fdb5457d7ddec04b5e4a1af38c6135708d806146cb565b61357e9060a0810190614357565b8760405161358f9493929190614478565b60405180910390a45b5050979650505050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b73ffffffffffffffffffffffffffffffffffffffff81168114612e6f57600080fd5b80356136498161361c565b919050565b803563ffffffff8116811461364957600080fd5b60008083601f84011261367457600080fd5b50813567ffffffffffffffff81111561368c57600080fd5b6020830191508360208260051b85010111156136a757600080fd5b9250929050565b600080600080606085870312156136c457600080fd5b84356136cf8161361c565b93506136dd6020860161364e565b9250604085013567ffffffffffffffff8111156136f957600080fd5b61370587828801613662565b95989497509550505050565b602080825282518282018190526000919060409081850190868401855b828110156137535781518051855286015186850152928401929085019060010161372e565b5091979650505050505050565b60008060008060008086880361012081121561377b57600080fd5b87356137868161361c565b96506137946020890161364e565b9550604088013567ffffffffffffffff808211156137b157600080fd5b9089019060c0828c0312156137c557600080fd5b81965060a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0840112156137f857600080fd5b60608a0195506101008a013592508083111561381357600080fd5b505061382189828a01613662565b979a9699509497509295939492505050565b60006020828403121561384557600080fd5b81356124a58161361c565b60008083601f84011261386257600080fd5b50813567ffffffffffffffff81111561387a57600080fd5b6020830191508360208260061b85010111156136a757600080fd5b600080602083850312156138a857600080fd5b823567ffffffffffffffff8111156138bf57600080fd5b6138cb85828601613850565b90969095509350505050565b600080604083850312156138ea57600080fd5b82356138f58161361c565b91506139036020840161364e565b90509250929050565b60005b8381101561392757818101518382015260200161390f565b50506000910152565b6000815180845261394881602086016020860161390c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006124a56020830184613930565b8581528460208201528315156040820152821515606082015260a0608082015260006139bc60a0830184613930565b979650505050505050565b600080600080600080600060a0888a0312156139e257600080fd5b87356139ed8161361c565b96506139fb6020890161364e565b9550604088013567ffffffffffffffff80821115613a1857600080fd5b9089019060e0828c031215613a2c57600080fd5b90955060608901359080821115613a4257600080fd5b613a4e8b838c01613662565b909650945060808a0135915080821115613a6757600080fd5b50613a748a828b01613850565b989b979a50959850939692959293505050565b8015158114612e6f57600080fd5b600080600060408486031215613aaa57600080fd5b833567ffffffffffffffff811115613ac157600080fd5b613acd86828701613662565b9094509250506020840135613ae181613a87565b809150509250925092565b600080600060408486031215613b0157600080fd5b8335613b0c8161361c565b9250602084013567ffffffffffffffff811115613b2857600080fd5b613b3486828701613662565b9497909650939450505050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015613bd2578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0018552815180518452878101511515888501528601516060878501819052613bbe81860183613930565b968901969450505090860190600101613b68565b509098975050505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613c1557600080fd5b830160208101925035905067ffffffffffffffff811115613c3557600080fd5b8036038213156136a757600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b81835260006020808501808196508560051b81019150846000805b88811015613d56578385038a5282357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81893603018112613ce6578283fd5b880160808135613cf58161361c565b73ffffffffffffffffffffffffffffffffffffffff168752613d1982890183613be0565b828a8a0152613d2b838a018284613c44565b604085810135908b015260609485013594909901939093525050509885019891850191600101613ca8565b509298975050505050505050565b600081357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1833603018112613d9857600080fd5b820160208101903567ffffffffffffffff811115613db557600080fd5b8060051b3603821315613dc757600080fd5b60c08552613dd960c086018284613c8d565b915050602083013560208501526040830135604085015260608301356060850152613e066080840161363e565b73ffffffffffffffffffffffffffffffffffffffff166080850152613e2e60a0840184613be0565b85830360a0870152610611838284613c44565b600081357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff41833603018112613e7557600080fd5b60e08452613e8860e08501848301613d64565b9050613ec5602085016020850180358252602081013560208301526040810135604083015260608101356060830152608081013560808301525050565b60c083013560c08501528091505092915050565b60208082528181018390526000906040600585901b840181019084018684805b88811015613d56577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845282357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff218b3603018112613f59578283fd5b613f65868c8301613e41565b9550509285019291850191600101613ef9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715613fca57613fca613f78565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561401757614017613f78565b604052919050565b6000602080838503121561403257600080fd5b825167ffffffffffffffff8082111561404a57600080fd5b818501915085601f83011261405e57600080fd5b81518181111561407057614070613f78565b61407e848260051b01613fd0565b818152848101925060069190911b83018401908782111561409e57600080fd5b928401925b818410156139bc57604084890312156140bc5760008081fd5b6140c4613fa7565b8451815285850151868201528352604090930192918401916140a3565b81835260006020808501808196508560051b81019150846000805b88811015613d56578385038a5282357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc189360301811261413a578283fd5b880160406141488280613be0565b828952614158838a018284613c44565b9250505087820135915061416b8261361c565b73ffffffffffffffffffffffffffffffffffffffff919091169587019590955298850198918501916001016140fc565b60e0815260006141ae60e0830187613d64565b6141e6602084018780358252602081013560208301526040810135604083015260608101356060830152608081013560808301525050565b82810360c08401526139bc8185876140e1565b60006020828403121561420b57600080fd5b81516124a581613a87565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561425757600080fd5b81356124a581613a87565b600082601f83011261427357600080fd5b815167ffffffffffffffff81111561428d5761428d613f78565b6142be60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613fd0565b8181528460208386010111156142d357600080fd5b6142e482602083016020870161390c565b949350505050565b6000602082840312156142fe57600080fd5b815167ffffffffffffffff81111561431557600080fd5b610cae84828501614262565b60006020828403121561433357600080fd5b81516124a58161361c565b60006020828403121561435057600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261438c57600080fd5b83018035915067ffffffffffffffff8211156143a757600080fd5b6020019150368190038213156136a757600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610cb257610cb26143bc565b6000806040838503121561441157600080fd5b825161441c81613a87565b602084015190925067ffffffffffffffff81111561443957600080fd5b61444585828601614262565b9150509250929050565b63ffffffff8416815260406020820152600061446f604083018486613c44565b95945050505050565b63ffffffff85168152606060208201526000614498606083018587613c44565b82810360408401526139bc8185613930565b8082028115828204841417610cb257610cb26143bc565b6000826144f7577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60608152600061450f6060830188613e41565b60208382038185015261452382888a6140e1565b84810360408681019190915286825287935090820160005b8781101561455f57843582528385013584830152938201939082019060010161453b565b509a9950505050505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff618336030181126145a257600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126145e157600080fd5b83018035915067ffffffffffffffff8211156145fc57600080fd5b6020019150600681901b36038213156136a757600080fd5b60006020828403121561462657600080fd5b6124a58261364e565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff218336030181126145a257600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261469857600080fd5b83018035915067ffffffffffffffff8211156146b357600080fd5b6020019150600581901b36038213156136a757600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff418336030181126145a257600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614730576147306143bc565b506001019056fea2646970667358221220380cb1d59ec81db9112a02f4e44aa1758556f27507ba641a65199a45450eed3364736f6c63430008120033000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e687
Deployed Bytecode
0x6080604052600436106101965760003560e01c8063700742eb116100e1578063ad9ddf171161008a578063d817a8c911610064578063d817a8c9146104b5578063d99f5d3a146104d5578063db421487146104f5578063f2fde38b1461052957600080fd5b8063ad9ddf171461045b578063b0c5ea881461046e578063c5e15557146104a257600080fd5b806378853bb5116100bb57806378853bb5146103a95780638da5cb5b146103ef578063946d92041461043b57600080fd5b8063700742eb14610361578063715018a614610381578063715b9fdc1461039657600080fd5b806355ecef671161014357806368626d8f1161011d57806368626d8f1461030a57806369d12c3a1461032e5780636d85c65f1461034e57600080fd5b806355ecef67146102a95780635868e124146102c957806359e727eb146102f757600080fd5b80633f66feff116101745780633f66feff1461024757806340be24e9146102695780634ad446881461029657600080fd5b8063139203eb1461019b57806322917a0c146101d15780632520e7ff14610201575b600080fd5b3480156101a757600080fd5b506101bb6101b63660046136ae565b610549565b6040516101c89190613711565b60405180910390f35b3480156101dd57600080fd5b506101f16101ec366004613760565b61061b565b60405190151581526020016101c8565b34801561020d57600080fd5b506101f161021c366004613833565b73ffffffffffffffffffffffffffffffffffffffff1660009081526066602052604090205460011490565b34801561025357600080fd5b50610267610262366004613895565b6106d0565b005b34801561027557600080fd5b506102896102843660046138d7565b6109e5565b6040516101c8919061397a565b6102676102a4366004613760565b610cb8565b3480156102b557600080fd5b506102896102c43660046138d7565b610d18565b3480156102d557600080fd5b506102e96102e43660046138d7565b610f4d565b6040519081526020016101c8565b610267610305366004613760565b6110d7565b61031d610318366004613760565b61113b565b6040516101c895949392919061398d565b34801561033a57600080fd5b506101f16103493660046139c7565b611665565b61026761035c3660046139c7565b61171d565b34801561036d57600080fd5b5061026761037c366004613895565b61177a565b34801561038d57600080fd5b5061026761199a565b6102676103a4366004613a95565b6119d4565b3480156103b557600080fd5b506101f16103c4366004613833565b73ffffffffffffffffffffffffffffffffffffffff1660009081526065602052604090205460011490565b3480156103fb57600080fd5b5060335473ffffffffffffffffffffffffffffffffffffffff165b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101c8565b34801561044757600080fd5b50610267610456366004613aec565b611ce2565b61031d6104693660046139c7565b612011565b34801561047a57600080fd5b506104167f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e68781565b6102676104b03660046139c7565b61231b565b3480156104c157600080fd5b506104166104d03660046138d7565b612373565b6104e86104e3366004613a95565b6124ac565b6040516101c89190613b41565b34801561050157600080fd5b506102e97f6b106ae0e3afae21508569f62d81c7d826b900a2e9ccc973ba97abfae026fc5481565b34801561053557600080fd5b50610267610544366004613833565b612dbb565b606060006105578686612e72565b6040517f8449b2c900000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690638449b2c9906105ae9087908790600401613ed9565b600060405180830381865afa1580156105cb573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610611919081019061401f565b9695505050505050565b6000806106288888612e72565b6040517f2a4bf79400000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690632a4bf7949061068390899089908990899060040161419b565b602060405180830381865afa1580156106a0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106c491906141f9565b98975050505050505050565b60335473ffffffffffffffffffffffffffffffffffffffff163314806107055750336000908152606660205260409020546001145b61073b576040517f7a3acd8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600061075d60335473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614905060005b828110156109de5760008585838181106107ac576107ac614216565b6107c29260206040909202019081019150613833565b73ffffffffffffffffffffffffffffffffffffffff160361080f576040517f7bb8c4fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600085858381811061082357610823614216565b905060400201602001602081019061083b9190614245565b610846576000610849565b60015b60ff16905082806108b55750801580156108b5575085858381811061087057610870614216565b6108869260206040909202019081019150613833565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b6108eb576040517f7a3acd8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b806066600088888681811061090257610902614216565b6109189260206040909202019081019150613833565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205585858381811061095157610951614216565b90506040020160200160208101906109699190614245565b151586868481811061097d5761097d614216565b6109939260206040909202019081019150613833565b73ffffffffffffffffffffffffffffffffffffffff167fbce29f3c87027a39c8405b00ac40728d467fc8f800c6bbfbb37db8f3380400be60405160405180910390a350600101610790565b5050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff84811660208084019190915263ffffffff85168385015260006060808501919091528451808503820181526080850186528051908301207fff0000000000000000000000000000000000000000000000000000000000000060a08601527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000007f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e687831b1660a186015260b58501527f6b106ae0e3afae21508569f62d81c7d826b900a2e9ccc973ba97abfae026fc5460d5808601919091528551808603909101815260f5909401909452825192019190912016803b15610b8f578073ffffffffffffffffffffffffffffffffffffffff166387265c956040518163ffffffff1660e01b8152600401600060405180830381865afa158015610b41573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610b8791908101906142ec565b915050610cb2565b7f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e68773ffffffffffffffffffffffffffffffffffffffff166328807b8b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bfa573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c1e9190614321565b73ffffffffffffffffffffffffffffffffffffffff166387265c956040518163ffffffff1660e01b8152600401600060405180830381865afa158015610c68573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610cae91908101906142ec565b9150505b92915050565b33600090815260656020526040902054600114610d01576040517f7a3acd8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d0f868686868686613048565b50505050505050565b6040805173ffffffffffffffffffffffffffffffffffffffff84811660208084019190915263ffffffff85168385015260006060808501919091528451808503820181526080850186528051908301207fff0000000000000000000000000000000000000000000000000000000000000060a08601527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000007f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e687831b1660a186015260b58501527f6b106ae0e3afae21508569f62d81c7d826b900a2e9ccc973ba97abfae026fc5460d5808601919091528551808603909101815260f5909401909452825192019190912016803b15610e74578073ffffffffffffffffffffffffffffffffffffffff1663b4907ddc6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610b41573d6000803e3d6000fd5b7f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e68773ffffffffffffffffffffffffffffffffffffffff166328807b8b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610edf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f039190614321565b73ffffffffffffffffffffffffffffffffffffffff1663b4907ddc6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610c68573d6000803e3d6000fd5b6040805173ffffffffffffffffffffffffffffffffffffffff84811660208084019190915263ffffffff851683850152600060608085018290528551808603820181526080860187528051908401207fff0000000000000000000000000000000000000000000000000000000000000060a08701527f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e68790911b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a186015260b58501527f6b106ae0e3afae21508569f62d81c7d826b900a2e9ccc973ba97abfae026fc5460d5808601919091528551808603909101815260f5909401909452825192019190912016803b156110cd578073ffffffffffffffffffffffffffffffffffffffff1663bda443316040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110a9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b87919061433e565b5060009392505050565b6000806110e888888888888861113b565b945094505050508161113157806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611128919061397a565b60405180910390fd5b5050505050505050565b60008060008060606111766040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b5a60208201526111868c8c613278565b73ffffffffffffffffffffffffffffffffffffffff909216808452604080517fb4907ddc0000000000000000000000000000000000000000000000000000000081529051929850929650600092839263b4907ddc9160048082019286929091908290030181865afa1580156111ff573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261124591908101906142ec565b805160209182012060408051808201909152600581527f312e302e3000000000000000000000000000000000000000000000000000000092019190915290507f06c015bd22b4c69690933c1058878ebdfef31f9aaae40bbe86d8a09fe1b2972c811480611306575060408051808201909152600581527f312e302e310000000000000000000000000000000000000000000000000000006020909101527ffc7f6d936935ae6385924f29da7af79e941070dafe46831a51595892abc1b97a81145b156113f1575a9150826000015173ffffffffffffffffffffffffffffffffffffffff16639428ae4e8c608001356113528f8060a001906113469190614357565b60080261213401919050565b5a61135d91906143eb565b908f8f8f8f6040518763ffffffff1660e01b8152600401611381949392919061419b565b600060405180830381858988f115801561139f573d6000803e3d6000fd5b5050505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526113e791908101906143fe565b90955093506114c7565b5a9150826000015173ffffffffffffffffffffffffffffffffffffffff16638142d4018c6080013561142c8f8060a001906113469190614357565b5a61143791906143eb565b908f8f8f8f6040518763ffffffff1660e01b815260040161145b949392919061419b565b600060405180830381858988f1158015611479573d6000803e3d6000fd5b5050505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526114c191908101906143fe565b90955093505b5a6114d290836143eb565b975050508215611582576114ec60a08b0160808c01613833565b73ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff167fdaf1e6e151973de199f3ea25b9c6a7c3d94299dc85e269cfd20e48e517ecf7048e8e8060a001906115669190614357565b6040516115759392919061444f565b60405180910390a4611626565b61159260a08b0160808c01613833565b73ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff167f5350e8e0c8cacf19dd5334174c3d5a3e8b7d7e00fdb5457d7ddec04b5e4a1af38e8e8060a0019061160c9190614357565b8860405161161d9493929190614478565b60405180910390a45b6116566064600a5a846020015161163d91906143eb565b61164791906144aa565b61165191906144c1565b6132e5565b50965096509650965096915050565b6000806116728989612e72565b6040517f0f0bc51500000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff821690630f0bc515906116cf908a908a908a908a908a906004016144fc565b602060405180830381865afa1580156116ec573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061171091906141f9565b9998505050505050505050565b60008061172f89898989898989612011565b945094505050508161176f57806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611128919061397a565b505050505050505050565b60335473ffffffffffffffffffffffffffffffffffffffff163314806117af5750336000908152606660205260409020546001145b6117e5576040517f7a3acd8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060005b8181101561199457600084848381811061180557611805614216565b61181b9260206040909202019081019150613833565b73ffffffffffffffffffffffffffffffffffffffff1603611868576040517f7bb8c4fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83838281811061187a5761187a614216565b90506040020160200160208101906118929190614245565b61189d5760006118a0565b60015b60ff16606560008686858181106118b9576118b9614216565b6118cf9260206040909202019081019150613833565b73ffffffffffffffffffffffffffffffffffffffff16815260208101919091526040016000205583838281811061190857611908614216565b90506040020160200160208101906119209190614245565b151584848381811061193457611934614216565b61194a9260206040909202019081019150613833565b73ffffffffffffffffffffffffffffffffffffffff167f8e37ce4bd982978769e6e23562ee5a1c223c57e867089adf19509e1e4c6e8eed60405160405180910390a36001016117e9565b50505050565b6119a2613316565b6040517f956cbbf900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33600090815260656020526040902054600114611a1d576040517f7a3acd8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b816002811015611a59576040517f7bb8c4fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805b82811015611cda576000868683818110611a7957611a79614216565b9050602002810190611a8b919061456e565b611a999060808101906145ac565b90501115611bad57611ba6868683818110611ab657611ab6614216565b9050602002810190611ac8919061456e565b611ad6906020810190613833565b878784818110611ae857611ae8614216565b9050602002810190611afa919061456e565b611b0b906040810190602001614614565b888885818110611b1d57611b1d614216565b9050602002810190611b2f919061456e565b611b3d90604081019061462f565b898986818110611b4f57611b4f614216565b9050602002810190611b61919061456e565b611b6f906060810190614663565b8b8b88818110611b8157611b81614216565b9050602002810190611b93919061456e565b611ba19060808101906145ac565b613399565b9150611cc2565b611cbf868683818110611bc257611bc2614216565b9050602002810190611bd4919061456e565b611be2906020810190613833565b878784818110611bf457611bf4614216565b9050602002810190611c06919061456e565b611c17906040810190602001614614565b888885818110611c2957611c29614216565b9050602002810190611c3b919061456e565b611c4990604081019061462f565b611c5390806146cb565b898986818110611c6557611c65614216565b9050602002810190611c77919061456e565b611c8590604081019061462f565b6020018a8a87818110611c9a57611c9a614216565b9050602002810190611cac919061456e565b611cba906060810190614663565b613048565b91505b81158015611cce575083155b611cda57600101611a5d565b505050505050565b8273ffffffffffffffffffffffffffffffffffffffff8116611d30576040517f7bb8c4fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054610100900460ff1615808015611d505750600054600160ff909116105b80611d6a5750303b158015611d6a575060005460ff166001145b611df6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401611128565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015611e5457600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b611e5d856135a5565b8260005b81811015611fa6576000868683818110611e7d57611e7d614216565b9050602002016020810190611e929190613833565b73ffffffffffffffffffffffffffffffffffffffff1603611edf576040517f7bb8c4fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160656000888885818110611ef757611ef7614216565b9050602002016020810190611f0c9190613833565b73ffffffffffffffffffffffffffffffffffffffff1681526020810191909152604001600020556001868683818110611f4757611f47614216565b9050602002016020810190611f5c9190613833565b73ffffffffffffffffffffffffffffffffffffffff167f8e37ce4bd982978769e6e23562ee5a1c223c57e867089adf19509e1e4c6e8eed60405160405180910390a3600101611e61565b505080156109de57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050505050565b600080600080606061204c6040518060400160405280600073ffffffffffffffffffffffffffffffffffffffff168152602001600081525090565b5a602082015261205c8d8d613278565b73ffffffffffffffffffffffffffffffffffffffff90921683529550935060005a9050816000015173ffffffffffffffffffffffffffffffffffffffff1663aecd4fb48d602001608001356120c88f80600001906120ba91906146cb565b6113469060a0810190614357565b5a6120d391906143eb565b908f8f8f8f8f6040518863ffffffff1660e01b81526004016120f99594939291906144fc565b600060405180830381858988f1158015612117573d6000803e3d6000fd5b5050505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261215f91908101906143fe565b90945092505a61216f90826143eb565b9650508215612237576121828b806146cb565b6121939060a0810190608001613833565b73ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff167fdaf1e6e151973de199f3ea25b9c6a7c3d94299dc85e269cfd20e48e517ecf7048f8f806000019061220d91906146cb565b61221b9060a0810190614357565b60405161222a9392919061444f565b60405180910390a46122f4565b6122418b806146cb565b6122529060a0810190608001613833565b73ffffffffffffffffffffffffffffffffffffffff16816000015173ffffffffffffffffffffffffffffffffffffffff168e73ffffffffffffffffffffffffffffffffffffffff167f5350e8e0c8cacf19dd5334174c3d5a3e8b7d7e00fdb5457d7ddec04b5e4a1af38f8f80600001906122cc91906146cb565b6122da9060a0810190614357565b886040516122eb9493929190614478565b60405180910390a45b61230b6064600a5a846020015161163d91906143eb565b5097509750975097509792505050565b33600090815260656020526040902054600114612364576040517f7a3acd8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61113187878787878787613399565b600073ffffffffffffffffffffffffffffffffffffffff83163b1561239a57506000610cb2565b6040805173ffffffffffffffffffffffffffffffffffffffff80861660208084019190915263ffffffff86168385015260006060808501919091528451808503820181526080850186528051908301207fff0000000000000000000000000000000000000000000000000000000000000060a08601527f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e68790911b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a185015260b58401527f6b106ae0e3afae21508569f62d81c7d826b900a2e9ccc973ba97abfae026fc5460d5808501919091528451808503909101815260f590930190935281519190920120165b9392505050565b606060005a90508360028110156124ef576040517f7bb8c4fb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8067ffffffffffffffff81111561250857612508613f78565b60405190808252806020026020018201604052801561255557816020015b604080516060808201835260008083526020830152918101919091528152602001906001900390816125265790505b50925060008060005b83811015612d9d576125d589898381811061257b5761257b614216565b905060200281019061258d919061456e565b61259b906020810190613833565b8a8a848181106125ad576125ad614216565b90506020028101906125bf919061456e565b6125d0906040810190602001614614565b613278565b50909350505a915060008989838181106125f1576125f1614216565b9050602002810190612603919061456e565b6126119060808101906145ac565b9050111561281e578273ffffffffffffffffffffffffffffffffffffffff1663aecd4fb48a8a8481811061264757612647614216565b9050602002810190612659919061456e565b61266790604081019061462f565b60a001356126aa8c8c8681811061268057612680614216565b9050602002810190612692919061456e565b6126a090604081019061462f565b6120ba90806146cb565b5a6126b591906143eb565b908c8c868181106126c8576126c8614216565b90506020028101906126da919061456e565b6126e890604081019061462f565b8d8d878181106126fa576126fa614216565b905060200281019061270c919061456e565b61271a906060810190614663565b8f8f8981811061272c5761272c614216565b905060200281019061273e919061456e565b61274c9060808101906145ac565b6040518863ffffffff1660e01b815260040161276c9594939291906144fc565b600060405180830381858988f115801561278a573d6000803e3d6000fd5b5050505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526127d291908101906143fe565b8783815181106127e4576127e4614216565b602002602001015160200188848151811061280157612801614216565b602002602001015160400182905282151515158152505050612a01565b8273ffffffffffffffffffffffffffffffffffffffff16638142d4018a8a8481811061284c5761284c614216565b905060200281019061285e919061456e565b61286c90604081019061462f565b60a001356128858c8c8681811061268057612680614216565b5a61289091906143eb565b908c8c868181106128a3576128a3614216565b90506020028101906128b5919061456e565b6128c390604081019061462f565b6128cd90806146cb565b8d8d878181106128df576128df614216565b90506020028101906128f1919061456e565b6128ff90604081019061462f565b6020018e8e8881811061291457612914614216565b9050602002810190612926919061456e565b612934906060810190614663565b6040518763ffffffff1660e01b8152600401612953949392919061419b565b600060405180830381858988f1158015612971573d6000803e3d6000fd5b5050505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526129b991908101906143fe565b8783815181106129cb576129cb614216565b60200260200101516020018884815181106129e8576129e8614216565b6020026020010151604001829052821515151581525050505b5a612a0c90836143eb565b868281518110612a1e57612a1e614216565b60200260200101516000018181525050858181518110612a4057612a40614216565b60200260200101516020015115612bcf57888882818110612a6357612a63614216565b9050602002810190612a75919061456e565b612a8390604081019061462f565b612a8d90806146cb565b612a9e9060a0810190608001613833565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff168a8a84818110612add57612add614216565b9050602002810190612aef919061456e565b612afd906020810190613833565b73ffffffffffffffffffffffffffffffffffffffff167fdaf1e6e151973de199f3ea25b9c6a7c3d94299dc85e269cfd20e48e517ecf7048c8c86818110612b4657612b46614216565b9050602002810190612b58919061456e565b612b69906040810190602001614614565b8d8d87818110612b7b57612b7b614216565b9050602002810190612b8d919061456e565b612b9b90604081019061462f565b612ba590806146cb565b612bb39060a0810190614357565b604051612bc29392919061444f565b60405180910390a4612d68565b888882818110612be157612be1614216565b9050602002810190612bf3919061456e565b612c0190604081019061462f565b612c0b90806146cb565b612c1c9060a0810190608001613833565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff168a8a84818110612c5b57612c5b614216565b9050602002810190612c6d919061456e565b612c7b906020810190613833565b73ffffffffffffffffffffffffffffffffffffffff167f5350e8e0c8cacf19dd5334174c3d5a3e8b7d7e00fdb5457d7ddec04b5e4a1af38c8c86818110612cc457612cc4614216565b9050602002810190612cd6919061456e565b612ce7906040810190602001614614565b8d8d87818110612cf957612cf9614216565b9050602002810190612d0b919061456e565b612d1990604081019061462f565b612d2390806146cb565b612d319060a0810190614357565b8c8881518110612d4357612d43614216565b602002602001015160400151604051612d5f9493929190614478565b60405180910390a45b858181518110612d7a57612d7a614216565b602002602001015160200151158015612d91575086155b612d9d5760010161255e565b50612db06064600a5a61163d90886143eb565b505050509392505050565b612dc3613316565b73ffffffffffffffffffffffffffffffffffffffff8116612e66576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401611128565b612e6f816135a5565b50565b6040805173ffffffffffffffffffffffffffffffffffffffff84811660208084019190915263ffffffff851683850152600060608085018290528551808603820181526080860187528051908401207fff0000000000000000000000000000000000000000000000000000000000000060a08701527f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e68790911b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a186015260b58501527f6b106ae0e3afae21508569f62d81c7d826b900a2e9ccc973ba97abfae026fc5460d5808601919091528551808603909101815260f5909401909452825192019190912016803b15612f8a579050610cb2565b6040517f2adc4cf700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff858116600483015263ffffffff851660248301527f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e6871690632adc4cf7906044016020604051808303816000875af1158015613024573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b879190614321565b6000806130558888612e72565b9050606073ffffffffffffffffffffffffffffffffffffffff8216639428ae4e608088013561308a61134660a08c018c614357565b5a61309591906143eb565b908a8a8a8a6040518763ffffffff1660e01b81526004016130b9949392919061419b565b600060405180830381858988f11580156130d7573d6000803e3d6000fd5b5050505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261311f91908101906143fe565b909350905082156131cc5761313a60a0880160808901613833565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff167fdaf1e6e151973de199f3ea25b9c6a7c3d94299dc85e269cfd20e48e517ecf7048b8b8060a001906131b09190614357565b6040516131bf9392919061444f565b60405180910390a461326c565b6131dc60a0880160808901613833565b73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff167f5350e8e0c8cacf19dd5334174c3d5a3e8b7d7e00fdb5457d7ddec04b5e4a1af38b8b8060a001906132529190614357565b876040516132639493929190614478565b60405180910390a45b50509695505050505050565b6000808061dead33146132b7576040517f7a3acd8400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005a90506132c68686612e72565b93505a6132d390826143eb565b9250620186a083109150509250925092565b60005a905060005b825a6132f990846143eb565b10156133115780613309816146ff565b9150506132ed565b505050565b60335473ffffffffffffffffffffffffffffffffffffffff163314613397576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611128565b565b6000806133a68989612e72565b9050606073ffffffffffffffffffffffffffffffffffffffff82166333a2d58460a08a01356133d86120ba8c806146cb565b5a6133e391906143eb565b908b8b8b8b8b6040518863ffffffff1660e01b81526004016134099594939291906144fc565b600060405180830381858988f1158015613427573d6000803e3d6000fd5b5050505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261346f91908101906143fe565b9093509050821561350a5761348488806146cb565b6134959060a0810190608001613833565b73ffffffffffffffffffffffffffffffffffffffff90811690838116908c167fdaf1e6e151973de199f3ea25b9c6a7c3d94299dc85e269cfd20e48e517ecf7048c6134e08d806146cb565b6134ee9060a0810190614357565b6040516134fd9392919061444f565b60405180910390a4613598565b61351488806146cb565b6135259060a0810190608001613833565b73ffffffffffffffffffffffffffffffffffffffff90811690838116908c167f5350e8e0c8cacf19dd5334174c3d5a3e8b7d7e00fdb5457d7ddec04b5e4a1af38c6135708d806146cb565b61357e9060a0810190614357565b8760405161358f9493929190614478565b60405180910390a45b5050979650505050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b73ffffffffffffffffffffffffffffffffffffffff81168114612e6f57600080fd5b80356136498161361c565b919050565b803563ffffffff8116811461364957600080fd5b60008083601f84011261367457600080fd5b50813567ffffffffffffffff81111561368c57600080fd5b6020830191508360208260051b85010111156136a757600080fd5b9250929050565b600080600080606085870312156136c457600080fd5b84356136cf8161361c565b93506136dd6020860161364e565b9250604085013567ffffffffffffffff8111156136f957600080fd5b61370587828801613662565b95989497509550505050565b602080825282518282018190526000919060409081850190868401855b828110156137535781518051855286015186850152928401929085019060010161372e565b5091979650505050505050565b60008060008060008086880361012081121561377b57600080fd5b87356137868161361c565b96506137946020890161364e565b9550604088013567ffffffffffffffff808211156137b157600080fd5b9089019060c0828c0312156137c557600080fd5b81965060a07fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0840112156137f857600080fd5b60608a0195506101008a013592508083111561381357600080fd5b505061382189828a01613662565b979a9699509497509295939492505050565b60006020828403121561384557600080fd5b81356124a58161361c565b60008083601f84011261386257600080fd5b50813567ffffffffffffffff81111561387a57600080fd5b6020830191508360208260061b85010111156136a757600080fd5b600080602083850312156138a857600080fd5b823567ffffffffffffffff8111156138bf57600080fd5b6138cb85828601613850565b90969095509350505050565b600080604083850312156138ea57600080fd5b82356138f58161361c565b91506139036020840161364e565b90509250929050565b60005b8381101561392757818101518382015260200161390f565b50506000910152565b6000815180845261394881602086016020860161390c565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006124a56020830184613930565b8581528460208201528315156040820152821515606082015260a0608082015260006139bc60a0830184613930565b979650505050505050565b600080600080600080600060a0888a0312156139e257600080fd5b87356139ed8161361c565b96506139fb6020890161364e565b9550604088013567ffffffffffffffff80821115613a1857600080fd5b9089019060e0828c031215613a2c57600080fd5b90955060608901359080821115613a4257600080fd5b613a4e8b838c01613662565b909650945060808a0135915080821115613a6757600080fd5b50613a748a828b01613850565b989b979a50959850939692959293505050565b8015158114612e6f57600080fd5b600080600060408486031215613aaa57600080fd5b833567ffffffffffffffff811115613ac157600080fd5b613acd86828701613662565b9094509250506020840135613ae181613a87565b809150509250925092565b600080600060408486031215613b0157600080fd5b8335613b0c8161361c565b9250602084013567ffffffffffffffff811115613b2857600080fd5b613b3486828701613662565b9497909650939450505050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b83811015613bd2578883037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0018552815180518452878101511515888501528601516060878501819052613bbe81860183613930565b968901969450505090860190600101613b68565b509098975050505050505050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613c1557600080fd5b830160208101925035905067ffffffffffffffff811115613c3557600080fd5b8036038213156136a757600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b81835260006020808501808196508560051b81019150846000805b88811015613d56578385038a5282357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81893603018112613ce6578283fd5b880160808135613cf58161361c565b73ffffffffffffffffffffffffffffffffffffffff168752613d1982890183613be0565b828a8a0152613d2b838a018284613c44565b604085810135908b015260609485013594909901939093525050509885019891850191600101613ca8565b509298975050505050505050565b600081357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1833603018112613d9857600080fd5b820160208101903567ffffffffffffffff811115613db557600080fd5b8060051b3603821315613dc757600080fd5b60c08552613dd960c086018284613c8d565b915050602083013560208501526040830135604085015260608301356060850152613e066080840161363e565b73ffffffffffffffffffffffffffffffffffffffff166080850152613e2e60a0840184613be0565b85830360a0870152610611838284613c44565b600081357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff41833603018112613e7557600080fd5b60e08452613e8860e08501848301613d64565b9050613ec5602085016020850180358252602081013560208301526040810135604083015260608101356060830152608081013560808301525050565b60c083013560c08501528091505092915050565b60208082528181018390526000906040600585901b840181019084018684805b88811015613d56577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc088860301845282357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff218b3603018112613f59578283fd5b613f65868c8301613e41565b9550509285019291850191600101613ef9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff81118282101715613fca57613fca613f78565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561401757614017613f78565b604052919050565b6000602080838503121561403257600080fd5b825167ffffffffffffffff8082111561404a57600080fd5b818501915085601f83011261405e57600080fd5b81518181111561407057614070613f78565b61407e848260051b01613fd0565b818152848101925060069190911b83018401908782111561409e57600080fd5b928401925b818410156139bc57604084890312156140bc5760008081fd5b6140c4613fa7565b8451815285850151868201528352604090930192918401916140a3565b81835260006020808501808196508560051b81019150846000805b88811015613d56578385038a5282357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc189360301811261413a578283fd5b880160406141488280613be0565b828952614158838a018284613c44565b9250505087820135915061416b8261361c565b73ffffffffffffffffffffffffffffffffffffffff919091169587019590955298850198918501916001016140fc565b60e0815260006141ae60e0830187613d64565b6141e6602084018780358252602081013560208301526040810135604083015260608101356060830152608081013560808301525050565b82810360c08401526139bc8185876140e1565b60006020828403121561420b57600080fd5b81516124a581613a87565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60006020828403121561425757600080fd5b81356124a581613a87565b600082601f83011261427357600080fd5b815167ffffffffffffffff81111561428d5761428d613f78565b6142be60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601613fd0565b8181528460208386010111156142d357600080fd5b6142e482602083016020870161390c565b949350505050565b6000602082840312156142fe57600080fd5b815167ffffffffffffffff81111561431557600080fd5b610cae84828501614262565b60006020828403121561433357600080fd5b81516124a58161361c565b60006020828403121561435057600080fd5b5051919050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261438c57600080fd5b83018035915067ffffffffffffffff8211156143a757600080fd5b6020019150368190038213156136a757600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610cb257610cb26143bc565b6000806040838503121561441157600080fd5b825161441c81613a87565b602084015190925067ffffffffffffffff81111561443957600080fd5b61444585828601614262565b9150509250929050565b63ffffffff8416815260406020820152600061446f604083018486613c44565b95945050505050565b63ffffffff85168152606060208201526000614498606083018587613c44565b82810360408401526139bc8185613930565b8082028115828204841417610cb257610cb26143bc565b6000826144f7577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b60608152600061450f6060830188613e41565b60208382038185015261452382888a6140e1565b84810360408681019190915286825287935090820160005b8781101561455f57843582528385013584830152938201939082019060010161453b565b509a9950505050505050505050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff618336030181126145a257600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126145e157600080fd5b83018035915067ffffffffffffffff8211156145fc57600080fd5b6020019150600681901b36038213156136a757600080fd5b60006020828403121561462657600080fd5b6124a58261364e565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff218336030181126145a257600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe184360301811261469857600080fd5b83018035915067ffffffffffffffff8211156146b357600080fd5b6020019150600581901b36038213156136a757600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff418336030181126145a257600080fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614730576147306143bc565b506001019056fea2646970667358221220380cb1d59ec81db9112a02f4e44aa1758556f27507ba641a65199a45450eed3364736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e687
-----Decoded View---------------
Arg [0] : avoFactory_ (address): 0xe981E50c7c47F0Df8826B5ce3F533f5E4440e687
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e687
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
[ 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.