ETH Price: $2,762.73 (+2.09%)

Contract

0x334b18E5e81657efA2057F80e19b8E81F0e5783C
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
TokenMapping

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 200 runs

Other Settings:
shanghai EvmVersion
File 1 of 13 : TokenMapping.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity 0.8.20;

import {IRegistryAccess} from "src/interfaces/registry/IRegistryAccess.sol";
import {IRegistryContract} from "src/interfaces/registry/IRegistryContract.sol";
import {ITokenMapping} from "src/interfaces/tokenManager/ITokenMapping.sol";
import {IERC20Metadata} from "openzeppelin-contracts/interfaces/IERC20Metadata.sol";
import {DEFAULT_ADMIN_ROLE, MAX_RWA_COUNT} from "src/constants.sol";
import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import {CheckAccessControl} from "src/utils/CheckAccessControl.sol";

import {NullAddress, InvalidToken, SameValue, Invalid, TooManyRWA} from "src/errors.sol";

/// @title   TokenMapping contract
/// @notice  TokenMapping contract to manage Rwa, Usd0, and Lp tokens.
/// @dev     This contract provides functionalities to link Real World Assets (RWA) tokens with Stable Coin (Usd0) tokens and manage token pairs.
/// @dev     It's part of the Usual Tech team's broader ecosystem to facilitate various operations within the platform.
/// @author  Usual Tech team
contract TokenMapping is ITokenMapping, Initializable {
    using CheckAccessControl for IRegistryAccess;

    struct TokenMappingStorageV0 {
        /// @notice Immutable instance of the REGISTRY_ACCESS contract for role checks.
        IRegistryAccess _registryAccess;
        /// @notice Immutable instance of the REGISTRY_CONTRACT for contract interaction.
        IRegistryContract _registryContract;
        /// @dev track last associated RWA ID associated to USD0.
        uint256 _usd0ToRwaLastId;
        /// @dev assign a RWA token address to USD0 token address.
        mapping(address => bool) isUsd0Collateral;
        /// @dev  RWA ID associated with USD0 token address.
        // solhint-disable-next-line var-name-mixedcase
        mapping(uint256 => address) USD0Rwas;
    }

    // keccak256(abi.encode(uint256(keccak256("tokenmapping.storage.v0")) - 1)) & ~bytes32(uint256(0xff))
    // solhint-disable-next-line
    bytes32 public constant TokenMappingStorageV0Location =
        0xb0e2a10694f571e49337681df93856b25ecda603d0f0049769ee36b541ef2300;

    /// @notice Returns the storage struct of the contract.
    /// @return $ .
    function _tokenMappingStorageV0() private pure returns (TokenMappingStorageV0 storage $) {
        bytes32 position = TokenMappingStorageV0Location;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            $.slot := position
        }
    }

    /*//////////////////////////////////////////////////////////////
                            Events
    //////////////////////////////////////////////////////////////*/

    /// @notice Emitted when an RWA token is linked to USD0 token.
    /// @param rwa The address of the RWA token.
    /// @param rwaId The ID of the RWA token.
    event AddUsd0Rwa(address indexed rwa, uint256 indexed rwaId);

    /*//////////////////////////////////////////////////////////////
                                Constructor
    //////////////////////////////////////////////////////////////*/

    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor() {
        _disableInitializers();
    }

    /// @notice Initializes the TokenMapping contract with registry information.
    /// @dev Sets the registry access and contract addresses upon deployment.
    /// @param registryAccess The address of the registry access contract.
    /// @param registryContract The address of the registry contract.
    function initialize(address registryAccess, address registryContract) public initializer {
        if (registryAccess == address(0) || registryContract == address(0)) {
            revert NullAddress();
        }

        TokenMappingStorageV0 storage $ = _tokenMappingStorageV0();
        $._registryAccess = IRegistryAccess(registryAccess);
        $._registryContract = IRegistryContract(registryContract);
    }

    /// @inheritdoc ITokenMapping
    function addUsd0Rwa(address rwa) external returns (bool) {
        if (rwa == address(0)) {
            revert NullAddress();
        }
        // check if there is a decimals function at the address
        // and if there is at least 1 decimal
        // if not, revert
        if (IERC20Metadata(rwa).decimals() == 0) {
            revert Invalid();
        }

        TokenMappingStorageV0 storage $ = _tokenMappingStorageV0();
        $._registryAccess.onlyMatchingRole(DEFAULT_ADMIN_ROLE);

        // is the RWA already registered as a USD0 RWA
        if ($.isUsd0Collateral[rwa]) revert SameValue();
        $.isUsd0Collateral[rwa] = true;
        // 0 index is always empty
        ++$._usd0ToRwaLastId;
        if ($._usd0ToRwaLastId > MAX_RWA_COUNT) {
            revert TooManyRWA();
        }
        $.USD0Rwas[$._usd0ToRwaLastId] = rwa;
        emit AddUsd0Rwa(rwa, $._usd0ToRwaLastId);
        return true;
    }

    /*//////////////////////////////////////////////////////////////
                                 View
    //////////////////////////////////////////////////////////////*/

    /// @inheritdoc ITokenMapping
    function getUsd0RwaById(uint256 rwaId) external view returns (address) {
        TokenMappingStorageV0 storage $ = _tokenMappingStorageV0();
        address rwa = $.USD0Rwas[rwaId];
        if (rwa == address(0)) {
            revert InvalidToken();
        }
        return rwa;
    }

    /// @inheritdoc ITokenMapping
    function getAllUsd0Rwa() external view returns (address[] memory) {
        TokenMappingStorageV0 storage $ = _tokenMappingStorageV0();
        address[] memory rwas = new address[]($._usd0ToRwaLastId);
        // maximum of 10 rwa tokens
        uint256 length = $._usd0ToRwaLastId;
        for (uint256 i = 1; i <= length;) {
            rwas[i - 1] = $.USD0Rwas[i];
            unchecked {
                ++i;
            }
        }
        return rwas;
    }

    /// @inheritdoc ITokenMapping
    function getLastUsd0RwaId() external view returns (uint256) {
        TokenMappingStorageV0 storage $ = _tokenMappingStorageV0();
        return $._usd0ToRwaLastId;
    }

    /// @inheritdoc ITokenMapping
    function isUsd0Collateral(address rwa) external view returns (bool) {
        TokenMappingStorageV0 storage $ = _tokenMappingStorageV0();
        return $.isUsd0Collateral[rwa];
    }
}

