Contract

0x1e5Ec00e7598d3f60471e45138c5d3c5172326eB

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
1905942024-12-08 0:42:0314 days ago1733618523  Contract Creation0 S
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x732D01C9...883c3B5DD
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
AvoFactory

Compiler Version
v0.8.18+commit.87f61d96

Optimization Enabled:
Yes with 10000000 runs

Other Settings:
default evmVersion
File 1 of 10 : AvoFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.18;

import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

import { IAvocado } from "./Avocado.sol";
import { IAvocadoMultisigV1 } from "./interfaces/IAvocadoMultisigV1.sol";
import { IAvoRegistry } from "./interfaces/IAvoRegistry.sol";
import { IAvoFactory } from "./interfaces/IAvoFactory.sol";
import { IAvoForwarder } from "./interfaces/IAvoForwarder.sol";

// --------------------------- DEVELOPER NOTES -----------------------------------------
// @dev To deploy a new version of Avocado (proxy), the new factory contract must be deployed
// and AvoFactoryProxy upgraded to that new contract (to update the cached bytecode).
// -------------------------------------------------------------------------------------

// empty interface used for Natspec docs for nice layout in automatically generated docs:
//
/// @title  AvoFactory v1.0.0
/// @notice Deploys Avocado smart wallet contracts at deterministic addresses using Create2.
///
/// Upgradeable through AvoFactoryProxy
interface AvoFactory_V1 {

}

abstract contract AvoFactoryErrors {
    /// @notice thrown when trying to deploy an Avocado for a smart contract as owner
    error AvoFactory__NotEOA();

    /// @notice thrown when a caller is not authorized to execute a certain action
    error AvoFactory__Unauthorized();

    /// @notice thrown when a method is called with invalid params (e.g. zero address)
    error AvoFactory__InvalidParams();

    /// @notice thrown when deploy is called with an index where index-1 is not deployed yet.
    ///         After index > 5, index must be used sequential.
    error AvoFactory__IndexNonSequential();

    /// @notice thrown when deploy methods are called before an implementation is defined
    error AvoFactory__ImplementationNotDefined();
}

abstract contract AvoFactoryConstants is AvoFactoryErrors, IAvoFactory {
    /// @notice hardcoded Avocado creation code.
    //
    // Avocado (proxy) should never change because it influences the deterministic address
    bytes public constant avocadoCreationCode =
        hex"60a060405234801561001057600080fd5b5060408051808201825260048152638c65738960e01b60208201529051600091339161003c91906100b2565b600060405180830381855afa9150503d8060008114610077576040519150601f19603f3d011682016040523d82523d6000602084013e61007c565b606091505b506020810151604090910151608052600080546001600160a01b0319166001600160a01b03909216919091179055506100e19050565b6000825160005b818110156100d357602081860181015185830152016100b9565b506000920191825250919050565b6080516101476100fb6000396000600601526101476000f3fe60806040527f00000000000000000000000000000000000000000000000000000000000000006000357f4d42058500000000000000000000000000000000000000000000000000000000810161006f5773ffffffffffffffffffffffffffffffffffffffff821660005260206000f35b7f68beab3f0000000000000000000000000000000000000000000000000000000081036100a0578160005260206000f35b73ffffffffffffffffffffffffffffffffffffffff600054167f874095c60000000000000000000000000000000000000000000000000000000082036100ea578060005260206000f35b3660008037600080366000845af49150503d6000803e80801561010c573d6000f35b3d6000fdfea2646970667358221220bf171834b0948ebffd196d6a4208dbd5d0a71f76dfac9d90499de318c59558fc64736f6c63430008120033";

    /// @notice cached avocado (proxy) bytecode hash to optimize gas usage
    bytes32 public constant avocadoBytecode = keccak256(abi.encodePacked(avocadoCreationCode));

    /// @notice  registry holding the valid versions (addresses) for Avocado smart wallet implementation contracts.
    ///          The registry is used to verify a valid version before setting a new `avoImpl`
    ///          as default for new deployments.
    IAvoRegistry public immutable avoRegistry;

    constructor(IAvoRegistry avoRegistry_) {
        avoRegistry = avoRegistry_;

        // check hardcoded avocadoBytecode matches expected value
        if (avocadoBytecode != 0x6b106ae0e3afae21508569f62d81c7d826b900a2e9ccc973ba97abfae026fc54) {
            revert AvoFactory__InvalidParams();
        }
    }
}

