Overview
S Balance
0 S
S Value
-More Info
Private Name Tags
ContractCreator
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
410501 | 6 days ago | Contract Creation | 0 S |
Loading...
Loading
Contract Name:
AvoSignersList
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 { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { IAvocadoMultisigV1 } from "./interfaces/IAvocadoMultisigV1.sol"; import { IAvoFactory } from "./interfaces/IAvoFactory.sol"; import { IAvoSignersList } from "./interfaces/IAvoSignersList.sol"; import { IAvoConfigV1 } from "./interfaces/IAvoConfigV1.sol"; // empty interface used for Natspec docs for nice layout in automatically generated docs: // /// @title AvoSignersList v1.0.0 /// @notice Tracks allowed signers for Avocados, making available a list of all signers /// linked to an Avocado or all Avocados for a certain signer address. /// /// If `trackInStorage` flag is set to false, then only an event will be emitted for off-chain tracking. /// The contract itself will not track avocados per signer! /// /// Upgradeable through AvoSignersListProxy /// /// _@dev Notes:_ /// In off-chain tracking, make sure to check for duplicates (i.e. mapping already exists). /// This should not happen but when not tracking the data on-chain there is no way to be sure. interface AvoSignersList_V1 { } abstract contract AvoSignersListErrors { /// @notice thrown when a method is called with invalid params (e.g. zero address) error AvoSignersList__InvalidParams(); /// @notice thrown when a view method is called that would require storage mapping data, /// but the flag `trackInStorage` is set to false and thus data is not available. error AvoSignersList__NotTracked(); } abstract contract AvoSignersListConstants is AvoSignersListErrors { /// @notice AvoFactory used to confirm that an address is an Avocado smart wallet IAvoFactory public immutable avoFactory; /// @notice flag to signal if tracking should happen in storage or only events should be emitted (for off-chain). /// This can be set to false to reduce gas cost on expensive chains bool public immutable trackInStorage; /// @notice constructor sets the immutable `avoFactory` (proxy) address and the `trackInStorage` flag constructor(IAvoFactory avoFactory_, IAvoConfigV1 avoConfigV1_) { if (address(avoFactory_) == address(0)) { revert AvoSignersList__InvalidParams(); } avoFactory = avoFactory_; // get trackInStorage flag from AvoConfigV1 contract IAvoConfigV1.AvoSignersListConfig memory avoConfig_ = avoConfigV1_.avoSignersListConfig(); trackInStorage = avoConfig_.trackInStorage; } } abstract contract AvoSignersListVariables is AvoSignersListConstants { using EnumerableSet for EnumerableSet.AddressSet; /// @dev add a gap for slot 0 to 100 to easily inherit Initializable / OwnableUpgradeable etc. later on uint256[101] private __gap; // ---------------- slot 101 ----------------- /// @notice tracks all Avocados mapped to a signer: signer => EnumerableSet Avocados list /// @dev mappings to a struct with a mapping can not be public because the getter function that Solidity automatically /// generates for public variables cannot handle the potentially infinite size caused by mappings within the structs. mapping(address => EnumerableSet.AddressSet) internal _avocadosPerSigner; } abstract contract AvoSignersListEvents { /// @notice emitted when a new signer <> Avocado mapping is added event SignerMappingAdded(address signer, address avocado); /// @notice emitted when a signer <> Avocado mapping is removed event SignerMappingRemoved(address signer, address avocado); } abstract contract AvoSignersListViews is AvoSignersListVariables { using EnumerableSet for EnumerableSet.AddressSet; /// @notice returns true if `signer_` is an allowed signer of `avocado_` function isSignerOf(address avocado_, address signer_) public view returns (bool) { // make sure avocado_ is an actual Avocado if (!avoFactory.isAvocado(avocado_)) { return false; } if (!trackInStorage) { return IAvocadoMultisigV1(avocado_).isSigner(signer_); } return _avocadosPerSigner[signer_].contains(avocado_); } /// @notice returns all signers for a certain `avocado_` function signers(address avocado_) public view returns (address[] memory) { // make sure avocado_ is an actual Avocado if (!avoFactory.isAvocado(avocado_)) { return new address[](0); } return IAvocadoMultisigV1(avocado_).signers(); } /// @notice returns all Avocados for a certain `signer_'. /// reverts with `AvoSignersList__NotTracked()` if `trackInStorage` is set to false (data not available) function avocados(address signer_) public view returns (address[] memory) { if (!trackInStorage) { revert AvoSignersList__NotTracked(); } return _avocadosPerSigner[signer_].values(); } /// @notice returns the number of mapped signers for a certain `avocado_' function signersCount(address avocado_) public view returns (uint256) { // make sure avocado_ is an actual Avocado if (!avoFactory.isAvocado(avocado_)) { return 0; } return IAvocadoMultisigV1(avocado_).signersCount(); } /// @notice returns the number of mapped avocados for a certain `signer_' /// reverts with `AvoSignersList__NotTracked()` if `trackInStorage` is set to false (data not available) function avocadosCount(address signer_) public view returns (uint256) { if (!trackInStorage) { revert AvoSignersList__NotTracked(); } return _avocadosPerSigner[signer_].length(); } } contract AvoSignersList is AvoSignersListErrors, AvoSignersListConstants, AvoSignersListVariables, AvoSignersListEvents, AvoSignersListViews, IAvoSignersList { using EnumerableSet for EnumerableSet.AddressSet; /// @notice constructor sets the immutable `avoFactory` (proxy) address and the `trackInStorage` flag constructor( IAvoFactory avoFactory_, IAvoConfigV1 avoConfigV1_ ) AvoSignersListConstants(avoFactory_, avoConfigV1_) {} /// @inheritdoc IAvoSignersList function syncAddAvoSignerMappings(address avocado_, address[] calldata addSigners_) external { // make sure avocado_ is an actual Avocado if (!avoFactory.isAvocado(avocado_)) { revert AvoSignersList__InvalidParams(); } uint256 addSignersLength_ = addSigners_.length; if (addSignersLength_ == 1) { // if adding just one signer, using `isSigner()` is cheaper than looping through allowed signers here if (IAvocadoMultisigV1(avocado_).isSigner(addSigners_[0])) { if (trackInStorage) { // `.add()` method also checks if signer is already mapped to the address if (_avocadosPerSigner[addSigners_[0]].add(avocado_)) { emit SignerMappingAdded(addSigners_[0], avocado_); } // else ignore silently if mapping is already present } else { emit SignerMappingAdded(addSigners_[0], avocado_); } } else { revert AvoSignersList__InvalidParams(); } } else { // get actual signers present at AvocadoMultisig to make sure data here will be correct address[] memory allowedSigners_ = IAvocadoMultisigV1(avocado_).signers(); uint256 allowedSignersLength_ = allowedSigners_.length; // track last allowed signer index for loop performance improvements uint256 lastAllowedSignerIndex_ = 0; // keeping `isAllowedSigner_` outside the loop so it is not re-initialized in each loop -> cheaper bool isAllowedSigner_ = false; for (uint256 i; i < addSignersLength_; ) { // because allowedSigners_ and addSigners_ must be ordered ascending, the for loop can be optimized // each new cycle to start from the position where the last signer has been found for (uint256 j = lastAllowedSignerIndex_; j < allowedSignersLength_; ) { if (allowedSigners_[j] == addSigners_[i]) { isAllowedSigner_ = true; lastAllowedSignerIndex_ = j + 1; // set to j+1 so that next cycle starts at next array position break; } // could be optimized by checking if allowedSigners_[j] > recoveredSigners_[i] // and immediately skipping with a `break;` if so. Because that implies that the recoveredSigners_[i] // can not be present in allowedSigners_ due to ascending sort. // But that would optimize the failing invalid case and increase cost for the default case where // the input data is valid -> skip. unchecked { ++j; } } // validate signer trying to add mapping for is really allowed at AvocadoMultisig if (!isAllowedSigner_) { revert AvoSignersList__InvalidParams(); } else { // reset `isAllowedSigner_` for next loop isAllowedSigner_ = false; } if (trackInStorage) { // `.add()` method also checks if signer is already mapped to the address if (_avocadosPerSigner[addSigners_[i]].add(avocado_)) { emit SignerMappingAdded(addSigners_[i], avocado_); } // else ignore silently if mapping is already present } else { emit SignerMappingAdded(addSigners_[i], avocado_); } unchecked { ++i; } } } } /// @inheritdoc IAvoSignersList function syncRemoveAvoSignerMappings(address avocado_, address[] calldata removeSigners_) external { uint256 removeSignersLength_ = removeSigners_.length; // make sure `avocado_` is an actual Avocado if (!avoFactory.isAvocado(avocado_)) { if (trackInStorage) { // Avocado could have been self-destructed. remove any mapping that might still exist for input data bool removedAny_ = false; for (uint256 i; i < removeSignersLength_; ) { // `.remove()` method also checks if signer is not mapped to the address if (_avocadosPerSigner[removeSigners_[i]].remove(avocado_)) { emit SignerMappingRemoved(removeSigners_[i], avocado_); removedAny_ = true; } unchecked { ++i; } } if (removedAny_) { return; } } revert AvoSignersList__InvalidParams(); } if (removeSignersLength_ == 1) { // if removing just one signer, using `isSigner()` is cheaper than looping through allowed signers here if (IAvocadoMultisigV1(avocado_).isSigner(removeSigners_[0])) { revert AvoSignersList__InvalidParams(); } else { if (trackInStorage) { // `.remove()` method also checks if signer is not mapped to the address if (_avocadosPerSigner[removeSigners_[0]].remove(avocado_)) { emit SignerMappingRemoved(removeSigners_[0], avocado_); } // else ignore silently if mapping is not present } else { emit SignerMappingRemoved(removeSigners_[0], avocado_); } } } else { // get actual signers present at AvocadoMultisig to make sure data here will be correct address[] memory allowedSigners_ = IAvocadoMultisigV1(avocado_).signers(); uint256 allowedSignersLength_ = allowedSigners_.length; // track last signer index where signer to be removed was > allowedSigners for loop performance improvements uint256 lastSkipSignerIndex_ = 0; for (uint256 i; i < removeSignersLength_; ) { for (uint256 j = lastSkipSignerIndex_; j < allowedSignersLength_; ) { if (allowedSigners_[j] == removeSigners_[i]) { // validate signer trying to remove mapping for is really not present at AvocadoMultisig revert AvoSignersList__InvalidParams(); } if (allowedSigners_[j] > removeSigners_[i]) { // because allowedSigners_ and removeSigners_ must be ordered ascending the for loop can be optimized: // there is no need to search further once the signer to be removed is < than the allowed signer. // and the next cycle can start from that position lastSkipSignerIndex_ = j; break; } unchecked { ++j; } } if (trackInStorage) { // `.remove()` method also checks if signer is not mapped to the address if (_avocadosPerSigner[removeSigners_[i]].remove(avocado_)) { emit SignerMappingRemoved(removeSigners_[i], avocado_); } // else ignore silently if mapping is not present } else { emit SignerMappingRemoved(removeSigners_[i], avocado_); } unchecked { ++i; } } } } }
// 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 // OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. pragma solidity ^0.8.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes32 lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values in the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// 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 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; } }
// 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 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 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 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; interface IAvoConfigV1 { struct AvocadoMultisigConfig { uint256 authorizedMinFee; uint256 authorizedMaxFee; address authorizedFeeCollector; } struct AvoDepositManagerConfig { address depositToken; } struct AvoSignersListConfig { bool trackInStorage; } /// @notice config for AvocadoMultisig function avocadoMultisigConfig() external view returns (AvocadoMultisigConfig memory); /// @notice config for AvoDepositManager function avoDepositManagerConfig() external view returns (AvoDepositManagerConfig memory); /// @notice config for AvoSignersList function avoSignersListConfig() external view returns (AvoSignersListConfig memory); }
// 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 for the Avocado contract used for Create2 address computation function avocadoBytecode() external view returns (bytes32); }
// 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_ calculate 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; }
// SPDX-License-Identifier: MIT pragma solidity >=0.8.18; interface IAvoSignersList { /// @notice adds mappings of `addSigners_` to an Avocado `avocado_`. /// checks the data present at the Avocado to validate input data. /// /// If `trackInStorage` flag is set to false, then only an event will be emitted for off-chain tracking. /// The contract itself will not track avocados per signer on-chain! /// /// Silently ignores `addSigners_` that are already added /// /// There is expectedly no need for this method to be called by anyone other than the Avocado itself. function syncAddAvoSignerMappings(address avocado_, address[] calldata addSigners_) external; /// @notice removes mappings of `removeSigners_` from an Avocado `avocado_`. /// checks the data present at the Avocado to validate input data. /// /// If `trackInStorage` flag is set to false, then only an event will be emitted for off-chain tracking. /// The contract itself will not track avocados per signer on-chain! /// /// Silently ignores `addSigners_` that are already removed /// /// There is expectedly no need for this method to be called by anyone other than the Avocado itself. function syncRemoveAvoSignerMappings(address avocado_, address[] calldata removeSigners_) external; }
{ "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"},{"internalType":"contract IAvoConfigV1","name":"avoConfigV1_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AvoSignersList__InvalidParams","type":"error"},{"inputs":[],"name":"AvoSignersList__NotTracked","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"signer","type":"address"},{"indexed":false,"internalType":"address","name":"avocado","type":"address"}],"name":"SignerMappingAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"signer","type":"address"},{"indexed":false,"internalType":"address","name":"avocado","type":"address"}],"name":"SignerMappingRemoved","type":"event"},{"inputs":[],"name":"avoFactory","outputs":[{"internalType":"contract IAvoFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"signer_","type":"address"}],"name":"avocados","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"signer_","type":"address"}],"name":"avocadosCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"avocado_","type":"address"},{"internalType":"address","name":"signer_","type":"address"}],"name":"isSignerOf","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"avocado_","type":"address"}],"name":"signers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"avocado_","type":"address"}],"name":"signersCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"avocado_","type":"address"},{"internalType":"address[]","name":"addSigners_","type":"address[]"}],"name":"syncAddAvoSignerMappings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"avocado_","type":"address"},{"internalType":"address[]","name":"removeSigners_","type":"address[]"}],"name":"syncRemoveAvoSignerMappings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trackInStorage","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60c06040523480156200001157600080fd5b5060405162001c1b38038062001c1b83398101604081905262000034916200010d565b81816001600160a01b038216620000615760405160016242d74960e01b0319815260040160405180910390fd5b816001600160a01b03166080816001600160a01b0316815250506000816001600160a01b03166389492a9f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000e291906200014c565b51151560a05250620001ad9350505050565b6001600160a01b03811681146200010a57600080fd5b50565b600080604083850312156200012157600080fd5b82516200012e81620000f4565b60208401519092506200014181620000f4565b809150509250929050565b6000602082840312156200015f57600080fd5b604051602081016001600160401b03811182821017156200019057634e487b7160e01b600052604160045260246000fd5b60405282518015158114620001a457600080fd5b81529392505050565b60805160a0516119ed6200022e6000396000818161019d0152818161030f015281816105b90152818161087101528181610b5601528181610d5c01528181610fc30152818161124701526113950152600081816101510152818161021a015281816103e00152818161053e015281816106ee0152610ce901526119ed6000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c8063863deb1111610076578063b0c5ea881161005b578063b0c5ea881461014c578063dbbd903514610198578063e247cefc146101bf57600080fd5b8063863deb1114610124578063a1153e7f1461013957600080fd5b80633ff2de1a146100a857806357834213146100ce578063736c0d5b146100ee57806378dbcfdb14610101575b600080fd5b6100bb6100b6366004611665565b6101d2565b6040519081526020015b60405180910390f35b6100e16100dc366004611665565b61030b565b6040516100c59190611682565b6100e16100fc366004611665565b610398565b61011461010f3660046116dc565b6104f6565b60405190151581526020016100c5565b610137610132366004611715565b6106a9565b005b610137610147366004611715565b610ca2565b6101737f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c5565b6101147f000000000000000000000000000000000000000000000000000000000000000081565b6100bb6101cd366004611665565b611391565b6040517f52f1a1c000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906352f1a1c090602401602060405180830381865afa158015610263573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610287919061179d565b61029357506000919050565b8173ffffffffffffffffffffffffffffffffffffffff1663e40956b16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102de573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061030291906117bf565b60ff1692915050565b60607f0000000000000000000000000000000000000000000000000000000000000000610364576040517fd7fddb6f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600090815260656020526040902061039290611418565b92915050565b6040517f52f1a1c000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301526060917f0000000000000000000000000000000000000000000000000000000000000000909116906352f1a1c090602401602060405180830381865afa158015610429573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061044d919061179d565b61046557505060408051600081526020810190915290565b8173ffffffffffffffffffffffffffffffffffffffff166346f0975a6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156104b0573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526103929190810190611821565b6040517f52f1a1c000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526000917f0000000000000000000000000000000000000000000000000000000000000000909116906352f1a1c090602401602060405180830381865afa158015610587573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ab919061179d565b6105b757506000610392565b7f0000000000000000000000000000000000000000000000000000000000000000610673576040517f7df73e2700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152841690637df73e2790602401602060405180830381865afa158015610648573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066c919061179d565b9050610392565b73ffffffffffffffffffffffffffffffffffffffff821660009081526065602052604090206106a29084611425565b9392505050565b6040517f52f1a1c000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f000000000000000000000000000000000000000000000000000000000000000016906352f1a1c090602401602060405180830381865afa158015610735573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610759919061179d565b61078f576040517fffbd28b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060018190036109da578373ffffffffffffffffffffffffffffffffffffffff16637df73e27848460008181106107c8576107c8611904565b90506020020160208101906107dd9190611665565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015610846573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086a919061179d565b156109a8577f000000000000000000000000000000000000000000000000000000000000000015610974576108f18460656000868660008181106108b0576108b0611904565b90506020020160208101906108c59190611665565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002090611454565b1561096f577fdb65a3861ff24d4601416e207700686ed3bcc853f458b4c70d58ba1a2f0e12d08383600081811061092a5761092a611904565b905060200201602081019061093f9190611665565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291871660208301520160405180910390a15b610c9c565b7fdb65a3861ff24d4601416e207700686ed3bcc853f458b4c70d58ba1a2f0e12d08383600081811061092a5761092a611904565b6040517fffbd28b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008473ffffffffffffffffffffffffffffffffffffffff166346f0975a6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610a27573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610a6d9190810190611821565b8051909150600080805b85811015610c9657825b84811015610b1857888883818110610a9b57610a9b611904565b9050602002016020810190610ab09190611665565b73ffffffffffffffffffffffffffffffffffffffff16868281518110610ad857610ad8611904565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603610b105760019250610b098184611962565b9350610b18565b600101610a81565b5081610b50576040517fffbd28b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600091507f000000000000000000000000000000000000000000000000000000000000000015610c1657610b9489606560008b8b868181106108b0576108b0611904565b15610c11577fdb65a3861ff24d4601416e207700686ed3bcc853f458b4c70d58ba1a2f0e12d0888883818110610bcc57610bcc611904565b9050602002016020810190610be19190611665565b6040805173ffffffffffffffffffffffffffffffffffffffff9283168152918c1660208301520160405180910390a15b610c8e565b7fdb65a3861ff24d4601416e207700686ed3bcc853f458b4c70d58ba1a2f0e12d0888883818110610c4957610c49611904565b9050602002016020810190610c5e9190611665565b6040805173ffffffffffffffffffffffffffffffffffffffff9283168152918c1660208301520160405180910390a15b600101610a77565b50505050505b50505050565b6040517f52f1a1c000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015282917f0000000000000000000000000000000000000000000000000000000000000000909116906352f1a1c090602401602060405180830381865afa158015610d32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d56919061179d565b610eb1577f0000000000000000000000000000000000000000000000000000000000000000156109a8576000805b82811015610e7057610de78660656000888886818110610da657610da6611904565b9050602002016020810190610dbb9190611665565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002090611476565b15610e68577faae34dfbee40ae4cd6046178cae82eca956d66b9ea50c37c7a6c2ee0f3ca7aac858583818110610e1f57610e1f611904565b9050602002016020810190610e349190611665565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291891660208301520160405180910390a1600191505b600101610d84565b508015610e7e575050505050565b506040517fffbd28b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060010361106f578373ffffffffffffffffffffffffffffffffffffffff16637df73e2784846000818110610ee857610ee8611904565b9050602002016020810190610efd9190611665565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015610f66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8a919061179d565b15610fc1576040517fffbd28b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000001561103b57611002846065600086866000818110610da657610da6611904565b1561096f577faae34dfbee40ae4cd6046178cae82eca956d66b9ea50c37c7a6c2ee0f3ca7aac8383600081811061092a5761092a611904565b7faae34dfbee40ae4cd6046178cae82eca956d66b9ea50c37c7a6c2ee0f3ca7aac8383600081811061092a5761092a611904565b60008473ffffffffffffffffffffffffffffffffffffffff166346f0975a6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156110bc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526111029190810190611821565b80519091506000805b8481101561138757815b838110156112445787878381811061112f5761112f611904565b90506020020160208101906111449190611665565b73ffffffffffffffffffffffffffffffffffffffff1685828151811061116c5761116c611904565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16036111c1576040517fffbd28b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8787838181106111d3576111d3611904565b90506020020160208101906111e89190611665565b73ffffffffffffffffffffffffffffffffffffffff1685828151811061121057611210611904565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16111561123c57809250611244565b600101611115565b507f0000000000000000000000000000000000000000000000000000000000000000156113075761128588606560008a8a86818110610da657610da6611904565b15611302577faae34dfbee40ae4cd6046178cae82eca956d66b9ea50c37c7a6c2ee0f3ca7aac8787838181106112bd576112bd611904565b90506020020160208101906112d29190611665565b6040805173ffffffffffffffffffffffffffffffffffffffff9283168152918b1660208301520160405180910390a15b61137f565b7faae34dfbee40ae4cd6046178cae82eca956d66b9ea50c37c7a6c2ee0f3ca7aac87878381811061133a5761133a611904565b905060200201602081019061134f9190611665565b6040805173ffffffffffffffffffffffffffffffffffffffff9283168152918b1660208301520160405180910390a15b60010161110b565b5050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006113ea576040517fd7fddb6f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600090815260656020526040902061039290611498565b606060006106a2836114a2565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415156106a2565b60006106a28373ffffffffffffffffffffffffffffffffffffffff84166114fe565b60006106a28373ffffffffffffffffffffffffffffffffffffffff841661154d565b6000610392825490565b6060816000018054806020026020016040519081016040528092919081815260200182805480156114f257602002820191906000526020600020905b8154815260200190600101908083116114de575b50505050509050919050565b600081815260018301602052604081205461154557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610392565b506000610392565b60008181526001830160205260408120548015611636576000611571600183611975565b855490915060009061158590600190611975565b90508181146115ea5760008660000182815481106115a5576115a5611904565b90600052602060002001549050808760000184815481106115c8576115c8611904565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806115fb576115fb611988565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610392565b6000915050610392565b73ffffffffffffffffffffffffffffffffffffffff8116811461166257600080fd5b50565b60006020828403121561167757600080fd5b81356106a281611640565b6020808252825182820181905260009190848201906040850190845b818110156116d057835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161169e565b50909695505050505050565b600080604083850312156116ef57600080fd5b82356116fa81611640565b9150602083013561170a81611640565b809150509250929050565b60008060006040848603121561172a57600080fd5b833561173581611640565b9250602084013567ffffffffffffffff8082111561175257600080fd5b818601915086601f83011261176657600080fd5b81358181111561177557600080fd5b8760208260051b850101111561178a57600080fd5b6020830194508093505050509250925092565b6000602082840312156117af57600080fd5b815180151581146106a257600080fd5b6000602082840312156117d157600080fd5b815160ff811681146106a257600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b805161181c81611640565b919050565b6000602080838503121561183457600080fd5b825167ffffffffffffffff8082111561184c57600080fd5b818501915085601f83011261186057600080fd5b815181811115611872576118726117e2565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156118b5576118b56117e2565b6040529182528482019250838101850191888311156118d357600080fd5b938501935b828510156118f8576118e985611811565b845293850193928501926118d8565b98975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561039257610392611933565b8181038181111561039257610392611933565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220455967dd61ae1140513c08119339cf343d44db062c4a64f2df82793d997a5c9e64736f6c63430008120033000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e6870000000000000000000000001412121e487478498b355c227c77d5ed6cf1798d
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100a35760003560e01c8063863deb1111610076578063b0c5ea881161005b578063b0c5ea881461014c578063dbbd903514610198578063e247cefc146101bf57600080fd5b8063863deb1114610124578063a1153e7f1461013957600080fd5b80633ff2de1a146100a857806357834213146100ce578063736c0d5b146100ee57806378dbcfdb14610101575b600080fd5b6100bb6100b6366004611665565b6101d2565b6040519081526020015b60405180910390f35b6100e16100dc366004611665565b61030b565b6040516100c59190611682565b6100e16100fc366004611665565b610398565b61011461010f3660046116dc565b6104f6565b60405190151581526020016100c5565b610137610132366004611715565b6106a9565b005b610137610147366004611715565b610ca2565b6101737f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e68781565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c5565b6101147f000000000000000000000000000000000000000000000000000000000000000181565b6100bb6101cd366004611665565b611391565b6040517f52f1a1c000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301526000917f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e687909116906352f1a1c090602401602060405180830381865afa158015610263573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610287919061179d565b61029357506000919050565b8173ffffffffffffffffffffffffffffffffffffffff1663e40956b16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156102de573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061030291906117bf565b60ff1692915050565b60607f0000000000000000000000000000000000000000000000000000000000000001610364576040517fd7fddb6f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600090815260656020526040902061039290611418565b92915050565b6040517f52f1a1c000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301526060917f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e687909116906352f1a1c090602401602060405180830381865afa158015610429573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061044d919061179d565b61046557505060408051600081526020810190915290565b8173ffffffffffffffffffffffffffffffffffffffff166346f0975a6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156104b0573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526103929190810190611821565b6040517f52f1a1c000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526000917f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e687909116906352f1a1c090602401602060405180830381865afa158015610587573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ab919061179d565b6105b757506000610392565b7f0000000000000000000000000000000000000000000000000000000000000001610673576040517f7df73e2700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152841690637df73e2790602401602060405180830381865afa158015610648573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061066c919061179d565b9050610392565b73ffffffffffffffffffffffffffffffffffffffff821660009081526065602052604090206106a29084611425565b9392505050565b6040517f52f1a1c000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e68716906352f1a1c090602401602060405180830381865afa158015610735573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610759919061179d565b61078f576040517fffbd28b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060018190036109da578373ffffffffffffffffffffffffffffffffffffffff16637df73e27848460008181106107c8576107c8611904565b90506020020160208101906107dd9190611665565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015610846573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086a919061179d565b156109a8577f000000000000000000000000000000000000000000000000000000000000000115610974576108f18460656000868660008181106108b0576108b0611904565b90506020020160208101906108c59190611665565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002090611454565b1561096f577fdb65a3861ff24d4601416e207700686ed3bcc853f458b4c70d58ba1a2f0e12d08383600081811061092a5761092a611904565b905060200201602081019061093f9190611665565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291871660208301520160405180910390a15b610c9c565b7fdb65a3861ff24d4601416e207700686ed3bcc853f458b4c70d58ba1a2f0e12d08383600081811061092a5761092a611904565b6040517fffbd28b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008473ffffffffffffffffffffffffffffffffffffffff166346f0975a6040518163ffffffff1660e01b8152600401600060405180830381865afa158015610a27573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610a6d9190810190611821565b8051909150600080805b85811015610c9657825b84811015610b1857888883818110610a9b57610a9b611904565b9050602002016020810190610ab09190611665565b73ffffffffffffffffffffffffffffffffffffffff16868281518110610ad857610ad8611904565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603610b105760019250610b098184611962565b9350610b18565b600101610a81565b5081610b50576040517fffbd28b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600091507f000000000000000000000000000000000000000000000000000000000000000115610c1657610b9489606560008b8b868181106108b0576108b0611904565b15610c11577fdb65a3861ff24d4601416e207700686ed3bcc853f458b4c70d58ba1a2f0e12d0888883818110610bcc57610bcc611904565b9050602002016020810190610be19190611665565b6040805173ffffffffffffffffffffffffffffffffffffffff9283168152918c1660208301520160405180910390a15b610c8e565b7fdb65a3861ff24d4601416e207700686ed3bcc853f458b4c70d58ba1a2f0e12d0888883818110610c4957610c49611904565b9050602002016020810190610c5e9190611665565b6040805173ffffffffffffffffffffffffffffffffffffffff9283168152918c1660208301520160405180910390a15b600101610a77565b50505050505b50505050565b6040517f52f1a1c000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015282917f000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e687909116906352f1a1c090602401602060405180830381865afa158015610d32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d56919061179d565b610eb1577f0000000000000000000000000000000000000000000000000000000000000001156109a8576000805b82811015610e7057610de78660656000888886818110610da657610da6611904565b9050602002016020810190610dbb9190611665565b73ffffffffffffffffffffffffffffffffffffffff168152602081019190915260400160002090611476565b15610e68577faae34dfbee40ae4cd6046178cae82eca956d66b9ea50c37c7a6c2ee0f3ca7aac858583818110610e1f57610e1f611904565b9050602002016020810190610e349190611665565b6040805173ffffffffffffffffffffffffffffffffffffffff928316815291891660208301520160405180910390a1600191505b600101610d84565b508015610e7e575050505050565b506040517fffbd28b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060010361106f578373ffffffffffffffffffffffffffffffffffffffff16637df73e2784846000818110610ee857610ee8611904565b9050602002016020810190610efd9190611665565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015610f66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f8a919061179d565b15610fc1576040517fffbd28b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000011561103b57611002846065600086866000818110610da657610da6611904565b1561096f577faae34dfbee40ae4cd6046178cae82eca956d66b9ea50c37c7a6c2ee0f3ca7aac8383600081811061092a5761092a611904565b7faae34dfbee40ae4cd6046178cae82eca956d66b9ea50c37c7a6c2ee0f3ca7aac8383600081811061092a5761092a611904565b60008473ffffffffffffffffffffffffffffffffffffffff166346f0975a6040518163ffffffff1660e01b8152600401600060405180830381865afa1580156110bc573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526111029190810190611821565b80519091506000805b8481101561138757815b838110156112445787878381811061112f5761112f611904565b90506020020160208101906111449190611665565b73ffffffffffffffffffffffffffffffffffffffff1685828151811061116c5761116c611904565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16036111c1576040517fffbd28b700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8787838181106111d3576111d3611904565b90506020020160208101906111e89190611665565b73ffffffffffffffffffffffffffffffffffffffff1685828151811061121057611210611904565b602002602001015173ffffffffffffffffffffffffffffffffffffffff16111561123c57809250611244565b600101611115565b507f0000000000000000000000000000000000000000000000000000000000000001156113075761128588606560008a8a86818110610da657610da6611904565b15611302577faae34dfbee40ae4cd6046178cae82eca956d66b9ea50c37c7a6c2ee0f3ca7aac8787838181106112bd576112bd611904565b90506020020160208101906112d29190611665565b6040805173ffffffffffffffffffffffffffffffffffffffff9283168152918b1660208301520160405180910390a15b61137f565b7faae34dfbee40ae4cd6046178cae82eca956d66b9ea50c37c7a6c2ee0f3ca7aac87878381811061133a5761133a611904565b905060200201602081019061134f9190611665565b6040805173ffffffffffffffffffffffffffffffffffffffff9283168152918b1660208301520160405180910390a15b60010161110b565b5050505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000016113ea576040517fd7fddb6f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600090815260656020526040902061039290611498565b606060006106a2836114a2565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260018301602052604081205415156106a2565b60006106a28373ffffffffffffffffffffffffffffffffffffffff84166114fe565b60006106a28373ffffffffffffffffffffffffffffffffffffffff841661154d565b6000610392825490565b6060816000018054806020026020016040519081016040528092919081815260200182805480156114f257602002820191906000526020600020905b8154815260200190600101908083116114de575b50505050509050919050565b600081815260018301602052604081205461154557508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610392565b506000610392565b60008181526001830160205260408120548015611636576000611571600183611975565b855490915060009061158590600190611975565b90508181146115ea5760008660000182815481106115a5576115a5611904565b90600052602060002001549050808760000184815481106115c8576115c8611904565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806115fb576115fb611988565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610392565b6000915050610392565b73ffffffffffffffffffffffffffffffffffffffff8116811461166257600080fd5b50565b60006020828403121561167757600080fd5b81356106a281611640565b6020808252825182820181905260009190848201906040850190845b818110156116d057835173ffffffffffffffffffffffffffffffffffffffff168352928401929184019160010161169e565b50909695505050505050565b600080604083850312156116ef57600080fd5b82356116fa81611640565b9150602083013561170a81611640565b809150509250929050565b60008060006040848603121561172a57600080fd5b833561173581611640565b9250602084013567ffffffffffffffff8082111561175257600080fd5b818601915086601f83011261176657600080fd5b81358181111561177557600080fd5b8760208260051b850101111561178a57600080fd5b6020830194508093505050509250925092565b6000602082840312156117af57600080fd5b815180151581146106a257600080fd5b6000602082840312156117d157600080fd5b815160ff811681146106a257600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b805161181c81611640565b919050565b6000602080838503121561183457600080fd5b825167ffffffffffffffff8082111561184c57600080fd5b818501915085601f83011261186057600080fd5b815181811115611872576118726117e2565b8060051b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f830116810181811085821117156118b5576118b56117e2565b6040529182528482019250838101850191888311156118d357600080fd5b938501935b828510156118f8576118e985611811565b845293850193928501926118d8565b98975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561039257610392611933565b8181038181111561039257610392611933565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220455967dd61ae1140513c08119339cf343d44db062c4a64f2df82793d997a5c9e64736f6c63430008120033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e6870000000000000000000000001412121e487478498b355c227c77d5ed6cf1798d
-----Decoded View---------------
Arg [0] : avoFactory_ (address): 0xe981E50c7c47F0Df8826B5ce3F533f5E4440e687
Arg [1] : avoConfigV1_ (address): 0x1412121E487478498b355C227c77D5ED6CF1798d
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000e981e50c7c47f0df8826b5ce3f533f5e4440e687
Arg [1] : 0000000000000000000000001412121e487478498b355c227c77d5ed6cf1798d
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.