File 2 of 13 : IRegistryAccess.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity 0.8.20;

import {IAccessControlDefaultAdminRules} from
    "openzeppelin-contracts/access/extensions/IAccessControlDefaultAdminRules.sol";

// solhint-disable-next-line no-empty-blocks
interface IRegistryAccess is IAccessControlDefaultAdminRules {}

File 3 of 13 : IRegistryContract.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity 0.8.20;

interface IRegistryContract {
    function setContract(bytes32 name, address contractAddress) external;

    function getContract(bytes32 name) external view returns (address);
}

File 4 of 13 : ITokenMapping.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity 0.8.20;

interface ITokenMapping {
    /// @notice Links an RWA token to USD0 token.
    /// @dev Only the admin can link the RWA token to USD0 token.
    /// @dev Ensures the RWA token is valid and not already linked to USD0 token.
    /// @param rwa The address of the RWA token.
    /// @return A boolean value indicating success.
    function addUsd0Rwa(address rwa) external returns (bool);

    /// @notice Retrieves the RWA token linked to USD0 token.
    /// @dev Returns the address of the Rwa token associated with USD0 token.
    /// @param rwaId The ID of the RWA token.
    /// @return The address of the associated Rwa token.
    function getUsd0RwaById(uint256 rwaId) external view returns (address);

    /// @notice Retrieves all RWA tokens linked to USD0 token.
    /// @dev Returns an array of addresses of all RWA tokens associated with USD0 token.
    /// @dev the maximum number of RWA tokens that can be associated with USD0 token is 10.
    /// @return An array of addresses of associated RWA tokens.
    function getAllUsd0Rwa() external view returns (address[] memory);

    /// @notice Retrieves the last RWA ID for USD0 token.
    /// @dev Returns the highest index used for the RWA tokens associated with the USD0 token.
    /// @return The last RWA ID used in the STBC to RWA mapping.
    function getLastUsd0RwaId() external view returns (uint256);

    /// @notice Checks if the RWA token is linked to USD0 token.
    /// @dev Returns a boolean value indicating if the RWA token is linked to USD0 token.
    /// @param rwa The address of the RWA token.
    /// @return A boolean value indicating if the RWA token is linked to USD0 token.
    function isUsd0Collateral(address rwa) external view returns (bool);
}

File 5 of 13 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20Metadata.sol)

