S Price: $0.584268 (-1.81%)

Contract

0x8820db193191cc0F50F72eD030d08E4d49984C91

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
EdgeFactoryPerspective

Compiler Version
v0.8.24+commit.e11b9ed9

Optimization Enabled:
Yes with 20000 runs

Other Settings:
cancun EvmVersion
File 1 of 9 : EdgeFactoryPerspective.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.24;

import {IEdgeFactory} from "../../EdgeFactory/interfaces/IEdgeFactory.sol";
import {BasePerspective} from "../implementation/BasePerspective.sol";

/// @title EdgeFactoryPerspective
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice A contract that verifies whether a vault was deployed by the Edge Factory.
contract EdgeFactoryPerspective is BasePerspective {
    /// @notice Creates a new EdgeFactoryPerspective instance.
    /// @param edgeFactory_ The address of the EdgeFactory contract.
    constructor(address edgeFactory_) BasePerspective(edgeFactory_) {}

    /// @inheritdoc BasePerspective
    function name() public pure virtual override returns (string memory) {
        return "Edge Factory Perspective";
    }

    /// @inheritdoc BasePerspective
    function perspectiveVerifyInternal(address vault) internal virtual override {
        testProperty(IEdgeFactory(address(vaultFactory)).isDeployed(vault), ERROR__FACTORY);
    }

    /// @inheritdoc BasePerspective
    function isVerified(address vault) public view virtual override returns (bool) {
        return IEdgeFactory(address(vaultFactory)).isDeployed(vault);
    }

    /// @inheritdoc BasePerspective
    function verifiedLength() public view virtual override returns (uint256) {
        address[][] memory list = IEdgeFactory(address(vaultFactory)).getDeploymentsListSlice(0, type(uint256).max);

        uint256 count;
        for (uint256 i = 0; i < list.length; ++i) {
            count += list[i].length;
        }

        return count;
    }

    /// @inheritdoc BasePerspective
    function verifiedArray() public view virtual override returns (address[] memory) {
        address[][] memory list = IEdgeFactory(address(vaultFactory)).getDeploymentsListSlice(0, type(uint256).max);

        uint256 count;
        for (uint256 i = 0; i < list.length; ++i) {
            count += list[i].length;
        }

        address[] memory result = new address[](count);
        count = 0;

        for (uint256 i = 0; i < list.length; ++i) {
            for (uint256 j = 0; j < list[i].length; ++j) {
                result[count++] = list[i][j];
            }
        }

        return result;
    }
}

File 2 of 9 : IEdgeFactory.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity >=0.8.0;

/// @title IEdgeFactory
/// @custom:security-contact [email protected]
/// @author Objective Labs (https://www.objectivelabs.io/)
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Factory contract for deploying and configuring Edge markets
interface IEdgeFactory {
    /// @notice Parameters for deploying a vault
    /// @param asset The underlying asset of the vault
    /// @param irm The address of the interest rate model, ignored if escrow
    /// @param escrow True if the vault is collateral only, false if it is borrowable
    struct VaultParams {
        address asset;
        address irm;
        bool escrow;
    }

    /// @notice Parameters for configuring an oracle adapter in the router
    /// @param base The base token address
    /// @param adapter The oracle adapter address
    struct AdapterParams {
        address base;
        address adapter;
    }

    /// @notice Parameters for configuring the oracle router
    /// @param externalResolvedVaults Array of external ERC4626 vaults to be resolved
    /// @param adapters Array of oracle adapter configurations
    struct RouterParams {
        address[] externalResolvedVaults;
        AdapterParams[] adapters;
    }

    /// @notice Parameters for setting loan-to-value ratios between vaults
    /// @param collateralVaultIndex Index of the collateral vault in the vaults array
    /// @param controllerVaultIndex Index of the controller vault in the vaults array
    /// @param borrowLTV The loan-to-value ratio for borrowing (1e4 = 100%)
    /// @param liquidationLTV The loan-to-value ratio for liquidation (1e4 = 100%)
    struct LTVParams {
        uint256 collateralVaultIndex;
        uint256 controllerVaultIndex;
        uint16 borrowLTV;
        uint16 liquidationLTV;
    }

    /// @notice Parameters for deploying an Edge market
    /// @param vaults Array of vault configurations
    /// @param router Router configuration
    /// @param ltv Array of LTV configurations between vaults
    /// @param unitOfAccount The unit of account token address
    struct DeployParams {
        VaultParams[] vaults;
        RouterParams router;
        LTVParams[] ltv;
        address unitOfAccount;
    }

    /// @notice Emitted when a new Edge market is deployed
    /// @param router The deployed router contract
    /// @param vaults Array of constituent vaults
    event EdgeDeployed(address indexed router, address[] vaults);

    /// @notice Thrown when attempting to deploy with fewer than 2 vaults
    error E_TooFewVaults();

    /// @notice Thrown when attempting to query deployments with invalid indices
    error E_BadQuery();

    /// @notice Deploys an Edge market
    /// @param params The deployment parameters
    /// @dev This function performs the following steps:
    /// @dev 1. Deploys a router
    /// @dev 2. Configures price adapters in the router
    /// @dev 3. Resolves external vaults in the router
    /// @dev 4. Deploys and configures vaults with specified parameters
    /// @dev 5. Sets up LTV relationships between vaults
    /// @dev 6. Renounces governance for all deployed contracts
    /// @dev After deployment, governance is permanently renounced
    /// @dev Reverts if:
    /// @dev - Less than 2 vaults are specified in params
    /// @return The deployed router contract
    /// @return An array of vault addresses in the market
    function deploy(DeployParams calldata params) external returns (address, address[] memory);