abstract contract AvoFactoryVariables is AvoFactoryConstants, Initializable {
    // @dev Before variables here are vars from Initializable:
    // uint8 private _initialized;
    // bool private _initializing;

    /// @notice Avocado logic contract address that new Avocado deployments point to.
    ///         Modifiable only by `avoRegistry`.
    address public avoImpl;

    // 10 bytes empty

    // ----------------------- slot 1 to 101 ---------------------------

    // create some storage slot gaps because variables below will be replaced with transient storage vars after
    // EIP-1153 becomes available.
    uint256[101] private __gaps;

    // ----------------------- slot 102 ----------------------------

    /// @dev owner of Avocado that is currently being deployed.
    // set before deploying proxy, to return in callback transientDeployData()
    address internal _transientDeployOwner;

    /// @dev index Avocado that is currently being deployed.
    // set before deploying proxy, to return in callback transientDeployData()
    uint32 internal _transientDeployIndex;

    // 8 bytes empty

    // ----------------------- slot 103 ----------------------------
    /// @dev version address Avocado that is currently being deployed.
    // set before deploying proxy, to return in callback transientDeployData()
    address internal _transientDeployVersion;

    // 12 bytes empty

    /// @dev resets transient storage to default value (1). 1 is better than 0 for optimizing gas refunds
    /// because total refund amount is capped to 20% of tx gas cost (EIP-3529).
    function _resetTransientStorage() internal {
        assembly {
            // Store 1 in the transient storage 102 & 103
            sstore(102, 1)
            sstore(103, 1)
        }
    }
}

abstract contract AvoFactoryEvents {
    /// @notice Emitted when a new Avocado has been deployed
    event AvocadoDeployed(address indexed owner, uint32 indexed index, uint16 avoType, address indexed avocado);

    /// @notice Emitted when a new Avocado has been deployed with a non-default version
    event AvocadoDeployedWithVersion(
        address indexed owner,
        uint32 index,
        uint16 avoType,
        address indexed avocado,
        address indexed version
    );
}

abstract contract AvoFactoryCore is AvoFactoryErrors, AvoFactoryConstants, AvoFactoryVariables, AvoFactoryEvents {
    constructor(IAvoRegistry avoRegistry_) AvoFactoryConstants(avoRegistry_) {
        if (address(avoRegistry_) == address(0)) {
            revert AvoFactory__InvalidParams();
        }

        // Ensure logic contract initializer is not abused by disabling initializing
        // see https://forum.openzeppelin.com/t/security-advisory-initialize-uups-implementation-contracts/15301
        // and https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#initializing_the_implementation_contract
        _disableInitializers();
    }
}