pragma solidity ^0.8.20;

import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";

File 6 of 13 : constants.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity 0.8.20;

bytes32 constant ADMIN = keccak256("ADMIN");
bytes32 constant DEFAULT_ADMIN_ROLE = 0x00;
bytes32 constant DAO_COLLATERAL = keccak256("DAO_COLLATERAL_CONTRACT");
bytes32 constant USD0_MINT = keccak256("USD0_MINT");
bytes32 constant USD0_BURN = keccak256("USD0_BURN");
bytes32 constant INTENT_MATCHING_ROLE = keccak256("INTENT_MATCHING_ROLE");
bytes32 constant SWAPPER_ENGINE = keccak256("SWAPPER_ENGINE");
bytes32 constant INTENT_TYPE_HASH = keccak256(
    "SwapIntent(address recipient,address rwaToken,uint256 amountInTokenDecimals,uint256 nonce,uint256 deadline)"
);
/* Contracts */

bytes32 constant CONTRACT_REGISTRY_ACCESS = keccak256("CONTRACT_REGISTRY_ACCESS");
bytes32 constant CONTRACT_DAO_COLLATERAL = keccak256("CONTRACT_DAO_COLLATERAL");
bytes32 constant CONTRACT_USD0PP = keccak256("CONTRACT_USD0PP");
bytes32 constant CONTRACT_TOKEN_MAPPING = keccak256("CONTRACT_TOKEN_MAPPING");
bytes32 constant CONTRACT_ORACLE = keccak256("CONTRACT_ORACLE");
bytes32 constant CONTRACT_ORACLE_USUAL = keccak256("CONTRACT_ORACLE_USUAL");
bytes32 constant CONTRACT_DATA_PUBLISHER = keccak256("CONTRACT_DATA_PUBLISHER");
bytes32 constant CONTRACT_TREASURY = keccak256("CONTRACT_TREASURY");
bytes32 constant CONTRACT_SWAPPER_ENGINE = keccak256("CONTRACT_SWAPPER_ENGINE");
/* Contract tokens */
bytes32 constant CONTRACT_USD0 = keccak256("CONTRACT_USD0");
bytes32 constant CONTRACT_USDC = keccak256("CONTRACT_USDC");
/* Constants */
uint256 constant SCALAR_ONE = 1e18;
uint256 constant SCALAR_TEN_KWEI = 10_000;
uint256 constant MAX_REDEEM_FEE = 2500;
uint256 constant MINIMUM_USDC_PROVIDED = 100e6; //minimum of 100 USDC deposit;
// we take 12sec as the average block time
// 1 year = 3600sec * 24 hours * 365 days * 4 years  = 126144000 + 1 day // adding a leap day
uint256 constant BOND_DURATION_FOUR_YEAR = 126_230_400; //including a leap day;
uint256 constant BOND_START_DATE = 1_719_489_600; // Thu Jun 27 2024 12:00:00 GMT+0000
uint256 constant BASIS_POINT_BASE = 10_000;
uint64 constant ONE_WEEK = 604_800;
uint256 constant ONE_USDC = 1e6;

/*
 * The maximum relative price difference between two oracle responses allowed in order for the PriceFeed
 * to return to using the Oracle oracle. 18-digit precision.
 */

uint256 constant INITIAL_MAX_DEPEG_THRESHOLD = 100;

/* Maximum number of RWA tokens that can be associated with USD0 */
uint256 constant MAX_RWA_COUNT = 10;

File 7 of 13 : Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)

pragma solidity ^0.8.20;

