Contract

0x6e7E2A4e77706Fac5a392E42c3c66C1fdA9De17A

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

-

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Latest 1 internal transaction

Parent Transaction Hash Block From To
4105012024-12-14 18:07:376 days ago1734199657  Contract Creation0 S
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
AvoSignersList

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 10000000 runs

Other Settings:
default evmVersion
File 1 of 9 : AvoSignersList.sol
// 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;
                }
            }
        }
    }
}

File 2 of 9 : Address.sol
// 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);
        }
    }
}

File 3 of 9 : EnumerableSet.sol
// 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;
    }
}

File 4 of 9 : AvocadoMultisigStructs.sol
// 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;
    }
}

File 5 of 9 : IAvocadoMultisigV1.sol
// 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);
}

File 6 of 9 : IAvoConfigV1.sol
// 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);
}

File 7 of 9 : IAvoFactory.sol
// 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);
}

File 8 of 9 : IAvoRegistry.sol
// 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;
}

File 9 of 9 : IAvoSignersList.sol
// 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;
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 10000000
  },
  "libraries": {},
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"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"}]

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


Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.