    /// @notice The factory contract for deploying vaults
    function eVaultFactory() external view returns (address);

    /// @notice The factory contract for deploying routers
    function eulerRouterFactory() external view returns (address);

    /// @notice Address of the escrowed collateral perspective contract
    function escrowedCollateralPerspective() external view returns (address);

    /// @notice Get the array of vaults for a given deployment index
    function getDeployment(uint256 i) external view returns (address[] memory);

    /// @notice Get the total number of deployments
    /// @return count The total number of Edge markets deployed
    function getDeploymentsListLength() external view returns (uint256);

    /// @notice Get a slice of vault deployment addresses
    /// @param start The start index of the slice from the list of deployed routers (inclusive)
    /// @param end The end index of the slice from the list of deployed routers (exclusive)
    /// @return list An array of arrays of vault addresses, where each inner array contains all vaults for a single Edge
    /// market
    function getDeploymentsListSlice(uint256 start, uint256 end) external view returns (address[][] memory list);

    /// @notice Whether a vault belongs to any one Edge market
    function isDeployed(address vault) external view returns (bool);
}

File 3 of 9 : BasePerspective.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.24;

import {EnumerableSet} from "openzeppelin-contracts/utils/structs/EnumerableSet.sol";
import {GenericFactory} from "evk/GenericFactory/GenericFactory.sol";

import {IPerspective} from "./interfaces/IPerspective.sol";
import {PerspectiveErrors} from "./PerspectiveErrors.sol";

/// @title BasePerspective
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice A base contract for implementing a perspective.
abstract contract BasePerspective is IPerspective, PerspectiveErrors {
    using EnumerableSet for EnumerableSet.AddressSet;

    struct Transient {
        uint256 placeholder;
    }

    GenericFactory public immutable vaultFactory;

    EnumerableSet.AddressSet internal verified;
    Transient private transientVerified;
    Transient private transientErrors;
    Transient private transientVault;
    Transient private transientFailEarly;

    /// @notice Creates a new BasePerspective instance.
    /// @param vaultFactory_ The address of the GenericFactory contract.
    constructor(address vaultFactory_) {
        vaultFactory = GenericFactory(vaultFactory_);
    }

    /// @inheritdoc IPerspective
    function name() public view virtual returns (string memory);

    /// @inheritdoc IPerspective
    function perspectiveVerify(address vault, bool failEarly) public virtual {
        bytes32 transientVerifiedHash;
        assembly {
            mstore(0, vault)
            mstore(32, transientVerified.slot)
            transientVerifiedHash := keccak256(0, 64)

            // if optimistically verified, return
            if eq(tload(transientVerifiedHash), true) { return(0, 0) }
        }

        // if already verified, return
        if (verified.contains(vault)) return;

        address _vault;
        bool _failEarly;
        assembly {
            _vault := tload(transientVault.slot)
            _failEarly := tload(transientFailEarly.slot)
            tstore(transientVault.slot, vault)
            tstore(transientFailEarly.slot, failEarly)

            // optimistically assume that the vault is verified
            tstore(transientVerifiedHash, true)
        }

        // perform the perspective verification
        perspectiveVerifyInternal(vault);

        uint256 errors;
        assembly {
            // restore the cached values
            tstore(transientVault.slot, _vault)
            tstore(transientFailEarly.slot, _failEarly)

            errors := tload(transientErrors.slot)
        }

        // if early fail was not requested, we need to check for any property errors that may have occurred.
        // otherwise, we would have already reverted if there were any property errors
        if (errors != 0) revert PerspectiveError(address(this), vault, errors);

        // set the vault as permanently verified
        verified.add(vault);
        emit PerspectiveVerified(vault);
    }

    /// @inheritdoc IPerspective
    function isVerified(address vault) public view virtual returns (bool) {
        return verified.contains(vault);
    }

    /// @inheritdoc IPerspective
    function verifiedLength() public view virtual returns (uint256) {
        return verified.length();
    }

    /// @inheritdoc IPerspective
    function verifiedArray() public view virtual returns (address[] memory) {
        return verified.values();
    }

    /// @notice Internal function to perform verification of a vault.
    /// @dev This function must be defined in derived contracts to implement specific verification logic.
    /// @dev This function should use the testProperty function to test the properties of the vault.
    /// @param vault The address of the vault to verify.
    function perspectiveVerifyInternal(address vault) internal virtual;

    /// @notice Tests a property condition and handles error based on the result.
    /// @param condition The boolean condition to test, typically a property of a vault. i.e governor == address(0)
    /// @param errorCode The error code to use if the condition fails.
    function testProperty(bool condition, uint256 errorCode) internal virtual {
        if (condition) return;
        if (errorCode == 0) revert PerspectivePanic();

        bool failEarly;
        assembly {
            failEarly := tload(transientFailEarly.slot)
        }

        if (failEarly) {
            address vault;
            assembly {
                vault := tload(transientVault.slot)
            }
            revert PerspectiveError(address(this), vault, errorCode);
        } else {
            assembly {
                let errors := tload(transientErrors.slot)
                tstore(transientErrors.slot, or(errors, errorCode))
            }
        }
    }
}

File 4 of 9 : EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.20;