/**
 * @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]
 * ```solidity
 * 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 Storage of the initializable contract.
     *
     * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
     * when using with upgradeable contracts.
     *
     * @custom:storage-location erc7201:openzeppelin.storage.Initializable
     */
    struct InitializableStorage {
        /**
         * @dev Indicates that the contract has been initialized.
         */
        uint64 _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool _initializing;
    }

    // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
    bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;

    /**
     * @dev The contract is already initialized.
     */
    error InvalidInitialization();

    /**
     * @dev The contract is not initializing.
     */
    error NotInitializing();

    /**
     * @dev Triggered when the contract has been initialized or reinitialized.
     */
    event Initialized(uint64 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 in the context of a constructor an `initializer` may be invoked any
     * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
     * production.
     *
     * Emits an {Initialized} event.
     */
    modifier initializer() {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        // Cache values to avoid duplicated sloads
        bool isTopLevelCall = !$._initializing;
        uint64 initialized = $._initialized;

        // Allowed calls:
        // - initialSetup: the contract is not in the initializing state and no previous version was
        //                 initialized
        // - construction: the contract is initialized at version 1 (no reininitialization) and the
        //                 current contract is just being deployed
        bool initialSetup = initialized == 0 && isTopLevelCall;
        bool construction = initialized == 1 && address(this).code.length == 0;

        if (!initialSetup && !construction) {
            revert InvalidInitialization();
        }
        $._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 2**64 - 1 will prevent any future reinitialization.
     *
     * Emits an {Initialized} event.
     */
    modifier reinitializer(uint64 version) {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing || $._initialized >= version) {
            revert InvalidInitialization();
        }
        $._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() {
        _checkInitializing();
        _;
    }

    /**
     * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
     */
    function _checkInitializing() internal view virtual {
        if (!_isInitializing()) {
            revert NotInitializing();
        }
    }

    /**
     * @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 {
        // solhint-disable-next-line var-name-mixedcase
        InitializableStorage storage $ = _getInitializableStorage();

        if ($._initializing) {
            revert InvalidInitialization();
        }
        if ($._initialized != type(uint64).max) {
            $._initialized = type(uint64).max;
            emit Initialized(type(uint64).max);
        }
    }

    /**
     * @dev Returns the highest version that has been initialized. See {reinitializer}.
     */
    function _getInitializedVersion() internal view returns (uint64) {
        return _getInitializableStorage()._initialized;
    }

    /**
     * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
     */
    function _isInitializing() internal view returns (bool) {
        return _getInitializableStorage()._initializing;
    }

    /**
     * @dev Returns a pointer to the storage namespace.
     */
    // solhint-disable-next-line var-name-mixedcase
    function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
        assembly {
            $.slot := INITIALIZABLE_STORAGE
        }
    }
}

File 8 of 13 : CheckAccessControl.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity 0.8.20;

import {IRegistryAccess} from "src/interfaces/registry/IRegistryAccess.sol";

import {NotAuthorized} from "src/errors.sol";

/// @title Check Access control library
library CheckAccessControl {
    /// @dev Function to restrict to one access role.
    /// @param registryAccess The registry access contract.
    /// @param role The role being checked.
    function onlyMatchingRole(IRegistryAccess registryAccess, bytes32 role) internal view {
        if (!registryAccess.hasRole(role, msg.sender)) {
            revert NotAuthorized();
        }
    }
}

File 9 of 13 : errors.sol
// SPDX-License-Identifier: Apache-2.0

pragma solidity 0.8.20;

error AlreadyClaimed();
error AlreadyWhitelisted();
error AmountTooBig();
error AmountTooLow();
error AmountIsZero();
error Blacklisted();

error Empty();
error ExpiredSignature(uint256 deadline);
error SameValue();

error Invalid();
error InvalidToken();
error InvalidName();
error InvalidSigner(address owner);
error InvalidDeadline(uint256 approvalDeadline, uint256 intentDeadline);
error NoOrdersIdsProvided();
error InvalidSymbol();

error LockedOffer();

error NotAuthorized();
error NotClaimableYet();
error NullAddress();
error NullContract();

error OracleNotWorkingNotCurrent();
error OracleNotInitialized();
error OutOfBounds();
error InvalidTimeout();

error RedeemMustNotBePaused();
error RedeemMustBePaused();
error SwapMustNotBePaused();
error SwapMustBePaused();

error StablecoinDepeg();
error DepegThresholdTooHigh();

error TokenNotWhitelist();

error BondNotStarted();
error BondFinished();
error BondNotFinished();

error BeginInPast();

error CBRIsTooHigh();
error CBRIsNull();

error RedeemFeeTooBig();
error CancelFeeTooBig();
error MinterRewardTooBig();
error CollateralProviderRewardTooBig();
error DistributionRatioInvalid();
error TooManyRWA();
error FailingTransfer();

error InsufficientUSD0Balance();
error USDCAmountNotFullyMatched();
error OrderNotActive();
error NotRequester();
error InsufficientUSD0Allowance();
error ApprovalFailed();

File 10 of 13 : IAccessControlDefaultAdminRules.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlDefaultAdminRules.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev External interface of AccessControlDefaultAdminRules declared to support ERC165 detection.
 */