contract AvoFactory is AvoFactoryCore {
    /***********************************|
    |              MODIFIERS            |
    |__________________________________*/

    /// @dev reverts if `owner_` is a contract
    modifier onlyEOA(address owner_) {
        if (owner_ == address(0) || Address.isContract(owner_)) {
            revert AvoFactory__NotEOA();
        }
        _;
    }

    /// @dev reverts if `msg.sender` is not `avoRegistry`
    modifier onlyRegistry() {
        if (msg.sender != address(avoRegistry)) {
            revert AvoFactory__Unauthorized();
        }
        _;
    }

    /***********************************|
    |    CONSTRUCTOR / INITIALIZERS     |
    |__________________________________*/

    /// @notice constructor sets the immutable `avoRegistry` address
    constructor(IAvoRegistry avoRegistry_) AvoFactoryCore(avoRegistry_) {}

    /// @notice initializes the contract
    function initialize() public initializer {
        _resetTransientStorage();
    }

    /***********************************|
    |            PUBLIC API             |
    |__________________________________*/

    /// @inheritdoc IAvoFactory
    function isAvocado(address avoSmartWallet_) external view returns (bool) {
        if (avoSmartWallet_ == address(0) || !Address.isContract(avoSmartWallet_)) {
            // can not recognize isAvocado when not yet deployed
            return false;
        }

        // get the owner from the Avocado smart wallet
        try IAvocado(avoSmartWallet_)._data() returns (uint256 data_) {
            address owner_;
            uint32 index_;

            // cast last 20 bytes of hash to owner address and 2 bytes before to index via low level assembly
            assembly {
                owner_ := and(data_, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
                index_ := and(shr(160, data_), 0xFFFFFFFF) // shift right and mask to read index
            }

            // compute the Avocado address for that owner & index and check it against given address. if it
            // matches it guarantees the address is an Avocado deployed by this AvoFactory because factory
            // address is part of deterministic address computation
            if (computeAvocado(owner_, index_) == avoSmartWallet_) {
                return true;
            }
        } catch {
            // if fetching data_ (owner & index) doesn't work, can not determine if it's an Avocado smart wallet
            return false;
        }

        return false;
    }

    /// @inheritdoc IAvoFactory
    function deploy(address owner_, uint32 index_) external onlyEOA(owner_) returns (address deployedAvocado_) {
        _transientDeployVersion = avoImpl;
        if (_transientDeployVersion == address(0)) {
            revert AvoFactory__ImplementationNotDefined();
        }
        // check that a smart wallet at index -1 already exists (if > 0) to guarantee sequential use (easier to iterate)
        if (index_ > 5 && !Address.isContract(computeAvocado(owner_, index_ - 1))) {
            revert AvoFactory__IndexNonSequential();
        }

        _transientDeployOwner = owner_;
        _transientDeployIndex = index_;

        // deploy Avocado deterministically using low level CREATE2 opcode to use hardcoded Avocado bytecode
        bytes32 salt_ = _getSalt(owner_, index_);
        bytes memory byteCode_ = avocadoCreationCode;
        assembly {
            deployedAvocado_ := create2(0, add(byteCode_, 0x20), mload(byteCode_), salt_)
        }

        _resetTransientStorage();

        // initialize AvocadoMultisig through proxy with IAvocadoMultisig interface.
        // if version or owner would not be correctly set at the deployed contract, this would revert.
        IAvocadoMultisigV1(deployedAvocado_).initialize();

        emit AvocadoDeployed(owner_, index_, 0, deployedAvocado_);
    }

    /// @inheritdoc IAvoFactory
    function deployWithVersion(
        address owner_,
        uint32 index_,
        address avoVersion_
    ) external onlyEOA(owner_) returns (address deployedAvocado_) {
        avoRegistry.requireValidAvoVersion(avoVersion_);

        // check that a smart wallet at index -1 already exists (if > 0) to guarantee sequential use (easier to iterate)
        if (index_ > 5 && !Address.isContract(computeAvocado(owner_, index_ - 1))) {
            revert AvoFactory__InvalidParams();
        }

        _transientDeployOwner = owner_;
        _transientDeployIndex = index_;
        _transientDeployVersion = avoVersion_;

        // deploy Avocado deterministically using low level CREATE2 opcode to use hardcoded Avocado bytecode
        bytes32 salt_ = _getSalt(owner_, index_);
        bytes memory byteCode_ = avocadoCreationCode;
        assembly {
            deployedAvocado_ := create2(0, add(byteCode_, 0x20), mload(byteCode_), salt_)
        }

        _resetTransientStorage();

        // initialize AvocadoMultisig through proxy with IAvocadoMultisig interface.
        // if version or owner would not be correctly set at the deployed contract, this would revert.
        IAvocadoMultisigV1(deployedAvocado_).initialize();

        emit AvocadoDeployedWithVersion(owner_, index_, 0, deployedAvocado_, avoVersion_);
    }

    /// @inheritdoc IAvoFactory
    function computeAvocado(address owner_, uint32 index_) public view returns (address computedAddress_) {
        if (Address.isContract(owner_)) {
            // owner of a Avocado must be an EOA, if it's a contract return zero address
            return address(0);
        }

        // replicate Create2 address determination logic
        bytes32 hash = keccak256(
            abi.encodePacked(bytes1(0xff), address(this), _getSalt(owner_, index_), avocadoBytecode)
        );

        // cast last 20 bytes of hash to address via low level assembly
        assembly {
            computedAddress_ := and(hash, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
        }
    }

    function transientDeployData() external view returns (address version_, uint256 data_) {
        data_ =
            /* (uint256(0) << 192) | type currently not used, always 0 */
            (uint256(_transientDeployIndex) << 160) |
            uint256(uint160(_transientDeployOwner));
        return (_transientDeployVersion, data_);
    }

    /***********************************|
    |            ONLY  REGISTRY         |
    |__________________________________*/

    /// @inheritdoc IAvoFactory
    function setAvoImpl(address avoImpl_) external onlyRegistry {
        // do not `registry.requireValidAvoVersion()` because sender is registry anyway
        avoImpl = avoImpl_;
    }

    /***********************************|
    |              INTERNAL             |
    |__________________________________*/

    /// @dev            gets the salt used for deterministic deployment for `owner_` and `index_`
    /// @return         the bytes32 (keccak256) salt
    function _getSalt(address owner_, uint32 index_) internal pure returns (bytes32) {
        // use owner + index of wallet nr per EOA (plus "type", currently always 0)
        // Note CREATE2 deployments take into account the deployers address (i.e. this factory address)
        return keccak256(abi.encode(owner_, index_, 0));
    }
}

File 2 of 10 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.2;

import "../../utils/AddressUpgradeable.sol";

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
 * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
 * case an upgrade adds a module that needs to be initialized.
 *
 * For example:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * contract MyToken is ERC20Upgradeable {
 *     function initialize() initializer public {
 *         __ERC20_init("MyToken", "MTK");
 *     }
 * }
 * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
 *     function initializeV2() reinitializer(2) public {
 *         __ERC20Permit_init("MyToken");
 *     }
 * }
 * ```
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * [CAUTION]
 * ====
 * Avoid leaving a contract uninitialized.
 *
 * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
 * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
 * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
 *
 * [.hljs-theme-light.nopadding]
 * ```
 * /// @custom:oz-upgrades-unsafe-allow constructor
 * constructor() {
 *     _disableInitializers();
 * }
 * ```
 * ====
 */
abstract contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     * @custom:oz-retyped-from bool
     */
    uint8 private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint8 version);

    /**
     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
     * `onlyInitializing` functions can be used to initialize parent contracts.
     *
     * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
     * constructor.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        bool isTopLevelCall = !_initializing;
        require(
            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
            "Initializable: contract is already initialized"
        );
        _initialized = 1;
        if (isTopLevelCall) {
            _initializing = true;
        }
        _;
        if (isTopLevelCall) {
            _initializing = false;
            emit Initialized(1);
        }
    }

    /**
     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
     * used to initialize parent contracts.
     *
     * A reinitializer may be used after the original initialization step. This is essential to configure modules that
     * are added through upgrades and that require initialization.
     *
     * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
     * cannot be nested. If one is invoked in the context of another, execution will revert.
     *
     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
     * a contract, executing them in the right order is up to the developer or operator.
     *
     * WARNING: setting the version to 255 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint8 version) {
        require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
        _initialized = version;
        _initializing = true;
        _;
        _initializing = false;
        emit Initialized(version);
    }

    /**
     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
     * {initializer} and {reinitializer} modifiers, directly or indirectly.
     */
    modifier onlyInitializing() {
        require(_initializing, "Initializable: contract is not initializing");
        _;
    }

    /**
     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
     * through proxies.
     *
     * Emits an {Initialized} event the first time it is successfully executed.
     */
    function _disableInitializers() internal virtual {
        require(!_initializing, "Initializable: contract is initializing");
        if (_initialized < type(uint8).max) {
            _initialized = type(uint8).max;
            emit Initialized(type(uint8).max);
        }
    }

    /**
     * @dev Internal function that returns the initialized version. Returns `_initialized`
     */
    function _getInitializedVersion() internal view returns (uint8) {
        return _initialized;
    }

    /**
     * @dev Internal function that returns the initialized version. Returns `_initializing`
     */
    function _isInitializing() internal view returns (bool) {
        return _initializing;
    }
}

File 3 of 10 : AddressUpgradeable.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 AddressUpgradeable {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 4 of 10 : 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 5 of 10 : Avocado.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.18;

/// @title   IAvocado
/// @notice  interface to access internal vars on-chain
interface IAvocado {
    function _avoImpl() external view returns (address);

    function _data() external view returns (uint256);

    function _owner() external view returns (address);
}

/// @title      Avocado
/// @notice     Proxy for Avocados as deployed by the AvoFactory.
///             Basic Proxy with fallback to delegate and address for implementation contract at storage 0x0
//
// @dev        If this contract changes then the deployment addresses for new Avocados through factory change too!!
//             Relayers might want to pass in version as new param then to forward to the correct factory
contract Avocado {
    /// @notice flexible immutable data slot.
    /// first 20 bytes: address owner
    /// next 4 bytes: uint32 index
    /// next 1 byte: uint8 type
    /// next 9 bytes: used flexible for use-cases found in the future
    uint256 internal immutable _data;

    /// @notice address of the Avocado logic / implementation contract. IMPORTANT: SAME STORAGE SLOT AS FOR PROXY
    //
    // @dev    _avoImpl MUST ALWAYS be the first declared variable here in the proxy and in the logic contract
    //         when upgrading, the storage at memory address 0x0 is upgraded (first slot).
    //         To reduce deployment costs this variable is internal but can still be retrieved with
    //         _avoImpl(), see code and comments in fallback below
    address internal _avoImpl;

    /// @notice   sets _avoImpl & immutable _data, fetching it from msg.sender.
    //
    // @dev      those values are not input params to not influence the deterministic Create2 address!
    constructor() {
        // "\x8c\x65\x73\x89" is hardcoded bytes of function selector for transientDeployData()
        (, bytes memory deployData_) = msg.sender.staticcall(bytes("\x8c\x65\x73\x89"));

        address impl_;
        uint256 data_;
        assembly {
            // cast first 20 bytes to version address (_avoImpl)
            impl_ := mload(add(deployData_, 0x20))

            // cast bytes in position 0x40 to uint256 data; deployData_ plus 0x40 due to padding
            data_ := mload(add(deployData_, 0x40))
        }

        _data = data_;
        _avoImpl = impl_;
    }

    /// @notice Delegates the current call to `_avoImpl` unless one of the view methods is called:
    ///         `_avoImpl()` returns the address for `_avoImpl`, `_owner()` returns the first
    ///         20 bytes of `_data`, `_data()` returns `_data`.
    //
    // @dev    Mostly based on OpenZeppelin Proxy.sol
    // logic contract must not implement a function `_avoImpl()`, `_owner()` or  `_data()`
    // as they will not be callable due to collision
    fallback() external payable {
        uint256 data_ = _data;
        assembly {
            let functionSelector_ := calldataload(0)

            // 0xb2bdfa7b = function selector for _owner()
            if eq(functionSelector_, 0xb2bdfa7b00000000000000000000000000000000000000000000000000000000) {
                // store address owner at memory address 0x0, loading only last 20 bytes through the & mask
                mstore(0, and(data_, 0x000000000000000000000000ffffffffffffffffffffffffffffffffffffffff))
                return(0, 0x20) // send 32 bytes of memory slot 0 as return value
            }

            // 0x68beab3f = function selector for _data()
            if eq(functionSelector_, 0x68beab3f00000000000000000000000000000000000000000000000000000000) {
                mstore(0, data_) // store uint256 _data at memory address 0x0
                return(0, 0x20) // send 32 bytes of memory slot 0 as return value
            }

            // load address avoImpl_ from storage
            let avoImpl_ := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)

            // first 4 bytes of calldata specify which function to call.
            // if those first 4 bytes == 874095c6 (function selector for _avoImpl()) then we return the _avoImpl address
            // The value is right padded to 32-bytes with 0s
            if eq(functionSelector_, 0x874095c600000000000000000000000000000000000000000000000000000000) {
                mstore(0, avoImpl_) // store address avoImpl_ at memory address 0x0
                return(0, 0x20) // send 32 bytes of memory slot 0 as return value
            }

            // @dev code below is taken from OpenZeppelin Proxy.sol _delegate function

            // Copy msg.data. We take full control of memory in this inline assembly
            // block because it will not return to Solidity code. We overwrite the
            // Solidity scratch pad at memory position 0.
            calldatacopy(0, 0, calldatasize())

            // Call the implementation.
            // out and outsize are 0 because we don't know the size yet.
            let result := delegatecall(gas(), avoImpl_, 0, calldatasize(), 0, 0)

            // Copy the returned data.
            returndatacopy(0, 0, returndatasize())

            switch result
            // delegatecall returns 0 on error.
            case 0 {
                revert(0, returndatasize())
            }
            default {
                return(0, returndatasize())
            }
        }
    }
}

File 6 of 10 : 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 7 of 10 : 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 8 of 10 : 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 9 of 10 : IAvoForwarder.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.18;

import { IAvoFactory } from "./IAvoFactory.sol";

interface IAvoForwarder {
    /// @notice returns the AvoFactory (proxy) address
    function avoFactory() external view returns (IAvoFactory);
}

File 10 of 10 : 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;
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IAvoRegistry","name":"avoRegistry_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AvoFactory__ImplementationNotDefined","type":"error"},{"inputs":[],"name":"AvoFactory__IndexNonSequential","type":"error"},{"inputs":[],"name":"AvoFactory__InvalidParams","type":"error"},{"inputs":[],"name":"AvoFactory__NotEOA","type":"error"},{"inputs":[],"name":"AvoFactory__Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint32","name":"index","type":"uint32"},{"indexed":false,"internalType":"uint16","name":"avoType","type":"uint16"},{"indexed":true,"internalType":"address","name":"avocado","type":"address"}],"name":"AvocadoDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint32","name":"index","type":"uint32"},{"indexed":false,"internalType":"uint16","name":"avoType","type":"uint16"},{"indexed":true,"internalType":"address","name":"avocado","type":"address"},{"indexed":true,"internalType":"address","name":"version","type":"address"}],"name":"AvocadoDeployedWithVersion","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"inputs":[],"name":"avoImpl","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"avoRegistry","outputs":[{"internalType":"contract IAvoRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"avocadoBytecode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"avocadoCreationCode","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"}],"name":"computeAvocado","outputs":[{"internalType":"address","name":"computedAddress_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"}],"name":"deploy","outputs":[{"internalType":"address","name":"deployedAvocado_","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"uint32","name":"index_","type":"uint32"},{"internalType":"address","name":"avoVersion_","type":"address"}],"name":"deployWithVersion","outputs":[{"internalType":"address","name":"deployedAvocado_","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"avoSmartWallet_","type":"address"}],"name":"isAvocado","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"avoImpl_","type":"address"}],"name":"setAvoImpl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transientDeployData","outputs":[{"internalType":"address","name":"version_","type":"address"},{"internalType":"uint256","name":"data_","type":"uint256"}],"stateMutability":"view","type":"function"}]

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100c95760003560e01c80638c65738911610081578063ba6f63a11161005b578063ba6f63a114610219578063d817a8c91461022c578063db4214871461023f57600080fd5b80638c657389146101715780639cae7aa8146101dd578063afecd5411461020457600080fd5b806352f1a1c0116100b257806352f1a1c014610131578063665e3058146101545780638129fc1c1461016957600080fd5b806328807b8b146100ce5780632adc4cf71461011e575b600080fd5b6000546100f49062010000900473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6100f461012c366004610e96565b610255565b61014461013f366004610ec9565b610581565b6040519015158152602001610115565b610167610162366004610ec9565b6106bb565b005b610167610777565b6066546067546040805173ffffffffffffffffffffffffffffffffffffffff92831681529183167401000000000000000000000000000000000000000090930460a01b77ffffffff00000000000000000000000000000000000000001692909217602082015201610115565b6100f47f0000000000000000000000003ffbe8381da8eb6783171b9c48fe4eb88712cae381565b61020c610914565b6040516101159190610f0f565b6100f4610227366004610f60565b610933565b6100f461023a366004610e96565b610c6f565b610247610e14565b604051908152602001610115565b60008273ffffffffffffffffffffffffffffffffffffffff81161580610291575073ffffffffffffffffffffffffffffffffffffffff81163b15155b156102c8576040517f6e31ab6d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600054606780546201000090920473ffffffffffffffffffffffffffffffffffffffff167fffffffffffffffffffffffff00000000000000000000000000000000000000009092168217905561034a576040517ffd97024300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60058363ffffffff1611801561038b575061038961036d8561023a600187610fa3565b73ffffffffffffffffffffffffffffffffffffffff163b151590565b155b156103c2576040517fe98b740b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6066805463ffffffff851674010000000000000000000000000000000000000000027fffffffffffffffff00000000000000000000000000000000000000000000000090911673ffffffffffffffffffffffffffffffffffffffff871617179055600061048385856040805173ffffffffffffffffffffffffffffffffffffffff8416602082015263ffffffff8316918101919091526000606082018190529060800160405160208183030381529060405280519060200120905092915050565b90506000604051806102800160405280610242815260200161102461024291399050818151602083016000f593506104c060016066556001606755565b8373ffffffffffffffffffffffffffffffffffffffff16638129fc1c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561050857600080fd5b505af115801561051c573d6000803e3d6000fd5b50506040516000815273ffffffffffffffffffffffffffffffffffffffff808816935063ffffffff891692508916907fb2e6130f590922fd6e9fbd3b5f2c7aab70d0c0a10ff31b9ee72231511e038a8e9060200160405180910390a450505092915050565b600073ffffffffffffffffffffffffffffffffffffffff821615806105bb575073ffffffffffffffffffffffffffffffffffffffff82163b155b156105c857506000919050565b8173ffffffffffffffffffffffffffffffffffffffff166368beab3f6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561064d575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820190925261064a91810190610fee565b60015b61065957506000919050565b73ffffffffffffffffffffffffffffffffffffffff8181169060a083901c63ffffffff1690851661068a8383610c6f565b73ffffffffffffffffffffffffffffffffffffffff16036106b057506001949350505050565b505050506000919050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003ffbe8381da8eb6783171b9c48fe4eb88712cae3161461072a576040517f14389b5500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000805473ffffffffffffffffffffffffffffffffffffffff90921662010000027fffffffffffffffffffff0000000000000000000000000000000000000000ffff909216919091179055565b600054610100900460ff16158080156107975750600054600160ff909116105b806107b15750303b1580156107b1575060005460ff166001145b610841576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a6564000000000000000000000000000000000000606482015260840160405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055801561089f57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6108ae60016066556001606755565b801561091157600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50565b6040518061028001604052806102428152602001611024610242913981565b60008373ffffffffffffffffffffffffffffffffffffffff8116158061096f575073ffffffffffffffffffffffffffffffffffffffff81163b15155b156109a6576040517f6e31ab6d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517efe90e300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301527f0000000000000000000000003ffbe8381da8eb6783171b9c48fe4eb88712cae3169062fe90e39060240160006040518083038186803b158015610a2b57600080fd5b505afa158015610a3f573d6000803e3d6000fd5b5050505060058463ffffffff16118015610a685750610a6661036d8661023a600188610fa3565b155b15610a9f576040517f8bce6cc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6066805473ffffffffffffffffffffffffffffffffffffffff8781167fffffffffffffffff00000000000000000000000000000000000000000000000090921682177401000000000000000000000000000000000000000063ffffffff891690810291909117909355606780547fffffffffffffffffffffffff00000000000000000000000000000000000000001691871691909117905560408051602080820193909352808201939093526000606080850182905282518086039091018152608085018084528151919094012061030085019092526102428084529193909291906110249060a001399050818151602083016000f59350610ba660016066556001606755565b8373ffffffffffffffffffffffffffffffffffffffff16638129fc1c6040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610bee57600080fd5b505af1158015610c02573d6000803e3d6000fd5b50506040805163ffffffff8a1681526000602082015273ffffffffffffffffffffffffffffffffffffffff808a16945088811693508b16917fe44ca7de6035e335f7ef293b045b26617fe756757838b93ba868d6176bee55c3910160405180910390a45050509392505050565b600073ffffffffffffffffffffffffffffffffffffffff83163b15610c9657506000610e0e565b6040805173ffffffffffffffffffffffffffffffffffffffff851660208083019190915263ffffffff8516828401526000606080840182905284518085039091018152608090930190935281519101207fff0000000000000000000000000000000000000000000000000000000000000090309060405180610280016040528061024281526020016110246102429139604051602001610d369190611007565b60405160208183030381529060405280519060200120604051602001610dbe94939291907fff0000000000000000000000000000000000000000000000000000000000000094909416845260609290921b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660018401526015830152603582015260550190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052805160209091012073ffffffffffffffffffffffffffffffffffffffff169150505b92915050565b60405180610280016040528061024281526020016110246102429139604051602001610e409190611007565b6040516020818303038152906040528051906020012081565b803573ffffffffffffffffffffffffffffffffffffffff81168114610e7d57600080fd5b919050565b803563ffffffff81168114610e7d57600080fd5b60008060408385031215610ea957600080fd5b610eb283610e59565b9150610ec060208401610e82565b90509250929050565b600060208284031215610edb57600080fd5b610ee482610e59565b9392505050565b60005b83811015610f06578181015183820152602001610eee565b50506000910152565b6020815260008251806020840152610f2e816040850160208701610eeb565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600080600060608486031215610f7557600080fd5b610f7e84610e59565b9250610f8c60208501610e82565b9150610f9a60408501610e59565b90509250925092565b63ffffffff828116828216039080821115610fe7577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b5092915050565b60006020828403121561100057600080fd5b5051919050565b60008251611019818460208701610eeb565b919091019291505056fe60a060405234801561001057600080fd5b5060408051808201825260048152638c65738960e01b60208201529051600091339161003c91906100b2565b600060405180830381855afa9150503d8060008114610077576040519150601f19603f3d011682016040523d82523d6000602084013e61007c565b606091505b506020810151604090910151608052600080546001600160a01b0319166001600160a01b03909216919091179055506100e19050565b6000825160005b818110156100d357602081860181015185830152016100b9565b506000920191825250919050565b6080516101476100fb6000396000600601526101476000f3fe60806040527f00000000000000000000000000000000000000000000000000000000000000006000357f4d42058500000000000000000000000000000000000000000000000000000000810161006f5773ffffffffffffffffffffffffffffffffffffffff821660005260206000f35b7f68beab3f0000000000000000000000000000000000000000000000000000000081036100a0578160005260206000f35b73ffffffffffffffffffffffffffffffffffffffff600054167f874095c60000000000000000000000000000000000000000000000000000000082036100ea578060005260206000f35b3660008037600080366000845af49150503d6000803e80801561010c573d6000f35b3d6000fdfea2646970667358221220bf171834b0948ebffd196d6a4208dbd5d0a71f76dfac9d90499de318c59558fc64736f6c63430008120033a2646970667358221220a122c70d7c91d4fd694cd79dc27e876a6bf3c1dca93ce832bf9d4fd8f782581564736f6c63430008120033

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.