/**
 * @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.
 *
 * ```solidity
 * 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 is the index of the value in the `values` array plus 1.
        // Position 0 is used to mean a value is not in the set.
        mapping(bytes32 value => uint256) _positions;
    }

    /**
     * @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._positions[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 cache the value's position to prevent multiple reads from the same storage slot
        uint256 position = set._positions[value];

        if (position != 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 valueIndex = position - 1;
            uint256 lastIndex = set._values.length - 1;

            if (valueIndex != lastIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the lastValue to the index where the value to delete is
                set._values[valueIndex] = lastValue;
                // Update the tracked position of the lastValue (that was just moved)
                set._positions[lastValue] = position;
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the tracked position for the deleted slot
            delete set._positions[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._positions[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;

        assembly ("memory-safe") {
            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;

        assembly ("memory-safe") {
            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;

        assembly ("memory-safe") {
            result := store
        }

        return result;
    }
}

File 5 of 9 : GenericFactory.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

import {BeaconProxy} from "./BeaconProxy.sol";
import {MetaProxyDeployer} from "./MetaProxyDeployer.sol";

/// @title IComponent
/// @notice Minimal interface which must be implemented by the contract deployed by the factory
interface IComponent {
    /// @notice Function replacing the constructor in proxied contracts
    /// @param creator The new contract's creator address
    function initialize(address creator) external;
}

/// @title GenericFactory
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice The factory allows permissionless creation of upgradeable or non-upgradeable proxy contracts and serves as a
/// beacon for the upgradeable ones
contract GenericFactory is MetaProxyDeployer {
    // Constants

    uint256 internal constant REENTRANCYLOCK__UNLOCKED = 1;
    uint256 internal constant REENTRANCYLOCK__LOCKED = 2;

    // State

    /// @title ProxyConfig
    /// @notice This struct is used to store the configuration of a proxy deployed by the factory
    struct ProxyConfig {
        // If true, proxy is an instance of the BeaconProxy
        bool upgradeable;
        // Address of the implementation contract
        // May be an out-of-date value, if upgradeable (handled by getProxyConfig)
        address implementation;
        // The metadata attached to every call passing through the proxy
        bytes trailingData;
    }

    uint256 private reentrancyLock;

    /// @notice Address of the account authorized to upgrade the implementation contract
    address public upgradeAdmin;
    /// @notice Address of the implementation contract, which the deployed proxies will delegate-call to
    /// @dev The contract must implement the `IComponent` interface
    address public implementation;
    /// @notice A lookup for configurations of the proxy contracts deployed by the factory
    mapping(address proxy => ProxyConfig) internal proxyLookup;
    /// @notice An array of addresses of all the proxies deployed by the factory
    address[] public proxyList;

    // Events

    /// @notice The factory is created
    event Genesis();

    /// @notice A new proxy is created
    /// @param proxy Address of the new proxy
    /// @param upgradeable If true, proxy is an instance of the BeaconProxy. If false, the proxy is a minimal meta proxy
    /// @param implementation Address of the implementation contract, at the time the proxy was deployed
    /// @param trailingData The metadata that will be attached to every call passing through the proxy
    event ProxyCreated(address indexed proxy, bool upgradeable, address implementation, bytes trailingData);

    /// @notice Set a new implementation contract. All the BeaconProxies are upgraded to the new logic
    /// @param newImplementation Address of the new implementation contract
    event SetImplementation(address indexed newImplementation);

    /// @notice Set a new upgrade admin
    /// @param newUpgradeAdmin Address of the new admin
    event SetUpgradeAdmin(address indexed newUpgradeAdmin);

    // Errors

    error E_Reentrancy();
    error E_Unauthorized();
    error E_Implementation();
    error E_BadAddress();
    error E_BadQuery();

    // Modifiers

    modifier nonReentrant() {
        if (reentrancyLock == REENTRANCYLOCK__LOCKED) revert E_Reentrancy();

        reentrancyLock = REENTRANCYLOCK__LOCKED;
        _;
        reentrancyLock = REENTRANCYLOCK__UNLOCKED;
    }

    modifier adminOnly() {
        if (msg.sender != upgradeAdmin) revert E_Unauthorized();
        _;
    }

    constructor(address admin) {
        emit Genesis();

        if (admin == address(0)) revert E_BadAddress();

        reentrancyLock = REENTRANCYLOCK__UNLOCKED;

        upgradeAdmin = admin;

        emit SetUpgradeAdmin(admin);
    }

    /// @notice A permissionless funtion to deploy new proxies
    /// @param desiredImplementation Address of the implementation contract expected to be registered in the factory
    /// during proxy creation
    /// @param upgradeable If true, the proxy will be an instance of the BeaconProxy. If false, a minimal meta proxy
    /// will be deployed
    /// @param trailingData Metadata to be attached to every call passing through the new proxy
    /// @return The address of the new proxy
    /// @dev The desired implementation serves as a protection against (unintentional) front-running of upgrades
    function createProxy(address desiredImplementation, bool upgradeable, bytes memory trailingData)
        external
        nonReentrant
        returns (address)
    {
        address _implementation = implementation;
        if (desiredImplementation == address(0)) desiredImplementation = _implementation;

        if (desiredImplementation == address(0) || desiredImplementation != _implementation) revert E_Implementation();

        // The provided trailing data is prefixed with 4 zero bytes to avoid potential selector clashing in case the
        // proxy is called with empty calldata.
        bytes memory prefixTrailingData = abi.encodePacked(bytes4(0), trailingData);
        address proxy;

        if (upgradeable) {
            proxy = address(new BeaconProxy(prefixTrailingData));
        } else {
            proxy = deployMetaProxy(desiredImplementation, prefixTrailingData);
        }

        proxyLookup[proxy] =
            ProxyConfig({upgradeable: upgradeable, implementation: desiredImplementation, trailingData: trailingData});

        proxyList.push(proxy);

        IComponent(proxy).initialize(msg.sender);

        emit ProxyCreated(proxy, upgradeable, desiredImplementation, trailingData);

        return proxy;
    }

    // EVault beacon upgrade

    /// @notice Set a new implementation contract
    /// @param newImplementation Address of the new implementation contract
    /// @dev Upgrades all existing BeaconProxies to the new logic immediately
    function setImplementation(address newImplementation) external nonReentrant adminOnly {
        if (newImplementation.code.length == 0) revert E_BadAddress();
        implementation = newImplementation;
        emit SetImplementation(newImplementation);
    }

    // Admin role

    /// @notice Transfer admin rights to a new address
    /// @param newUpgradeAdmin Address of the new admin
    /// @dev For creating non upgradeable factories, or to finalize all upgradeable proxies to current implementation,
    /// @dev set the admin to zero address.
    /// @dev If setting to address zero, make sure the implementation contract is already set
    function setUpgradeAdmin(address newUpgradeAdmin) external nonReentrant adminOnly {
        upgradeAdmin = newUpgradeAdmin;
        emit SetUpgradeAdmin(newUpgradeAdmin);
    }

    // Proxy getters

    /// @notice Get current proxy configuration
    /// @param proxy Address of the proxy to query
    /// @return config The proxy's configuration, including current implementation
    function getProxyConfig(address proxy) external view returns (ProxyConfig memory config) {
        config = proxyLookup[proxy];
        if (config.upgradeable) config.implementation = implementation;
    }

    /// @notice Check if an address is a proxy deployed with this factory
    /// @param proxy Address to check
    /// @return True if the address is a proxy
    function isProxy(address proxy) external view returns (bool) {
        return proxyLookup[proxy].implementation != address(0);
    }

    /// @notice Fetch the length of the deployed proxies list
    /// @return The length of the proxy list array
    function getProxyListLength() external view returns (uint256) {
        return proxyList.length;
    }

    /// @notice Get a slice of the deployed proxies array
    /// @param start Start index of the slice
    /// @param end End index of the slice
    /// @return list An array containing the slice of the proxy list
    function getProxyListSlice(uint256 start, uint256 end) external view returns (address[] memory list) {
        if (end == type(uint256).max) end = proxyList.length;
        if (end < start || end > proxyList.length) revert E_BadQuery();

        list = new address[](end - start);
        for (uint256 i; i < end - start; ++i) {
            list[i] = proxyList[start + i];
        }
    }
}

File 6 of 9 : IPerspective.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity >=0.8.0;

/// @title IPerspective
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice A contract that verifies the properties of a vault.
interface IPerspective {
    /// @notice Emitted when a vault is verified successfully.
    /// @param vault The address of the vault that has been verified.
    event PerspectiveVerified(address indexed vault);

    /// @notice Error thrown when a perspective verification fails.
    /// @param perspective The address of the perspective contract where the error occurred.
    /// @param vault The address of the vault being verified.
    /// @param codes The error codes indicating the reasons for verification failure.
    error PerspectiveError(address perspective, address vault, uint256 codes);

    /// @notice Error thrown when a panic occurs in the perspective contract.
    error PerspectivePanic();

    /// @notice Returns the name of the perspective.
    /// @dev Name should be unique and descriptive.
    /// @return The name of the perspective.
    function name() external view returns (string memory);

    /// @notice Verifies the properties of a vault.
    /// @param vault The address of the vault to verify.
    /// @param failEarly Determines whether to fail early on the first error encountered or allow the verification to
    /// continue and report all errors.
    function perspectiveVerify(address vault, bool failEarly) external;

    /// @notice Checks if a vault is verified.
    /// @param vault The address of the vault to check.
    /// @return True if the vault is verified, false otherwise.
    function isVerified(address vault) external view returns (bool);

    /// @notice Returns the number of verified vaults.
    /// @return The number of verified vaults.
    function verifiedLength() external view returns (uint256);

    /// @notice Returns an array of all verified vault addresses.
    /// @return An array of addresses of verified vaults.
    function verifiedArray() external view returns (address[] memory);
}

File 7 of 9 : PerspectiveErrors.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

/// @title PerspectiveErrors
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice A contract that defines the error codes for the perspectives.
abstract contract PerspectiveErrors {
    uint256 internal constant ERROR__FACTORY = 1 << 0;
    uint256 internal constant ERROR__IMPLEMENTATION = 1 << 1;
    uint256 internal constant ERROR__UPGRADABILITY = 1 << 2;
    uint256 internal constant ERROR__SINGLETON = 1 << 3;
    uint256 internal constant ERROR__NESTING = 1 << 4;
    uint256 internal constant ERROR__ORACLE_INVALID_ROUTER = 1 << 5;
    uint256 internal constant ERROR__ORACLE_GOVERNED_ROUTER = 1 << 6;
    uint256 internal constant ERROR__ORACLE_INVALID_FALLBACK = 1 << 7;
    uint256 internal constant ERROR__ORACLE_INVALID_ROUTER_CONFIG = 1 << 8;
    uint256 internal constant ERROR__ORACLE_INVALID_ADAPTER = 1 << 9;
    uint256 internal constant ERROR__UNIT_OF_ACCOUNT = 1 << 10;
    uint256 internal constant ERROR__CREATOR = 1 << 11;
    uint256 internal constant ERROR__GOVERNOR = 1 << 12;
    uint256 internal constant ERROR__FEE_RECEIVER = 1 << 13;
    uint256 internal constant ERROR__INTEREST_FEE = 1 << 14;
    uint256 internal constant ERROR__INTEREST_RATE_MODEL = 1 << 15;
    uint256 internal constant ERROR__SUPPLY_CAP = 1 << 16;
    uint256 internal constant ERROR__BORROW_CAP = 1 << 17;
    uint256 internal constant ERROR__HOOK_TARGET = 1 << 18;
    uint256 internal constant ERROR__HOOKED_OPS = 1 << 19;
    uint256 internal constant ERROR__CONFIG_FLAGS = 1 << 20;
    uint256 internal constant ERROR__NAME = 1 << 21;
    uint256 internal constant ERROR__SYMBOL = 1 << 22;
    uint256 internal constant ERROR__LIQUIDATION_DISCOUNT = 1 << 23;
    uint256 internal constant ERROR__LIQUIDATION_COOL_OFF_TIME = 1 << 24;
    uint256 internal constant ERROR__LTV_COLLATERAL_CONFIG_LENGTH = 1 << 25;
    uint256 internal constant ERROR__LTV_COLLATERAL_CONFIG_SEPARATION = 1 << 26;
    uint256 internal constant ERROR__LTV_COLLATERAL_CONFIG_BORROW = 1 << 27;
    uint256 internal constant ERROR__LTV_COLLATERAL_CONFIG_LIQUIDATION = 1 << 28;
    uint256 internal constant ERROR__LTV_COLLATERAL_RAMPING = 1 << 29;
    uint256 internal constant ERROR__LTV_COLLATERAL_RECOGNITION = 1 << 30;
}

File 8 of 9 : BeaconProxy.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

/// @title BeaconProxy
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice A proxy contract, forwarding all calls to an implementation contract, fetched from a beacon
/// @dev The proxy attaches up to 128 bytes of metadata to the delegated call data.
contract BeaconProxy {
    // ERC-1967 beacon address slot. bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)
    bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
    // Beacon implementation() selector
    bytes32 internal constant IMPLEMENTATION_SELECTOR =
        0x5c60da1b00000000000000000000000000000000000000000000000000000000;
    // Max trailing data length, 4 immutable slots
    uint256 internal constant MAX_TRAILING_DATA_LENGTH = 128;

    address internal immutable beacon;
    uint256 internal immutable metadataLength;
    bytes32 internal immutable metadata0;
    bytes32 internal immutable metadata1;
    bytes32 internal immutable metadata2;
    bytes32 internal immutable metadata3;

    event Genesis();

    constructor(bytes memory trailingData) {
        emit Genesis();

        require(trailingData.length <= MAX_TRAILING_DATA_LENGTH, "trailing data too long");

        // Beacon is always the proxy creator; store it in immutable
        beacon = msg.sender;

        // Store the beacon address in ERC-1967 slot for compatibility with block explorers
        assembly {
            sstore(BEACON_SLOT, caller())
        }

        // Record length as immutable
        metadataLength = trailingData.length;

        // Pad length with uninitialized memory so the decode will succeed
        assembly {
            mstore(trailingData, MAX_TRAILING_DATA_LENGTH)
        }
        (metadata0, metadata1, metadata2, metadata3) = abi.decode(trailingData, (bytes32, bytes32, bytes32, bytes32));
    }

    fallback() external payable {
        address beacon_ = beacon;
        uint256 metadataLength_ = metadataLength;
        bytes32 metadata0_ = metadata0;
        bytes32 metadata1_ = metadata1;
        bytes32 metadata2_ = metadata2;
        bytes32 metadata3_ = metadata3;

        assembly {
            // Fetch implementation address from the beacon
            mstore(0, IMPLEMENTATION_SELECTOR)
            // Implementation call is trusted not to revert and to return an address
            let result := staticcall(gas(), beacon_, 0, 4, 0, 32)
            let implementation := mload(0)

            // delegatecall to the implementation with trailing metadata
            calldatacopy(0, 0, calldatasize())
            mstore(calldatasize(), metadata0_)
            mstore(add(32, calldatasize()), metadata1_)
            mstore(add(64, calldatasize()), metadata2_)
            mstore(add(96, calldatasize()), metadata3_)
            result := delegatecall(gas(), implementation, 0, add(metadataLength_, calldatasize()), 0, 0)
            returndatacopy(0, 0, returndatasize())

            switch result
            case 0 { revert(0, returndatasize()) }
            default { return(0, returndatasize()) }
        }
    }
}

File 9 of 9 : MetaProxyDeployer.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.8.0;

/// @title MetaProxyDeployer
/// @custom:security-contact [email protected]
/// @author Euler Labs (https://www.eulerlabs.com/)
/// @notice Contract for deploying minimal proxies with metadata, based on EIP-3448.
/// @dev The metadata of the proxies does not include the data length as defined by EIP-3448, saving gas at a cost of
/// supporting variable size data.
contract MetaProxyDeployer {
    error E_DeploymentFailed();

    // Meta proxy bytecode from EIP-3488 https://eips.ethereum.org/EIPS/eip-3448
    bytes constant BYTECODE_HEAD = hex"600b380380600b3d393df3363d3d373d3d3d3d60368038038091363936013d73";
    bytes constant BYTECODE_TAIL = hex"5af43d3d93803e603457fd5bf3";

    /// @dev Creates a proxy for `targetContract` with metadata from `metadata`.
    /// @return addr A non-zero address if successful.
    function deployMetaProxy(address targetContract, bytes memory metadata) internal returns (address addr) {
        bytes memory code = abi.encodePacked(BYTECODE_HEAD, targetContract, BYTECODE_TAIL, metadata);

        assembly ("memory-safe") {
            addr := create(0, add(code, 32), mload(code))
        }

        if (addr == address(0)) revert E_DeploymentFailed();
    }
}

Settings
{
  "remappings": [
    "lib/euler-price-oracle:@openzeppelin/contracts/=lib/euler-price-oracle/lib/openzeppelin-contracts/contracts/",
    "lib/native-token-transfers/evm:openzeppelin-contracts/contracts/=lib/native-token-transfers/evm/lib/openzeppelin-contracts/contracts/",
    "lib/euler-earn:@openzeppelin/=lib/euler-earn/lib/openzeppelin-contracts/",
    "lib/euler-earn:@openzeppelin-upgradeable/=lib/euler-earn/lib/openzeppelin-contracts-upgradeable/contracts/",
    "lib/euler-earn:ethereum-vault-connector/=lib/euler-earn/lib/ethereum-vault-connector/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "ethereum-vault-connector/=lib/ethereum-vault-connector/src/",
    "evc/=lib/ethereum-vault-connector/src/",
    "evk/=lib/euler-vault-kit/src/",
    "evk-test/=lib/euler-vault-kit/test/",
    "euler-price-oracle/=lib/euler-price-oracle/src/",
    "euler-price-oracle-test/=lib/euler-price-oracle/test/",
    "fee-flow/=lib/fee-flow/src/",
    "reward-streams/=lib/reward-streams/src/",
    "@openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "euler-earn/=lib/euler-earn/src/",
    "native-token-transfers/=lib/native-token-transfers/evm/src/",
    "@openzeppelin-upgradeable/=lib/euler-earn/lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@pendle/core-v2/=lib/euler-price-oracle/lib/pendle-core-v2-public/contracts/",
    "@pyth/=lib/euler-price-oracle/lib/pyth-sdk-solidity/",
    "@redstone/evm-connector/=lib/euler-price-oracle/lib/redstone-oracles-monorepo/packages/evm-connector/contracts/",
    "@solady/=lib/euler-price-oracle/lib/solady/src/",
    "@uniswap/v3-core/=lib/euler-price-oracle/lib/v3-core/",
    "@uniswap/v3-periphery/=lib/euler-price-oracle/lib/v3-periphery/",
    "ERC4626/=lib/euler-earn/lib/properties/lib/ERC4626/contracts/",
    "crytic-properties/=lib/euler-earn/lib/properties/contracts/",
    "ds-test/=lib/ethereum-vault-connector/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "euler-vault-kit/=lib/euler-vault-kit/",
    "forge-gas-snapshot/=lib/euler-vault-kit/lib/permit2/lib/forge-gas-snapshot/src/",
    "forge-std/=lib/forge-std/src/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
    "layerzero-devtools/=lib/layerzero-devtools/packages/toolbox-foundry/src/",
    "layerzero-v2/=lib/layerzero-v2/",
    "openzeppelin/=lib/ethereum-vault-connector/lib/openzeppelin-contracts/contracts/",
    "pendle-core-v2-public/=lib/euler-price-oracle/lib/pendle-core-v2-public/contracts/",
    "permit2/=lib/euler-vault-kit/lib/permit2/",
    "properties/=lib/euler-earn/lib/properties/contracts/",
    "pyth-sdk-solidity/=lib/euler-price-oracle/lib/pyth-sdk-solidity/",
    "redstone-oracles-monorepo/=lib/euler-price-oracle/lib/",
    "solady/=lib/euler-price-oracle/lib/solady/src/",
    "solidity-bytes-utils/=lib/native-token-transfers/evm/lib/solidity-bytes-utils/contracts/",
    "solmate/=lib/fee-flow/lib/solmate/src/",
    "v3-core/=lib/euler-price-oracle/lib/v3-core/contracts/",
    "v3-periphery/=lib/euler-price-oracle/lib/v3-periphery/contracts/",
    "wormhole-solidity-sdk/=lib/native-token-transfers/evm/lib/wormhole-solidity-sdk/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 20000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"edgeFactory_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"perspective","type":"address"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"uint256","name":"codes","type":"uint256"}],"name":"PerspectiveError","type":"error"},{"inputs":[],"name":"PerspectivePanic","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"vault","type":"address"}],"name":"PerspectiveVerified","type":"event"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"isVerified","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"},{"internalType":"bool","name":"failEarly","type":"bool"}],"name":"perspectiveVerify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vaultFactory","outputs":[{"internalType":"contract GenericFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"verifiedArray","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"verifiedLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60a060405234801561000f575f80fd5b50604051610d5d380380610d5d83398101604081905261002e9161003f565b6001600160a01b031660805261006c565b5f6020828403121561004f575f80fd5b81516001600160a01b0381168114610065575f80fd5b9392505050565b608051610cbd6100a05f395f8181610123015281816101d80152818161043e01528181610654015261073f0152610cbd5ff3fe608060405234801561000f575f80fd5b506004361061006f575f3560e01c80638d5e21d31161004d5780638d5e21d3146100e6578063b9209e33146100fb578063d8a06f731461011e575f80fd5b806306fdde0314610073578063138721d9146100bb5780632e5896e5146100d1575b5f80fd5b604080518082018252601881527f4564676520466163746f72792050657273706563746976650000000000000000602082015290516100b291906108d9565b60405180910390f35b6100c361016a565b6040519081526020016100b2565b6100e46100df366004610971565b6102a6565b005b6100ee6103d0565b6040516100b291906109a8565b61010e610109366004610a01565b61060d565b60405190151581526020016100b2565b6101457f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100b2565b6040517fe536913d0000000000000000000000000000000000000000000000000000000081525f600482018190527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602483015290819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063e536913d906044015f60405180830381865afa15801561021c573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526102619190810190610abb565b90505f805b825181101561029f5782818151811061028157610281610bc8565b602002602001015151826102959190610c22565b9150600101610266565b5092915050565b5f8281526002602052604090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff815c016102dd57005b6102e75f846106c5565b156102f157505050565b6004805c9060055c9085905d8360055d6001835d61030e856106f6565b5f8260045d8160055d5060035c801561037d576040517f818fa2cf00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff87166024820152604481018290526064015b60405180910390fd5b6103875f876107b4565b5060405173ffffffffffffffffffffffffffffffffffffffff8716907f570e1c1f1f2e6e95bfd6d0cae607f36c3cd5ebb7bc35c2f87299924b1bcd3920905f90a2505050505050565b6040517fe536913d0000000000000000000000000000000000000000000000000000000081525f600482018190527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602483015260609173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063e536913d906044015f60405180830381865afa158015610482573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104c79190810190610abb565b90505f805b8251811015610505578281815181106104e7576104e7610bc8565b602002602001015151826104fb9190610c22565b91506001016104cc565b505f8167ffffffffffffffff81111561052057610520610a1c565b604051908082528060200260200182016040528015610549578160200160208202803683370190505b5090505f91505f5b8351811015610605575f5b84828151811061056e5761056e610bc8565b6020026020010151518110156105fc5784828151811061059057610590610bc8565b602002602001015181815181106105a9576105a9610bc8565b60200260200101518385806105bd90610c35565b9650815181106105cf576105cf610bc8565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015260010161055c565b50600101610551565b509392505050565b6040517f90184b0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f917f0000000000000000000000000000000000000000000000000000000000000000909116906390184b0290602401602060405180830381865afa15801561069b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106bf9190610c6c565b92915050565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260018301602052604081205415155b9392505050565b6040517f90184b0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301526107b1917f0000000000000000000000000000000000000000000000000000000000000000909116906390184b0290602401602060405180830381865afa158015610786573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107aa9190610c6c565b60016107d5565b50565b5f6106ef8373ffffffffffffffffffffffffffffffffffffffff841661088d565b81156107df575050565b805f03610818576040517fcb365b8800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055c801561087e576040517f818fa2cf000000000000000000000000000000000000000000000000000000008152306004808301919091525c73ffffffffffffffffffffffffffffffffffffffff811660248301526044820184905290606401610374565b60035c82811760035d50505050565b5f8181526001830160205260408120546108d257508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556106bf565b505f6106bf565b5f602080835283518060208501525f5b81811015610905578581018301518582016040015282016108e9565b505f6040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b73ffffffffffffffffffffffffffffffffffffffff811681146107b1575f80fd5b80151581146107b1575f80fd5b5f8060408385031215610982575f80fd5b823561098d81610943565b9150602083013561099d81610964565b809150509250929050565b602080825282518282018190525f9190848201906040850190845b818110156109f557835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016109c3565b50909695505050505050565b5f60208284031215610a11575f80fd5b81356106ef81610943565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610a9057610a90610a1c565b604052919050565b5f67ffffffffffffffff821115610ab157610ab1610a1c565b5060051b60200190565b5f6020808385031215610acc575f80fd5b825167ffffffffffffffff80821115610ae3575f80fd5b818501915085601f830112610af6575f80fd5b8151610b09610b0482610a98565b610a49565b818152600591821b8401850191858201919089841115610b27575f80fd5b8686015b84811015610bb957805186811115610b41575f80fd5b8701603f81018c13610b51575f80fd5b888101516040610b63610b0483610a98565b82815291851b83018101918b8101908f841115610b7e575f80fd5b938201935b83851015610ba85784519250610b9883610943565b828252938c0193908c0190610b83565b885250505093880193508701610b2b565b50909998505050505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156106bf576106bf610bf5565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610c6557610c65610bf5565b5060010190565b5f60208284031215610c7c575f80fd5b81516106ef8161096456fea264697066735822122086822f7c8ce08b043cbe7a9b95701703dd494b263875f64663c1fe9ddc41683464736f6c634300081800330000000000000000000000000ddcb0a765d09d86e526de7a9839398159274a63

Deployed Bytecode

0x608060405234801561000f575f80fd5b506004361061006f575f3560e01c80638d5e21d31161004d5780638d5e21d3146100e6578063b9209e33146100fb578063d8a06f731461011e575f80fd5b806306fdde0314610073578063138721d9146100bb5780632e5896e5146100d1575b5f80fd5b604080518082018252601881527f4564676520466163746f72792050657273706563746976650000000000000000602082015290516100b291906108d9565b60405180910390f35b6100c361016a565b6040519081526020016100b2565b6100e46100df366004610971565b6102a6565b005b6100ee6103d0565b6040516100b291906109a8565b61010e610109366004610a01565b61060d565b60405190151581526020016100b2565b6101457f0000000000000000000000000ddcb0a765d09d86e526de7a9839398159274a6381565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100b2565b6040517fe536913d0000000000000000000000000000000000000000000000000000000081525f600482018190527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602483015290819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000ddcb0a765d09d86e526de7a9839398159274a63169063e536913d906044015f60405180830381865afa15801561021c573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526102619190810190610abb565b90505f805b825181101561029f5782818151811061028157610281610bc8565b602002602001015151826102959190610c22565b9150600101610266565b5092915050565b5f8281526002602052604090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff815c016102dd57005b6102e75f846106c5565b156102f157505050565b6004805c9060055c9085905d8360055d6001835d61030e856106f6565b5f8260045d8160055d5060035c801561037d576040517f818fa2cf00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff87166024820152604481018290526064015b60405180910390fd5b6103875f876107b4565b5060405173ffffffffffffffffffffffffffffffffffffffff8716907f570e1c1f1f2e6e95bfd6d0cae607f36c3cd5ebb7bc35c2f87299924b1bcd3920905f90a2505050505050565b6040517fe536913d0000000000000000000000000000000000000000000000000000000081525f600482018190527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602483015260609173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000ddcb0a765d09d86e526de7a9839398159274a63169063e536913d906044015f60405180830381865afa158015610482573d5f803e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526104c79190810190610abb565b90505f805b8251811015610505578281815181106104e7576104e7610bc8565b602002602001015151826104fb9190610c22565b91506001016104cc565b505f8167ffffffffffffffff81111561052057610520610a1c565b604051908082528060200260200182016040528015610549578160200160208202803683370190505b5090505f91505f5b8351811015610605575f5b84828151811061056e5761056e610bc8565b6020026020010151518110156105fc5784828151811061059057610590610bc8565b602002602001015181815181106105a9576105a9610bc8565b60200260200101518385806105bd90610c35565b9650815181106105cf576105cf610bc8565b73ffffffffffffffffffffffffffffffffffffffff9092166020928302919091019091015260010161055c565b50600101610551565b509392505050565b6040517f90184b0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301525f917f0000000000000000000000000ddcb0a765d09d86e526de7a9839398159274a63909116906390184b0290602401602060405180830381865afa15801561069b573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106bf9190610c6c565b92915050565b73ffffffffffffffffffffffffffffffffffffffff81165f90815260018301602052604081205415155b9392505050565b6040517f90184b0200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301526107b1917f0000000000000000000000000ddcb0a765d09d86e526de7a9839398159274a63909116906390184b0290602401602060405180830381865afa158015610786573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107aa9190610c6c565b60016107d5565b50565b5f6106ef8373ffffffffffffffffffffffffffffffffffffffff841661088d565b81156107df575050565b805f03610818576040517fcb365b8800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60055c801561087e576040517f818fa2cf000000000000000000000000000000000000000000000000000000008152306004808301919091525c73ffffffffffffffffffffffffffffffffffffffff811660248301526044820184905290606401610374565b60035c82811760035d50505050565b5f8181526001830160205260408120546108d257508154600181810184555f8481526020808220909301849055845484825282860190935260409020919091556106bf565b505f6106bf565b5f602080835283518060208501525f5b81811015610905578581018301518582016040015282016108e9565b505f6040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b73ffffffffffffffffffffffffffffffffffffffff811681146107b1575f80fd5b80151581146107b1575f80fd5b5f8060408385031215610982575f80fd5b823561098d81610943565b9150602083013561099d81610964565b809150509250929050565b602080825282518282018190525f9190848201906040850190845b818110156109f557835173ffffffffffffffffffffffffffffffffffffffff16835292840192918401916001016109c3565b50909695505050505050565b5f60208284031215610a11575f80fd5b81356106ef81610943565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610a9057610a90610a1c565b604052919050565b5f67ffffffffffffffff821115610ab157610ab1610a1c565b5060051b60200190565b5f6020808385031215610acc575f80fd5b825167ffffffffffffffff80821115610ae3575f80fd5b818501915085601f830112610af6575f80fd5b8151610b09610b0482610a98565b610a49565b818152600591821b8401850191858201919089841115610b27575f80fd5b8686015b84811015610bb957805186811115610b41575f80fd5b8701603f81018c13610b51575f80fd5b888101516040610b63610b0483610a98565b82815291851b83018101918b8101908f841115610b7e575f80fd5b938201935b83851015610ba85784519250610b9883610943565b828252938c0193908c0190610b83565b885250505093880193508701610b2b565b50909998505050505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b808201808211156106bf576106bf610bf5565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610c6557610c65610bf5565b5060010190565b5f60208284031215610c7c575f80fd5b81516106ef8161096456fea264697066735822122086822f7c8ce08b043cbe7a9b95701703dd494b263875f64663c1fe9ddc41683464736f6c63430008180033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

0000000000000000000000000ddcb0a765d09d86e526de7a9839398159274a63

-----Decoded View---------------
Arg [0] : edgeFactory_ (address): 0x0ddcB0a765D09D86E526dE7a9839398159274A63

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000ddcb0a765d09d86e526de7a9839398159274a63


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

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.