interface IAccessControlDefaultAdminRules is IAccessControl {
    /**
     * @dev The new default admin is not a valid default admin.
     */
    error AccessControlInvalidDefaultAdmin(address defaultAdmin);

    /**
     * @dev At least one of the following rules was violated:
     *
     * - The `DEFAULT_ADMIN_ROLE` must only be managed by itself.
     * - The `DEFAULT_ADMIN_ROLE` must only be held by one account at the time.
     * - Any `DEFAULT_ADMIN_ROLE` transfer must be in two delayed steps.
     */
    error AccessControlEnforcedDefaultAdminRules();

    /**
     * @dev The delay for transferring the default admin delay is enforced and
     * the operation must wait until `schedule`.
     *
     * NOTE: `schedule` can be 0 indicating there's no transfer scheduled.
     */
    error AccessControlEnforcedDefaultAdminDelay(uint48 schedule);

    /**
     * @dev Emitted when a {defaultAdmin} transfer is started, setting `newAdmin` as the next
     * address to become the {defaultAdmin} by calling {acceptDefaultAdminTransfer} only after `acceptSchedule`
     * passes.
     */
    event DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule);

    /**
     * @dev Emitted when a {pendingDefaultAdmin} is reset if it was never accepted, regardless of its schedule.
     */
    event DefaultAdminTransferCanceled();

    /**
     * @dev Emitted when a {defaultAdminDelay} change is started, setting `newDelay` as the next
     * delay to be applied between default admin transfer after `effectSchedule` has passed.
     */
    event DefaultAdminDelayChangeScheduled(uint48 newDelay, uint48 effectSchedule);

    /**
     * @dev Emitted when a {pendingDefaultAdminDelay} is reset if its schedule didn't pass.
     */
    event DefaultAdminDelayChangeCanceled();

    /**
     * @dev Returns the address of the current `DEFAULT_ADMIN_ROLE` holder.
     */
    function defaultAdmin() external view returns (address);

    /**
     * @dev Returns a tuple of a `newAdmin` and an accept schedule.
     *
     * After the `schedule` passes, the `newAdmin` will be able to accept the {defaultAdmin} role
     * by calling {acceptDefaultAdminTransfer}, completing the role transfer.
     *
     * A zero value only in `acceptSchedule` indicates no pending admin transfer.
     *
     * NOTE: A zero address `newAdmin` means that {defaultAdmin} is being renounced.
     */
    function pendingDefaultAdmin() external view returns (address newAdmin, uint48 acceptSchedule);

    /**
     * @dev Returns the delay required to schedule the acceptance of a {defaultAdmin} transfer started.
     *
     * This delay will be added to the current timestamp when calling {beginDefaultAdminTransfer} to set
     * the acceptance schedule.
     *
     * NOTE: If a delay change has been scheduled, it will take effect as soon as the schedule passes, making this
     * function returns the new delay. See {changeDefaultAdminDelay}.
     */
    function defaultAdminDelay() external view returns (uint48);

    /**
     * @dev Returns a tuple of `newDelay` and an effect schedule.
     *
     * After the `schedule` passes, the `newDelay` will get into effect immediately for every
     * new {defaultAdmin} transfer started with {beginDefaultAdminTransfer}.
     *
     * A zero value only in `effectSchedule` indicates no pending delay change.
     *
     * NOTE: A zero value only for `newDelay` means that the next {defaultAdminDelay}
     * will be zero after the effect schedule.
     */
    function pendingDefaultAdminDelay() external view returns (uint48 newDelay, uint48 effectSchedule);

    /**
     * @dev Starts a {defaultAdmin} transfer by setting a {pendingDefaultAdmin} scheduled for acceptance
     * after the current timestamp plus a {defaultAdminDelay}.
     *
     * Requirements:
     *
     * - Only can be called by the current {defaultAdmin}.
     *
     * Emits a DefaultAdminRoleChangeStarted event.
     */
    function beginDefaultAdminTransfer(address newAdmin) external;

    /**
     * @dev Cancels a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}.
     *
     * A {pendingDefaultAdmin} not yet accepted can also be cancelled with this function.
     *
     * Requirements:
     *
     * - Only can be called by the current {defaultAdmin}.
     *
     * May emit a DefaultAdminTransferCanceled event.
     */
    function cancelDefaultAdminTransfer() external;

    /**
     * @dev Completes a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}.
     *
     * After calling the function:
     *
     * - `DEFAULT_ADMIN_ROLE` should be granted to the caller.
     * - `DEFAULT_ADMIN_ROLE` should be revoked from the previous holder.
     * - {pendingDefaultAdmin} should be reset to zero values.
     *
     * Requirements:
     *
     * - Only can be called by the {pendingDefaultAdmin}'s `newAdmin`.
     * - The {pendingDefaultAdmin}'s `acceptSchedule` should've passed.
     */
    function acceptDefaultAdminTransfer() external;

    /**
     * @dev Initiates a {defaultAdminDelay} update by setting a {pendingDefaultAdminDelay} scheduled for getting
     * into effect after the current timestamp plus a {defaultAdminDelay}.
     *
     * This function guarantees that any call to {beginDefaultAdminTransfer} done between the timestamp this
     * method is called and the {pendingDefaultAdminDelay} effect schedule will use the current {defaultAdminDelay}
     * set before calling.
     *
     * The {pendingDefaultAdminDelay}'s effect schedule is defined in a way that waiting until the schedule and then
     * calling {beginDefaultAdminTransfer} with the new delay will take at least the same as another {defaultAdmin}
     * complete transfer (including acceptance).
     *
     * The schedule is designed for two scenarios:
     *
     * - When the delay is changed for a larger one the schedule is `block.timestamp + newDelay` capped by
     * {defaultAdminDelayIncreaseWait}.
     * - When the delay is changed for a shorter one, the schedule is `block.timestamp + (current delay - new delay)`.
     *
     * A {pendingDefaultAdminDelay} that never got into effect will be canceled in favor of a new scheduled change.
     *
     * Requirements:
     *
     * - Only can be called by the current {defaultAdmin}.
     *
     * Emits a DefaultAdminDelayChangeScheduled event and may emit a DefaultAdminDelayChangeCanceled event.
     */
    function changeDefaultAdminDelay(uint48 newDelay) external;

    /**
     * @dev Cancels a scheduled {defaultAdminDelay} change.
     *
     * Requirements:
     *
     * - Only can be called by the current {defaultAdmin}.
     *
     * May emit a DefaultAdminDelayChangeCanceled event.
     */
    function rollbackDefaultAdminDelay() external;

    /**
     * @dev Maximum time in seconds for an increase to {defaultAdminDelay} (that is scheduled using {changeDefaultAdminDelay})
     * to take effect. Default to 5 days.
     *
     * When the {defaultAdminDelay} is scheduled to be increased, it goes into effect after the new delay has passed with
     * the purpose of giving enough time for reverting any accidental change (i.e. using milliseconds instead of seconds)
     * that may lock the contract. However, to avoid excessive schedules, the wait is capped by this function and it can
     * be overrode for a custom {defaultAdminDelay} increase scheduling.
     *
     * IMPORTANT: Make sure to add a reasonable amount of time while overriding this value, otherwise,
     * there's a risk of setting a high new delay that goes into effect almost immediately without the
     * possibility of human intervention in the case of an input error (eg. set milliseconds instead of seconds).
     */
    function defaultAdminDelayIncreaseWait() external view returns (uint48);
}

File 11 of 13 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 12 of 13 : IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)

pragma solidity ^0.8.20;

/**
 * @dev External interface of AccessControl declared to support ERC165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}

File 13 of 13 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "utils/=lib/utils/",
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/",
    "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
    "src/=src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "shanghai",
  "viaIR": false,
  "libraries": {
    "scripts/deployment/utils/DeploymentHelpers.sol": {
      "DeploymentHelpers": "0x758888Dd8Cc9C654519413E3Da099c3FF618CE84"
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Invalid","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"inputs":[],"name":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NullAddress","type":"error"},{"inputs":[],"name":"SameValue","type":"error"},{"inputs":[],"name":"TooManyRWA","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rwa","type":"address"},{"indexed":true,"internalType":"uint256","name":"rwaId","type":"uint256"}],"name":"AddUsd0Rwa","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"inputs":[],"name":"TokenMappingStorageV0Location","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"rwa","type":"address"}],"name":"addUsd0Rwa","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllUsd0Rwa","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLastUsd0RwaId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"rwaId","type":"uint256"}],"name":"getUsd0RwaById","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"registryAccess","type":"address"},{"internalType":"address","name":"registryContract","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rwa","type":"address"}],"name":"isUsd0Collateral","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

608060405234801561000f575f80fd5b5061001861001d565b6100cf565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff161561006d5760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146100cc5780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b6108a5806100dc5f395ff3fe608060405234801561000f575f80fd5b506004361061007a575f3560e01c8063696f9c5311610058578063696f9c53146100d35780639a8e0dae146100f6578063d7f568e21461011d578063f84e817c14610148575f80fd5b806343069d461461007e578063485cc9551461009c5780635441c909146100b1575b5f80fd5b610086610192565b60405161009391906106db565b60405180910390f35b6100af6100aa366004610742565b61027a565b005b6100c55f8051602061085083398151915281565b604051908152602001610093565b6100e66100e1366004610773565b610416565b6040519015158152602001610093565b7fb0e2a10694f571e49337681df93856b25ecda603d0f0049769ee36b541ef2302546100c5565b61013061012b36600461078c565b6105e3565b6040516001600160a01b039091168152602001610093565b6100e6610156366004610773565b6001600160a01b03165f9081527fb0e2a10694f571e49337681df93856b25ecda603d0f0049769ee36b541ef2303602052604090205460ff1690565b7fb0e2a10694f571e49337681df93856b25ecda603d0f0049769ee36b541ef2302546060905f80516020610850833981519152905f9067ffffffffffffffff8111156101e0576101e06107a3565b604051908082528060200260200182016040528015610209578160200160208202803683370190505b50600283015490915060015b818111610271575f8181526004850160205260409020546001600160a01b0316836102416001846107cb565b81518110610251576102516107e4565b6001600160a01b0390921660209283029190910190910152600101610215565b50909392505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff165f811580156102bf5750825b90505f8267ffffffffffffffff1660011480156102db5750303b155b9050811580156102e9575080155b156103075760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561033157845460ff60401b1916600160401b1785555b6001600160a01b038716158061034e57506001600160a01b038616155b1561036c5760405163e99d5ac560e01b815260040160405180910390fd5b5f8051602061085083398151915280546001600160a01b038981166001600160a01b0319928316179092557fb0e2a10694f571e49337681df93856b25ecda603d0f0049769ee36b541ef2301805492891692909116919091179055831561040d57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b5f6001600160a01b03821661043e5760405163e99d5ac560e01b815260040160405180910390fd5b816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561047a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061049e91906107f8565b60ff165f036104c057604051636dac6a0960e01b815260040160405180910390fd5b5f8051602061085083398151915280546104e3906001600160a01b03165f61064d565b6001600160a01b0383165f90815260038201602052604090205460ff161561051e5760405163c23f6ccb60e01b815260040160405180910390fd5b6001600160a01b0383165f9081526003820160205260408120805460ff1916600117905560028201805490919061055490610818565b909155506002810154600a101561057e57604051634811b7ed60e11b815260040160405180910390fd5b6002810180545f90815260048301602052604080822080546001600160a01b0319166001600160a01b038816908117909155925490519092917fadaa3ddbe7eee68aa4d4faf6cfb60002656fe2ab401323e4d8245fc6be3293e991a350600192915050565b5f8181527fb0e2a10694f571e49337681df93856b25ecda603d0f0049769ee36b541ef230460205260408120545f80516020610850833981519152906001600160a01b0316806106465760405163c1ab6dc160e01b815260040160405180910390fd5b9392505050565b604051632474521560e21b8152600481018290523360248201526001600160a01b038316906391d1485490604401602060405180830381865afa158015610696573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106ba9190610830565b6106d75760405163ea8e4eb560e01b815260040160405180910390fd5b5050565b602080825282518282018190525f9190848201906040850190845b8181101561071b5783516001600160a01b0316835292840192918401916001016106f6565b50909695505050505050565b80356001600160a01b038116811461073d575f80fd5b919050565b5f8060408385031215610753575f80fd5b61075c83610727565b915061076a60208401610727565b90509250929050565b5f60208284031215610783575f80fd5b61064682610727565b5f6020828403121561079c575f80fd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b818103818111156107de576107de6107b7565b92915050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215610808575f80fd5b815160ff81168114610646575f80fd5b5f60018201610829576108296107b7565b5060010190565b5f60208284031215610840575f80fd5b81518015158114610646575f80fdfeb0e2a10694f571e49337681df93856b25ecda603d0f0049769ee36b541ef2300a2646970667358221220b6d3b8dcd28fd34b45dbe43c7cc2429c8cbdc2473f8a7a439aa7b441e8afa9b464736f6c63430008140033

Deployed Bytecode

0x608060405234801561000f575f80fd5b506004361061007a575f3560e01c8063696f9c5311610058578063696f9c53146100d35780639a8e0dae146100f6578063d7f568e21461011d578063f84e817c14610148575f80fd5b806343069d461461007e578063485cc9551461009c5780635441c909146100b1575b5f80fd5b610086610192565b60405161009391906106db565b60405180910390f35b6100af6100aa366004610742565b61027a565b005b6100c55f8051602061085083398151915281565b604051908152602001610093565b6100e66100e1366004610773565b610416565b6040519015158152602001610093565b7fb0e2a10694f571e49337681df93856b25ecda603d0f0049769ee36b541ef2302546100c5565b61013061012b36600461078c565b6105e3565b6040516001600160a01b039091168152602001610093565b6100e6610156366004610773565b6001600160a01b03165f9081527fb0e2a10694f571e49337681df93856b25ecda603d0f0049769ee36b541ef2303602052604090205460ff1690565b7fb0e2a10694f571e49337681df93856b25ecda603d0f0049769ee36b541ef2302546060905f80516020610850833981519152905f9067ffffffffffffffff8111156101e0576101e06107a3565b604051908082528060200260200182016040528015610209578160200160208202803683370190505b50600283015490915060015b818111610271575f8181526004850160205260409020546001600160a01b0316836102416001846107cb565b81518110610251576102516107e4565b6001600160a01b0390921660209283029190910190910152600101610215565b50909392505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff165f811580156102bf5750825b90505f8267ffffffffffffffff1660011480156102db5750303b155b9050811580156102e9575080155b156103075760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561033157845460ff60401b1916600160401b1785555b6001600160a01b038716158061034e57506001600160a01b038616155b1561036c5760405163e99d5ac560e01b815260040160405180910390fd5b5f8051602061085083398151915280546001600160a01b038981166001600160a01b0319928316179092557fb0e2a10694f571e49337681df93856b25ecda603d0f0049769ee36b541ef2301805492891692909116919091179055831561040d57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b5f6001600160a01b03821661043e5760405163e99d5ac560e01b815260040160405180910390fd5b816001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561047a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061049e91906107f8565b60ff165f036104c057604051636dac6a0960e01b815260040160405180910390fd5b5f8051602061085083398151915280546104e3906001600160a01b03165f61064d565b6001600160a01b0383165f90815260038201602052604090205460ff161561051e5760405163c23f6ccb60e01b815260040160405180910390fd5b6001600160a01b0383165f9081526003820160205260408120805460ff1916600117905560028201805490919061055490610818565b909155506002810154600a101561057e57604051634811b7ed60e11b815260040160405180910390fd5b6002810180545f90815260048301602052604080822080546001600160a01b0319166001600160a01b038816908117909155925490519092917fadaa3ddbe7eee68aa4d4faf6cfb60002656fe2ab401323e4d8245fc6be3293e991a350600192915050565b5f8181527fb0e2a10694f571e49337681df93856b25ecda603d0f0049769ee36b541ef230460205260408120545f80516020610850833981519152906001600160a01b0316806106465760405163c1ab6dc160e01b815260040160405180910390fd5b9392505050565b604051632474521560e21b8152600481018290523360248201526001600160a01b038316906391d1485490604401602060405180830381865afa158015610696573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106ba9190610830565b6106d75760405163ea8e4eb560e01b815260040160405180910390fd5b5050565b602080825282518282018190525f9190848201906040850190845b8181101561071b5783516001600160a01b0316835292840192918401916001016106f6565b50909695505050505050565b80356001600160a01b038116811461073d575f80fd5b919050565b5f8060408385031215610753575f80fd5b61075c83610727565b915061076a60208401610727565b90509250929050565b5f60208284031215610783575f80fd5b61064682610727565b5f6020828403121561079c575f80fd5b5035919050565b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b818103818111156107de576107de6107b7565b92915050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215610808575f80fd5b815160ff81168114610646575f80fd5b5f60018201610829576108296107b7565b5060010190565b5f60208284031215610840575f80fd5b81518015158114610646575f80fdfeb0e2a10694f571e49337681df93856b25ecda603d0f0049769ee36b541ef2300a2646970667358221220b6d3b8dcd28fd34b45dbe43c7cc2429c8cbdc2473f8a7a439aa7b441e8afa9b464736f6c63430008140033

Block Transaction Difficulty 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
Loading...
Loading

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.