ETH Price: $3,182.11 (-4.68%)
 
Transaction Hash
Method
Block
From
To
Batch Claim217112082025-01-26 20:54:477 hrs ago1737924887IN
Superform : RewardsDistributor
0 ETH0.001016934.85232711
Batch Claim217073262025-01-26 7:53:2320 hrs ago1737878003IN
Superform : RewardsDistributor
0 ETH0.000404343.60268301
Batch Claim217067682025-01-26 6:01:2321 hrs ago1737871283IN
Superform : RewardsDistributor
0 ETH0.001036152.40753522
Batch Claim217015602025-01-25 12:36:5939 hrs ago1737808619IN
Superform : RewardsDistributor
0 ETH0.003315856.4825765
Batch Claim216983272025-01-25 1:45:232 days ago1737769523IN
Superform : RewardsDistributor
0 ETH0.002784875.95620072
Batch Claim216902962025-01-23 22:50:593 days ago1737672659IN
Superform : RewardsDistributor
0 ETH0.002205029.28489651
Batch Claim216853182025-01-23 6:12:113 days ago1737612731IN
Superform : RewardsDistributor
0 ETH0.000971524.87206829
Batch Claim216724312025-01-21 11:01:115 days ago1737457271IN
Superform : RewardsDistributor
0 ETH0.0013238811.91254536
Batch Claim216506812025-01-18 10:09:478 days ago1737194987IN
Superform : RewardsDistributor
0 ETH0.003314729.95894819
Batch Claim216414042025-01-17 3:03:3510 days ago1737083015IN
Superform : RewardsDistributor
0 ETH0.00247113.67360507
Batch Claim216402152025-01-16 23:04:3510 days ago1737068675IN
Superform : RewardsDistributor
0 ETH0.001230464
Batch Claim216380662025-01-16 15:53:3510 days ago1737042815IN
Superform : RewardsDistributor
0 ETH0.0063729910.32669708
Batch Claim216360422025-01-16 9:06:3510 days ago1737018395IN
Superform : RewardsDistributor
0 ETH0.0006675.94172501
Batch Claim216344072025-01-16 3:37:4711 days ago1736998667IN
Superform : RewardsDistributor
0 ETH0.000373723.39136167
Batch Claim216343902025-01-16 3:34:2311 days ago1736998463IN
Superform : RewardsDistributor
0 ETH0.000417193.78424436
Batch Claim216343822025-01-16 3:32:4711 days ago1736998367IN
Superform : RewardsDistributor
0 ETH0.000402463.67547289
Batch Claim216343632025-01-16 3:28:5911 days ago1736998139IN
Superform : RewardsDistributor
0 ETH0.000334113.0512591
Batch Claim216343532025-01-16 3:26:5911 days ago1736998019IN
Superform : RewardsDistributor
0 ETH0.000322192.92377646
Batch Claim216343402025-01-16 3:24:2311 days ago1736997863IN
Superform : RewardsDistributor
0 ETH0.000327252.96772703
Batch Claim216343322025-01-16 3:22:4711 days ago1736997767IN
Superform : RewardsDistributor
0 ETH0.000332733.01972518
Batch Claim216343232025-01-16 3:20:5911 days ago1736997659IN
Superform : RewardsDistributor
0 ETH0.000331483.00941598
Batch Claim216343172025-01-16 3:19:4711 days ago1736997587IN
Superform : RewardsDistributor
0 ETH0.000292442.65292681
Batch Claim216342792025-01-16 3:12:1111 days ago1736997131IN
Superform : RewardsDistributor
0 ETH0.000278552.52611111
Batch Claim216292922025-01-15 10:29:4711 days ago1736936987IN
Superform : RewardsDistributor
0 ETH0.002278533.51227238
Batch Claim216292662025-01-15 10:24:3511 days ago1736936675IN
Superform : RewardsDistributor
0 ETH0.002142733.25199039
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
199830892024-05-30 13:54:35241 days ago1717077275  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
RewardsDistributor

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
File 1 of 12 : RewardsDistributor.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;

/// library imports
import { MerkleProof } from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol";
import { SafeERC20 } from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";

/// local imports
import { Error } from "src/libraries/Error.sol";
import { ISuperRBAC } from "src/interfaces/ISuperRBAC.sol";
import { ISuperRegistry } from "src/interfaces/ISuperRegistry.sol";
import { IRewardsDistributor } from "src/interfaces/IRewardsDistributor.sol";

/// @title RewardsDistributor
/// @author Zeropoint Labs
/// @notice This will be SUPERFORM_RECEIVER in SuperRegistry.
/// @notice Also, requires a new REWARDS_ADMIN_ROLE (a fireblocks address)
contract RewardsDistributor is IRewardsDistributor {
    using SafeERC20 for IERC20;

    //////////////////////////////////////////////////////////////
    //                         CONSTANTS                         //
    //////////////////////////////////////////////////////////////

    ISuperRegistry public immutable superRegistry;
    uint64 public immutable CHAIN_ID;
    bytes32 internal constant ZERO_BYTES32 = bytes32(0);
    uint256 public constant DEADLINE = 52 weeks;

    //////////////////////////////////////////////////////////////
    //                      STATE VARIABLES                     //
    //////////////////////////////////////////////////////////////

    uint256 public currentPeriodId;

    /// @dev maps the periodic rewards id to its corresponding merkle root and startTimestamp
    mapping(uint256 periodId => PeriodicRewardsData data) public periodicRewardsMerkleRootData;

    /// @dev mapping from periodId to claimer address to claimed status
    mapping(uint256 periodId => mapping(address claimerAddress => bool claimed)) public periodicRewardsClaimed;

    //////////////////////////////////////////////////////////////
    //                       MODIFIERS                          //
    //////////////////////////////////////////////////////////////

    modifier onlyRewardsAdmin() {
        if (
            !ISuperRBAC(superRegistry.getAddress(keccak256("SUPER_RBAC"))).hasRole(
                keccak256("REWARDS_ADMIN_ROLE"), msg.sender
            )
        ) {
            revert NOT_REWARDS_ADMIN();
        }
        _;
    }

    //////////////////////////////////////////////////////////////
    //                      CONSTRUCTOR                         //
    //////////////////////////////////////////////////////////////

    /// @param superRegistry_ the superform registry contract
    constructor(address superRegistry_) {
        if (superRegistry_ == address(0)) {
            revert Error.ZERO_ADDRESS();
        }

        if (block.chainid > type(uint64).max) {
            revert Error.BLOCK_CHAIN_ID_OUT_OF_BOUNDS();
        }

        superRegistry = ISuperRegistry(superRegistry_);
        CHAIN_ID = uint64(block.chainid);
    }

    //////////////////////////////////////////////////////////////
    //              EXTERNAL WRITE FUNCTIONS                    //
    //////////////////////////////////////////////////////////////

    /// @inheritdoc IRewardsDistributor
    function setPeriodicRewards(bytes32 root_) external payable override onlyRewardsAdmin {
        if (root_ == ZERO_BYTES32) revert INVALID_MERKLE_ROOT();

        uint256 periodId = currentPeriodId;
        uint256 startTimestamp = block.timestamp;

        periodicRewardsMerkleRootData[periodId].startTimestamp = startTimestamp;
        periodicRewardsMerkleRootData[periodId].merkleRoot = root_;

        ++currentPeriodId;
        emit PeriodicRewardsSet(periodId, root_, startTimestamp);
    }

    /// @inheritdoc IRewardsDistributor
    function claim(
        address receiver_,
        uint256 periodId_,
        address[] calldata rewardTokens_,
        uint256[] calldata amountsClaimed_,
        bytes32[] calldata proof_
    )
        external
        override
    {
        if (receiver_ == address(0)) revert INVALID_RECEIVER();

        uint256 tokensToClaim = rewardTokens_.length;

        if (tokensToClaim == 0) revert ZERO_ARR_LENGTH();
        if (tokensToClaim != amountsClaimed_.length) revert INVALID_REQ_TOKENS_AMOUNTS();

        _claim(receiver_, periodId_, rewardTokens_, amountsClaimed_, tokensToClaim, proof_);

        emit RewardsClaimed(msg.sender, receiver_, periodId_, rewardTokens_, amountsClaimed_);
    }

    /// @inheritdoc IRewardsDistributor
    function batchClaim(
        address receiver_,
        uint256[] calldata periodIds_,
        address[][] calldata rewardTokens_,
        uint256[][] calldata amountsClaimed_,
        bytes32[][] calldata proofs_
    )
        external
        override
    {
        if (receiver_ == address(0)) revert INVALID_RECEIVER();

        uint256 len = periodIds_.length;

        if (len == 0) revert ZERO_ARR_LENGTH();

        if (!(len == proofs_.length && len == rewardTokens_.length && len == amountsClaimed_.length)) {
            revert INVALID_BATCH_REQ();
        }
        for (uint256 i; i < len; ++i) {
            uint256 tokensToClaim = rewardTokens_[i].length;

            if (tokensToClaim == 0) revert ZERO_ARR_LENGTH();
            if (tokensToClaim != amountsClaimed_[i].length) revert INVALID_BATCH_REQ_TOKENS_AMOUNTS();

            _claim(receiver_, periodIds_[i], rewardTokens_[i], amountsClaimed_[i], tokensToClaim, proofs_[i]);

            emit RewardsClaimed(msg.sender, receiver_, periodIds_[i], rewardTokens_[i], amountsClaimed_[i]);
        }
    }

    /// @inheritdoc IRewardsDistributor
    function rescueRewards(
        address[] calldata rewardTokens_,
        uint256[] calldata amounts_
    )
        external
        override
        onlyRewardsAdmin
    {
        address receiver = superRegistry.getAddress(keccak256("PAYMASTER"));

        uint256 len = rewardTokens_.length;

        if (len == 0) revert ZERO_ARR_LENGTH();
        if (len != amounts_.length) revert INVALID_REQ_TOKENS_AMOUNTS();

        _transferRewards(receiver, rewardTokens_, amounts_, rewardTokens_.length);
    }

    /// @inheritdoc IRewardsDistributor
    function invalidatePeriod(uint256 periodId_) external override onlyRewardsAdmin {
        delete periodicRewardsMerkleRootData[periodId_];
    }

    //////////////////////////////////////////////////////////////
    //              EXTERNAL VIEW FUNCTIONS                     //
    //////////////////////////////////////////////////////////////

    /// @inheritdoc IRewardsDistributor
    function verifyClaim(
        address receiver_,
        uint256 periodId_,
        address[] calldata rewardTokens_,
        uint256[] calldata amountsClaimed_,
        bytes32[] calldata proof_
    )
        public
        view
        override
        returns (bool valid)
    {
        bytes32 root = periodicRewardsMerkleRootData[periodId_].merkleRoot;
        if (root == ZERO_BYTES32) revert MERKLE_ROOT_NOT_SET();

        uint256 deadlineTimestamp = periodicRewardsMerkleRootData[periodId_].startTimestamp + DEADLINE;
        if (block.timestamp > deadlineTimestamp) revert CLAIM_DEADLINE_PASSED();

        /// @dev a given receiver cannot claim rewards a second time for a given period
        if (periodicRewardsClaimed[periodId_][receiver_]) revert ALREADY_CLAIMED();

        /// @dev double hashing is used to protect from
        /// https://www.rareskills.io/post/merkle-tree-second-preimage-attack
        bytes32 leaf = keccak256(
            bytes.concat(keccak256(abi.encode(receiver_, periodId_, rewardTokens_, amountsClaimed_, CHAIN_ID)))
        );

        return MerkleProof.verify(proof_, root, leaf);
    }

    //////////////////////////////////////////////////////////////
    //                  INTERNAL FUNCTIONS                      //
    //////////////////////////////////////////////////////////////

    /// @notice helper function for processing claim
    function _claim(
        address receiver_,
        uint256 periodId_,
        address[] calldata rewardTokens_,
        uint256[] calldata amountsClaimed_,
        uint256 tokensToClaim_,
        bytes32[] calldata proof_
    )
        internal
    {
        /// @dev claim verification is on receiver, this allows anyone to permissionessly claim on behalf of any address
        if (!verifyClaim(receiver_, periodId_, rewardTokens_, amountsClaimed_, proof_)) revert INVALID_CLAIM();

        periodicRewardsClaimed[periodId_][receiver_] = true;

        _transferRewards(receiver_, rewardTokens_, amountsClaimed_, tokensToClaim_);
    }

    /// @notice transfer token rewards to the receiver
    function _transferRewards(
        address receiver_,
        address[] calldata rewardTokens_,
        uint256[] calldata amountsClaimed_,
        uint256 tokensToClaim_
    )
        internal
    {
        for (uint256 i; i < tokensToClaim_; ++i) {
            IERC20(rewardTokens_[i]).safeTransfer(receiver_, amountsClaimed_[i]);
        }
    }
}

File 2 of 12 : MerkleProof.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol)

pragma solidity ^0.8.20;

/**
 * @dev These functions deal with verification of Merkle Tree proofs.
 *
 * The tree and the proofs can be generated using our
 * https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
 * You will find a quickstart guide in the readme.
 *
 * WARNING: You should avoid using leaf values that are 64 bytes long prior to
 * hashing, or use a hash function other than keccak256 for hashing leaves.
 * This is because the concatenation of a sorted pair of internal nodes in
 * the Merkle tree could be reinterpreted as a leaf value.
 * OpenZeppelin's JavaScript library generates Merkle trees that are safe
 * against this attack out of the box.
 */
library MerkleProof {
    /**
     *@dev The multiproof provided is not valid.
     */
    error MerkleProofInvalidMultiproof();

    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProof(proof, leaf) == root;
    }

    /**
     * @dev Calldata version of {verify}
     */
    function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        return processProofCalldata(proof, leaf) == root;
    }

    /**
     * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
     * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
     * hash matches the root of the tree. When processing the proof, the pairs
     * of leafs & pre-images are assumed to be sorted.
     */
    function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Calldata version of {processProof}
     */
    function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
        bytes32 computedHash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            computedHash = _hashPair(computedHash, proof[i]);
        }
        return computedHash;
    }

    /**
     * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
     * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function multiProofVerify(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProof(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Calldata version of {multiProofVerify}
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function multiProofVerifyCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32 root,
        bytes32[] memory leaves
    ) internal pure returns (bool) {
        return processMultiProofCalldata(proof, proofFlags, leaves) == root;
    }

    /**
     * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
     * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
     * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
     * respectively.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
     * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
     * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
     */
    function processMultiProof(
        bytes32[] memory proof,
        bool[] memory proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofLen = proof.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proofLen != totalHashes + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            if (proofPos != proofLen) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Calldata version of {processMultiProof}.
     *
     * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
     */
    function processMultiProofCalldata(
        bytes32[] calldata proof,
        bool[] calldata proofFlags,
        bytes32[] memory leaves
    ) internal pure returns (bytes32 merkleRoot) {
        // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
        // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
        // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
        // the Merkle tree.
        uint256 leavesLen = leaves.length;
        uint256 proofLen = proof.length;
        uint256 totalHashes = proofFlags.length;

        // Check proof validity.
        if (leavesLen + proofLen != totalHashes + 1) {
            revert MerkleProofInvalidMultiproof();
        }

        // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
        // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
        bytes32[] memory hashes = new bytes32[](totalHashes);
        uint256 leafPos = 0;
        uint256 hashPos = 0;
        uint256 proofPos = 0;
        // At each step, we compute the next hash using two values:
        // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
        //   get the next hash.
        // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
        //   `proof` array.
        for (uint256 i = 0; i < totalHashes; i++) {
            bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
            bytes32 b = proofFlags[i]
                ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
                : proof[proofPos++];
            hashes[i] = _hashPair(a, b);
        }

        if (totalHashes > 0) {
            if (proofPos != proofLen) {
                revert MerkleProofInvalidMultiproof();
            }
            unchecked {
                return hashes[totalHashes - 1];
            }
        } else if (leavesLen > 0) {
            return leaves[0];
        } else {
            return proof[0];
        }
    }

    /**
     * @dev Sorts the pair (a, b) and hashes the result.
     */
    function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
        return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
    }

    /**
     * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
     */
    function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, a)
            mstore(0x20, b)
            value := keccak256(0x00, 0x40)
        }
    }
}

File 3 of 12 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

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

File 4 of 12 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

File 5 of 12 : Error.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;

library Error {
    //////////////////////////////////////////////////////////////
    //                  CONFIGURATION ERRORS                    //
    //////////////////////////////////////////////////////////////
    ///@notice errors thrown in protocol setup

    /// @dev thrown if chain id exceeds max(uint64)
    error BLOCK_CHAIN_ID_OUT_OF_BOUNDS();

    /// @dev thrown if not possible to revoke a role in broadcasting
    error CANNOT_REVOKE_NON_BROADCASTABLE_ROLES();

    /// @dev thrown if not possible to revoke last admin
    error CANNOT_REVOKE_LAST_ADMIN();

    /// @dev thrown if trying to set again pseudo immutables in super registry
    error DISABLED();

    /// @dev thrown if rescue delay is not yet set for a chain
    error DELAY_NOT_SET();

    /// @dev thrown if get native token price estimate in paymentHelper is 0
    error INVALID_NATIVE_TOKEN_PRICE();

    /// @dev thrown if wormhole refund chain id is not set
    error REFUND_CHAIN_ID_NOT_SET();

    /// @dev thrown if wormhole relayer is not set
    error RELAYER_NOT_SET();

    /// @dev thrown if a role to be revoked is not assigned
    error ROLE_NOT_ASSIGNED();

    //////////////////////////////////////////////////////////////
    //                  AUTHORIZATION ERRORS                    //
    //////////////////////////////////////////////////////////////
    ///@notice errors thrown if functions cannot be called

    /// COMMON AUTHORIZATION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if caller is not address(this), internal call
    error INVALID_INTERNAL_CALL();

    /// @dev thrown if msg.sender is not a valid amb implementation
    error NOT_AMB_IMPLEMENTATION();

    /// @dev thrown if msg.sender is not an allowed broadcaster
    error NOT_ALLOWED_BROADCASTER();

    /// @dev thrown if msg.sender is not broadcast amb implementation
    error NOT_BROADCAST_AMB_IMPLEMENTATION();

    /// @dev thrown if msg.sender is not broadcast state registry
    error NOT_BROADCAST_REGISTRY();

    /// @dev thrown if msg.sender is not core state registry
    error NOT_CORE_STATE_REGISTRY();

    /// @dev thrown if msg.sender is not emergency admin
    error NOT_EMERGENCY_ADMIN();

    /// @dev thrown if msg.sender is not emergency queue
    error NOT_EMERGENCY_QUEUE();

    /// @dev thrown if msg.sender is not minter
    error NOT_MINTER();

    /// @dev thrown if msg.sender is not minter state registry
    error NOT_MINTER_STATE_REGISTRY_ROLE();

    /// @dev thrown if msg.sender is not paymaster
    error NOT_PAYMASTER();

    /// @dev thrown if msg.sender is not payment admin
    error NOT_PAYMENT_ADMIN();

    /// @dev thrown if msg.sender is not protocol admin
    error NOT_PROTOCOL_ADMIN();

    /// @dev thrown if msg.sender is not state registry
    error NOT_STATE_REGISTRY();

    /// @dev thrown if msg.sender is not super registry
    error NOT_SUPER_REGISTRY();

    /// @dev thrown if msg.sender is not superform router
    error NOT_SUPERFORM_ROUTER();

    /// @dev thrown if msg.sender is not a superform
    error NOT_SUPERFORM();

    /// @dev thrown if msg.sender is not superform factory
    error NOT_SUPERFORM_FACTORY();

    /// @dev thrown if msg.sender is not timelock form
    error NOT_TIMELOCK_SUPERFORM();

    /// @dev thrown if msg.sender is not timelock state registry
    error NOT_TIMELOCK_STATE_REGISTRY();

    /// @dev thrown if msg.sender is not user or disputer
    error NOT_VALID_DISPUTER();

    /// @dev thrown if the msg.sender is not privileged caller
    error NOT_PRIVILEGED_CALLER(bytes32 role);

    /// STATE REGISTRY AUTHORIZATION ERRORS
    /// ---------------------------------------------------------

    /// @dev layerzero adapter specific error, thrown if caller not layerzero endpoint
    error CALLER_NOT_ENDPOINT();

    /// @dev hyperlane adapter specific error, thrown if caller not hyperlane mailbox
    error CALLER_NOT_MAILBOX();

    /// @dev wormhole relayer specific error, thrown if caller not wormhole relayer
    error CALLER_NOT_RELAYER();

    /// @dev thrown if src chain sender is not valid
    error INVALID_SRC_SENDER();

    //////////////////////////////////////////////////////////////
    //                  INPUT VALIDATION ERRORS                 //
    //////////////////////////////////////////////////////////////
    ///@notice errors thrown if input variables are not valid

    /// COMMON INPUT VALIDATION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if there is an array length mismatch
    error ARRAY_LENGTH_MISMATCH();

    /// @dev thrown if payload id does not exist
    error INVALID_PAYLOAD_ID();

    /// @dev error thrown when msg value should be zero in certain payable functions
    error MSG_VALUE_NOT_ZERO();

    /// @dev thrown if amb ids length is 0
    error ZERO_AMB_ID_LENGTH();

    /// @dev thrown if address input is address 0
    error ZERO_ADDRESS();

    /// @dev thrown if amount input is 0
    error ZERO_AMOUNT();

    /// @dev thrown if final token is address 0
    error ZERO_FINAL_TOKEN();

    /// @dev thrown if value input is 0
    error ZERO_INPUT_VALUE();

    /// SUPERFORM ROUTER INPUT VALIDATION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if the vaults data is invalid
    error INVALID_SUPERFORMS_DATA();

    /// @dev thrown if receiver address is not set
    error RECEIVER_ADDRESS_NOT_SET();

    /// SUPERFORM FACTORY INPUT VALIDATION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if a form is not ERC165 compatible
    error ERC165_UNSUPPORTED();

    /// @dev thrown if a form is not form interface compatible
    error FORM_INTERFACE_UNSUPPORTED();

    /// @dev error thrown if form implementation address already exists
    error FORM_IMPLEMENTATION_ALREADY_EXISTS();

    /// @dev error thrown if form implementation id already exists
    error FORM_IMPLEMENTATION_ID_ALREADY_EXISTS();

    /// @dev thrown if a form does not exist
    error FORM_DOES_NOT_EXIST();

    /// @dev thrown if form id is larger than max uint16
    error INVALID_FORM_ID();

    /// @dev thrown if superform not on factory
    error SUPERFORM_ID_NONEXISTENT();

    /// @dev thrown if same vault and form implementation is used to create new superform
    error VAULT_FORM_IMPLEMENTATION_COMBINATION_EXISTS();

    /// FORM INPUT VALIDATION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if in case of no txData, if liqData.token != vault.asset()
    /// in case of txData, if token output of swap != vault.asset()
    error DIFFERENT_TOKENS();

    /// @dev thrown if the amount in direct withdraw is not correct
    error DIRECT_WITHDRAW_INVALID_LIQ_REQUEST();

    /// @dev thrown if the amount in xchain withdraw is not correct
    error XCHAIN_WITHDRAW_INVALID_LIQ_REQUEST();

    /// LIQUIDITY BRIDGE INPUT VALIDATION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if route id is blacklisted in socket
    error BLACKLISTED_ROUTE_ID();

    /// @dev thrown if route id is not blacklisted in socket
    error NOT_BLACKLISTED_ROUTE_ID();

    /// @dev error thrown when txData selector of lifi bridge is a blacklisted selector
    error BLACKLISTED_SELECTOR();

    /// @dev error thrown when txData selector of lifi bridge is not a blacklisted selector
    error NOT_BLACKLISTED_SELECTOR();

    /// @dev thrown if a certain action of the user is not allowed given the txData provided
    error INVALID_ACTION();

    /// @dev thrown if in deposits, the liqDstChainId doesn't match the stateReq dstChainId
    error INVALID_DEPOSIT_LIQ_DST_CHAIN_ID();

    /// @dev thrown if index is invalid
    error INVALID_INDEX();

    /// @dev thrown if the chain id in the txdata is invalid
    error INVALID_TXDATA_CHAIN_ID();

    /// @dev thrown if the validation of bridge txData fails due to a destination call present
    error INVALID_TXDATA_NO_DESTINATIONCALL_ALLOWED();

    /// @dev thrown if the validation of bridge txData fails due to wrong receiver
    error INVALID_TXDATA_RECEIVER();

    /// @dev thrown if the validation of bridge txData fails due to wrong token
    error INVALID_TXDATA_TOKEN();

    /// @dev thrown if txData is not present (in case of xChain actions)
    error NO_TXDATA_PRESENT();

    /// STATE REGISTRY INPUT VALIDATION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if payload is being updated with final amounts length different than amounts length
    error DIFFERENT_PAYLOAD_UPDATE_AMOUNTS_LENGTH();

    /// @dev thrown if payload is being updated with tx data length different than liq data length
    error DIFFERENT_PAYLOAD_UPDATE_TX_DATA_LENGTH();

    /// @dev thrown if keeper update final token is different than the vault underlying
    error INVALID_UPDATE_FINAL_TOKEN();

    /// @dev thrown if broadcast finality for wormhole is invalid
    error INVALID_BROADCAST_FINALITY();

    /// @dev thrown if amb id is not valid leading to an address 0 of the implementation
    error INVALID_BRIDGE_ID();

    /// @dev thrown if chain id involved in xchain message is invalid
    error INVALID_CHAIN_ID();

    /// @dev thrown if payload update amount isn't equal to dst swapper amount
    error INVALID_DST_SWAP_AMOUNT();

    /// @dev thrown if message amb and proof amb are the same
    error INVALID_PROOF_BRIDGE_ID();

    /// @dev thrown if order of proof AMBs is incorrect, either duplicated or not incrementing
    error INVALID_PROOF_BRIDGE_IDS();

    /// @dev thrown if rescue data lengths are invalid
    error INVALID_RESCUE_DATA();

    /// @dev thrown if delay is invalid
    error INVALID_TIMELOCK_DELAY();

    /// @dev thrown if amounts being sent in update payload mean a negative slippage
    error NEGATIVE_SLIPPAGE();

    /// @dev thrown if slippage is outside of bounds
    error SLIPPAGE_OUT_OF_BOUNDS();

    /// SUPERPOSITION INPUT VALIDATION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if src senders mismatch in state sync
    error SRC_SENDER_MISMATCH();

    /// @dev thrown if src tx types mismatch in state sync
    error SRC_TX_TYPE_MISMATCH();

    //////////////////////////////////////////////////////////////
    //                  EXECUTION ERRORS                        //
    //////////////////////////////////////////////////////////////
    ///@notice errors thrown due to function execution logic

    /// COMMON EXECUTION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if the swap in a direct deposit resulted in insufficient tokens
    error DIRECT_DEPOSIT_SWAP_FAILED();

    /// @dev thrown if payload is not unique
    error DUPLICATE_PAYLOAD();

    /// @dev thrown if native tokens fail to be sent to superform contracts
    error FAILED_TO_SEND_NATIVE();

    /// @dev thrown if allowance is not correct to deposit
    error INSUFFICIENT_ALLOWANCE_FOR_DEPOSIT();

    /// @dev thrown if contract has insufficient balance for operations
    error INSUFFICIENT_BALANCE();

    /// @dev thrown if native amount is not at least equal to the amount in the request
    error INSUFFICIENT_NATIVE_AMOUNT();

    /// @dev thrown if payload cannot be decoded
    error INVALID_PAYLOAD();

    /// @dev thrown if payload status is invalid
    error INVALID_PAYLOAD_STATUS();

    /// @dev thrown if payload type is invalid
    error INVALID_PAYLOAD_TYPE();

    /// LIQUIDITY BRIDGE EXECUTION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if we try to decode the final swap output token in a xChain liquidity bridging action
    error CANNOT_DECODE_FINAL_SWAP_OUTPUT_TOKEN();

    /// @dev thrown if liquidity bridge fails for erc20 or native tokens
    error FAILED_TO_EXECUTE_TXDATA(address token);

    /// @dev thrown if asset being used for deposit mismatches in multivault deposits
    error INVALID_DEPOSIT_TOKEN();

    /// STATE REGISTRY EXECUTION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if bridge tokens haven't arrived to destination
    error BRIDGE_TOKENS_PENDING();

    /// @dev thrown if withdrawal tx data cannot be updated
    error CANNOT_UPDATE_WITHDRAW_TX_DATA();

    /// @dev thrown if rescue passed dispute deadline
    error DISPUTE_TIME_ELAPSED();

    /// @dev thrown if message failed to reach the specified level of quorum needed
    error INSUFFICIENT_QUORUM();

    /// @dev thrown if broadcast payload is invalid
    error INVALID_BROADCAST_PAYLOAD();

    /// @dev thrown if broadcast fee is invalid
    error INVALID_BROADCAST_FEE();

    /// @dev thrown if retry fees is less than required
    error INVALID_RETRY_FEE();

    /// @dev thrown if broadcast message type is wrong
    error INVALID_MESSAGE_TYPE();

    /// @dev thrown if payload hash is invalid during `retryMessage` on Layezero implementation
    error INVALID_PAYLOAD_HASH();

    /// @dev thrown if update payload function was called on a wrong payload
    error INVALID_PAYLOAD_UPDATE_REQUEST();

    /// @dev thrown if a state registry id is 0
    error INVALID_REGISTRY_ID();

    /// @dev thrown if a form state registry id is 0
    error INVALID_FORM_REGISTRY_ID();

    /// @dev thrown if trying to finalize the payload but the withdraw is still locked
    error LOCKED();

    /// @dev thrown if payload is already updated (during xChain deposits)
    error PAYLOAD_ALREADY_UPDATED();

    /// @dev thrown if payload is already processed
    error PAYLOAD_ALREADY_PROCESSED();

    /// @dev thrown if payload is not in UPDATED state
    error PAYLOAD_NOT_UPDATED();

    /// @dev thrown if rescue is still in timelocked state
    error RESCUE_LOCKED();

    /// @dev thrown if rescue is already proposed
    error RESCUE_ALREADY_PROPOSED();

    /// @dev thrown if payload hash is zero during `retryMessage` on Layezero implementation
    error ZERO_PAYLOAD_HASH();

    /// DST SWAPPER EXECUTION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if process dst swap is tried for processed payload id
    error DST_SWAP_ALREADY_PROCESSED();

    /// @dev thrown if indices have duplicates
    error DUPLICATE_INDEX();

    /// @dev thrown if failed dst swap is already updated
    error FAILED_DST_SWAP_ALREADY_UPDATED();

    /// @dev thrown if indices are out of bounds
    error INDEX_OUT_OF_BOUNDS();

    /// @dev thrown if failed swap token amount is 0
    error INVALID_DST_SWAPPER_FAILED_SWAP();

    /// @dev thrown if failed swap token amount is not 0 and if token balance is less than amount (non zero)
    error INVALID_DST_SWAPPER_FAILED_SWAP_NO_TOKEN_BALANCE();

    /// @dev thrown if failed swap token amount is not 0 and if native amount is less than amount (non zero)
    error INVALID_DST_SWAPPER_FAILED_SWAP_NO_NATIVE_BALANCE();

    /// @dev forbid xChain deposits with destination swaps without interim token set (for user protection)
    error INVALID_INTERIM_TOKEN();

    /// @dev thrown if dst swap output is less than minimum expected
    error INVALID_SWAP_OUTPUT();

    /// FORM EXECUTION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if try to forward 4626 share from the superform
    error CANNOT_FORWARD_4646_TOKEN();

    /// @dev thrown in KYCDAO form if no KYC token is present
    error NO_VALID_KYC_TOKEN();

    /// @dev thrown in forms where a certain functionality is not allowed or implemented
    error NOT_IMPLEMENTED();

    /// @dev thrown if form implementation is PAUSED, users cannot perform any action
    error PAUSED();

    /// @dev thrown if shares != deposit output or assets != redeem output when minting SuperPositions
    error VAULT_IMPLEMENTATION_FAILED();

    /// @dev thrown if withdrawal tx data is not updated
    error WITHDRAW_TOKEN_NOT_UPDATED();

    /// @dev thrown if withdrawal tx data is not updated
    error WITHDRAW_TX_DATA_NOT_UPDATED();

    /// @dev thrown when redeeming from vault yields zero collateral
    error WITHDRAW_ZERO_COLLATERAL();

    /// PAYMENT HELPER EXECUTION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if chainlink is reporting an improper price
    error CHAINLINK_MALFUNCTION();

    /// @dev thrown if chainlink is reporting an incomplete round
    error CHAINLINK_INCOMPLETE_ROUND();

    /// @dev thrown if feed decimals is not 8
    error CHAINLINK_UNSUPPORTED_DECIMAL();

    /// EMERGENCY QUEUE EXECUTION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if emergency withdraw is not queued
    error EMERGENCY_WITHDRAW_NOT_QUEUED();

    /// @dev thrown if emergency withdraw is already processed
    error EMERGENCY_WITHDRAW_PROCESSED_ALREADY();

    /// SUPERPOSITION EXECUTION ERRORS
    /// ---------------------------------------------------------

    /// @dev thrown if uri cannot be updated
    error DYNAMIC_URI_FROZEN();

    /// @dev thrown if tx history is not found while state sync
    error TX_HISTORY_NOT_FOUND();
}

File 6 of 12 : ISuperRBAC.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;

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

/// @title ISuperRBAC
/// @dev Interface for SuperRBAC
/// @author Zeropoint Labs
interface ISuperRBAC is IAccessControl {

    //////////////////////////////////////////////////////////////
    //                           STRUCTS                         //
    //////////////////////////////////////////////////////////////

    struct InitialRoleSetup {
        address admin;
        address emergencyAdmin;
        address paymentAdmin;
        address csrProcessor;
        address tlProcessor;
        address brProcessor;
        address csrUpdater;
        address srcVaaRelayer;
        address dstSwapper;
        address csrRescuer;
        address csrDisputer;
    }

    //////////////////////////////////////////////////////////////
    //                          EVENTS                          //
    //////////////////////////////////////////////////////////////

    /// @dev is emitted when superRegistry is set
    event SuperRegistrySet(address indexed superRegistry);

    /// @dev is emitted when an admin is set for a role
    event RoleAdminSet(bytes32 role, bytes32 adminRole);

    //////////////////////////////////////////////////////////////
    //              EXTERNAL VIEW FUNCTIONS                     //
    //////////////////////////////////////////////////////////////

    /// @dev returns the id of the protocol admin role
    function PROTOCOL_ADMIN_ROLE() external view returns (bytes32);

    /// @dev returns the id of the emergency admin role
    function EMERGENCY_ADMIN_ROLE() external view returns (bytes32);

    /// @dev returns the id of the payment admin role
    function PAYMENT_ADMIN_ROLE() external view returns (bytes32);

    /// @dev returns the id of the broadcaster role
    function BROADCASTER_ROLE() external view returns (bytes32);

    /// @dev returns the id of the core state registry processor role
    function CORE_STATE_REGISTRY_PROCESSOR_ROLE() external view returns (bytes32);

    /// @dev returns the id of the timelock state registry processor role
    function TIMELOCK_STATE_REGISTRY_PROCESSOR_ROLE() external view returns (bytes32);

    /// @dev returns the id of the broadcast state registry processor role
    function BROADCAST_STATE_REGISTRY_PROCESSOR_ROLE() external view returns (bytes32);

    /// @dev returns the id of the core state registry updater role
    function CORE_STATE_REGISTRY_UPDATER_ROLE() external view returns (bytes32);

    /// @dev returns the id of the dst swapper role
    function DST_SWAPPER_ROLE() external view returns (bytes32);

    /// @dev returns the id of the core state registry rescuer role
    function CORE_STATE_REGISTRY_RESCUER_ROLE() external view returns (bytes32);

    /// @dev returns the id of the core state registry rescue disputer role
    function CORE_STATE_REGISTRY_DISPUTER_ROLE() external view returns (bytes32);

    /// @dev returns the id of wormhole vaa relayer role
    function WORMHOLE_VAA_RELAYER_ROLE() external view returns (bytes32);

    /// @dev returns whether the given address has the protocol admin role
    /// @param admin_ the address to check
    function hasProtocolAdminRole(address admin_) external view returns (bool);

    /// @dev returns whether the given address has the emergency admin role
    /// @param admin_ the address to check
    function hasEmergencyAdminRole(address admin_) external view returns (bool);

    //////////////////////////////////////////////////////////////
    //              EXTERNAL WRITE FUNCTIONS                    //
    //////////////////////////////////////////////////////////////

    /// @dev updates the super registry address
    function setSuperRegistry(address superRegistry_) external;

    /// @dev configures a new role in superForm
    /// @param role_ the role to set
    /// @param adminRole_ the admin role to set as admin
    function setRoleAdmin(bytes32 role_, bytes32 adminRole_) external;

    /// @dev revokes the role_ from superRegistryAddressId_ on all chains
    /// @param role_ the role to revoke
    /// @param extraData_ amb config if broadcasting is required
    /// @param superRegistryAddressId_ the super registry address id
    function revokeRoleSuperBroadcast(
        bytes32 role_,
        bytes memory extraData_,
        bytes32 superRegistryAddressId_
    )
        external
        payable;

    /// @dev allows sync of global roles from different chains using broadcast registry
    /// @notice may not work for all roles
    function stateSyncBroadcast(bytes memory data_) external;
}

File 7 of 12 : ISuperRegistry.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;

/// @title ISuperRegistry
/// @dev Interface for SuperRegistry
/// @author Zeropoint Labs
interface ISuperRegistry {
    //////////////////////////////////////////////////////////////
    //                          EVENTS                          //
    //////////////////////////////////////////////////////////////

    /// @dev emitted when permit2 is set.
    event SetPermit2(address indexed permit2);

    /// @dev is emitted when an address is set.
    event AddressUpdated(
        bytes32 indexed protocolAddressId, uint64 indexed chainId, address indexed oldAddress, address newAddress
    );

    /// @dev is emitted when a new token bridge is configured.
    event SetBridgeAddress(uint256 indexed bridgeId, address indexed bridgeAddress);

    /// @dev is emitted when a new bridge validator is configured.
    event SetBridgeValidator(uint256 indexed bridgeId, address indexed bridgeValidator);

    /// @dev is emitted when a new amb is configured.
    event SetAmbAddress(uint8 indexed ambId_, address indexed ambAddress_, bool indexed isBroadcastAMB_);

    /// @dev is emitted when a new state registry is configured.
    event SetStateRegistryAddress(uint8 indexed registryId_, address indexed registryAddress_);

    /// @dev is emitted when a new delay is configured.
    event SetDelay(uint256 indexed oldDelay_, uint256 indexed newDelay_);

    /// @dev is emitted when a new vault limit is configured
    event SetVaultLimitPerDestination(uint64 indexed chainId_, uint256 indexed vaultLimit_);

    //////////////////////////////////////////////////////////////
    //              EXTERNAL VIEW FUNCTIONS                     //
    //////////////////////////////////////////////////////////////

    /// @dev gets the deposit rescue delay
    function delay() external view returns (uint256);

    /// @dev returns the permit2 address
    function PERMIT2() external view returns (address);

    /// @dev returns the id of the superform router module
    function SUPERFORM_ROUTER() external view returns (bytes32);

    /// @dev returns the id of the superform factory module
    function SUPERFORM_FACTORY() external view returns (bytes32);

    /// @dev returns the id of the superform paymaster contract
    function PAYMASTER() external view returns (bytes32);

    /// @dev returns the id of the superform payload helper contract
    function PAYMENT_HELPER() external view returns (bytes32);

    /// @dev returns the id of the core state registry module
    function CORE_STATE_REGISTRY() external view returns (bytes32);

    /// @dev returns the id of the timelock form state registry module
    function TIMELOCK_STATE_REGISTRY() external view returns (bytes32);

    /// @dev returns the id of the broadcast state registry module
    function BROADCAST_REGISTRY() external view returns (bytes32);

    /// @dev returns the id of the super positions module
    function SUPER_POSITIONS() external view returns (bytes32);

    /// @dev returns the id of the super rbac module
    function SUPER_RBAC() external view returns (bytes32);

    /// @dev returns the id of the payload helper module
    function PAYLOAD_HELPER() external view returns (bytes32);

    /// @dev returns the id of the dst swapper keeper
    function DST_SWAPPER() external view returns (bytes32);

    /// @dev returns the id of the emergency queue
    function EMERGENCY_QUEUE() external view returns (bytes32);

    /// @dev returns the id of the superform receiver
    function SUPERFORM_RECEIVER() external view returns (bytes32);

    /// @dev returns the id of the payment admin keeper
    function PAYMENT_ADMIN() external view returns (bytes32);

    /// @dev returns the id of the core state registry processor keeper
    function CORE_REGISTRY_PROCESSOR() external view returns (bytes32);

    /// @dev returns the id of the broadcast registry processor keeper
    function BROADCAST_REGISTRY_PROCESSOR() external view returns (bytes32);

    /// @dev returns the id of the timelock form state registry processor keeper
    function TIMELOCK_REGISTRY_PROCESSOR() external view returns (bytes32);

    /// @dev returns the id of the core state registry updater keeper
    function CORE_REGISTRY_UPDATER() external view returns (bytes32);

    /// @dev returns the id of the core state registry updater keeper
    function CORE_REGISTRY_RESCUER() external view returns (bytes32);

    /// @dev returns the id of the core state registry updater keeper
    function CORE_REGISTRY_DISPUTER() external view returns (bytes32);

    /// @dev returns the id of the core state registry updater keeper
    function DST_SWAPPER_PROCESSOR() external view returns (bytes32);

    /// @dev gets the address of a contract on current chain
    /// @param id_ is the id of the contract
    function getAddress(bytes32 id_) external view returns (address);

    /// @dev gets the address of a contract on a target chain
    /// @param id_ is the id of the contract
    /// @param chainId_ is the chain id of that chain
    function getAddressByChainId(bytes32 id_, uint64 chainId_) external view returns (address);

    /// @dev gets the address of a bridge
    /// @param bridgeId_ is the id of a bridge
    /// @return bridgeAddress_ is the address of the form
    function getBridgeAddress(uint8 bridgeId_) external view returns (address bridgeAddress_);

    /// @dev gets the address of a bridge validator
    /// @param bridgeId_ is the id of a bridge
    /// @return bridgeValidator_ is the address of the form
    function getBridgeValidator(uint8 bridgeId_) external view returns (address bridgeValidator_);

    /// @dev gets the address of a amb
    /// @param ambId_ is the id of a bridge
    /// @return ambAddress_ is the address of the form
    function getAmbAddress(uint8 ambId_) external view returns (address ambAddress_);

    /// @dev gets the id of the amb
    /// @param ambAddress_ is the address of an amb
    /// @return ambId_ is the identifier of an amb
    function getAmbId(address ambAddress_) external view returns (uint8 ambId_);

    /// @dev gets the address of the registry
    /// @param registryId_ is the id of the state registry
    /// @return registryAddress_ is the address of the state registry
    function getStateRegistry(uint8 registryId_) external view returns (address registryAddress_);

    /// @dev gets the id of the registry
    /// @notice reverts if the id is not found
    /// @param registryAddress_ is the address of the state registry
    /// @return registryId_ is the id of the state registry
    function getStateRegistryId(address registryAddress_) external view returns (uint8 registryId_);

    /// @dev gets the safe vault limit
    /// @param chainId_ is the id of the remote chain
    /// @return vaultLimitPerDestination_ is the safe number of vaults to deposit
    /// without hitting out of gas error
    function getVaultLimitPerDestination(uint64 chainId_) external view returns (uint256 vaultLimitPerDestination_);

    /// @dev helps validate if an address is a valid state registry
    /// @param registryAddress_ is the address of the state registry
    /// @return valid_ a flag indicating if its valid.
    function isValidStateRegistry(address registryAddress_) external view returns (bool valid_);

    /// @dev helps validate if an address is a valid amb implementation
    /// @param ambAddress_ is the address of the amb implementation
    /// @return valid_ a flag indicating if its valid.
    function isValidAmbImpl(address ambAddress_) external view returns (bool valid_);

    /// @dev helps validate if an address is a valid broadcast amb implementation
    /// @param ambAddress_ is the address of the broadcast amb implementation
    /// @return valid_ a flag indicating if its valid.
    function isValidBroadcastAmbImpl(address ambAddress_) external view returns (bool valid_);

    //////////////////////////////////////////////////////////////
    //              EXTERNAL WRITE FUNCTIONS                    //
    //////////////////////////////////////////////////////////////

    /// @dev sets the deposit rescue delay
    /// @param delay_ the delay in seconds before the deposit rescue can be finalized
    function setDelay(uint256 delay_) external;

    /// @dev sets the permit2 address
    /// @param permit2_ the address of the permit2 contract
    function setPermit2(address permit2_) external;

    /// @dev sets the safe vault limit
    /// @param chainId_ is the remote chain identifier
    /// @param vaultLimit_ is the max limit of vaults per transaction
    function setVaultLimitPerDestination(uint64 chainId_, uint256 vaultLimit_) external;

    /// @dev sets new addresses on specific chains.
    /// @param ids_ are the identifiers of the address on that chain
    /// @param newAddresses_  are the new addresses on that chain
    /// @param chainIds_ are the chain ids of that chain
    function batchSetAddress(
        bytes32[] calldata ids_,
        address[] calldata newAddresses_,
        uint64[] calldata chainIds_
    )
        external;

    /// @dev sets a new address on a specific chain.
    /// @param id_ the identifier of the address on that chain
    /// @param newAddress_ the new address on that chain
    /// @param chainId_ the chain id of that chain
    function setAddress(bytes32 id_, address newAddress_, uint64 chainId_) external;

    /// @dev allows admin to set the bridge address for an bridge id.
    /// @notice this function operates in an APPEND-ONLY fashion.
    /// @param bridgeId_         represents the bridge unique identifier.
    /// @param bridgeAddress_    represents the bridge address.
    /// @param bridgeValidator_  represents the bridge validator address.
    function setBridgeAddresses(
        uint8[] memory bridgeId_,
        address[] memory bridgeAddress_,
        address[] memory bridgeValidator_
    )
        external;

    /// @dev allows admin to set the amb address for an amb id.
    /// @notice this function operates in an APPEND-ONLY fashion.
    /// @param ambId_         represents the bridge unique identifier.
    /// @param ambAddress_    represents the bridge address.
    /// @param isBroadcastAMB_ represents whether the amb implementation supports broadcasting
    function setAmbAddress(
        uint8[] memory ambId_,
        address[] memory ambAddress_,
        bool[] memory isBroadcastAMB_
    )
        external;

    /// @dev allows admin to set the state registry address for an state registry id.
    /// @notice this function operates in an APPEND-ONLY fashion.
    /// @param registryId_    represents the state registry's unique identifier.
    /// @param registryAddress_    represents the state registry's address.
    function setStateRegistryAddress(uint8[] memory registryId_, address[] memory registryAddress_) external;
}

File 8 of 12 : IRewardsDistributor.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;

/// @title IRewardsDistributor
/// @notice interface for the RewardsDistributor contract
/// @author Zeropoint Labs
interface IRewardsDistributor {
    //////////////////////////////////////////////////////////////
    //                     ERRORS                               //
    //////////////////////////////////////////////////////////////

    /// @dev error message for not being a rewards admin
    error NOT_REWARDS_ADMIN();

    /// @dev error message for an invalid claim
    error INVALID_CLAIM();

    /// @dev error message for an invalid batch request (different array lengths)
    error INVALID_BATCH_REQ();

    /// @dev error message for an invalid claim (invalid token/amounts array length)
    error INVALID_REQ_TOKENS_AMOUNTS();

    /// @dev error message for an invalid batch claim (invalid token/amounts array length)
    error INVALID_BATCH_REQ_TOKENS_AMOUNTS();

    /// @dev error message for an invalid merkle root
    error INVALID_MERKLE_ROOT();

    /// @dev error message for an invalid receiver
    error INVALID_RECEIVER();

    /// @dev error message for when merkle root is not set
    error MERKLE_ROOT_NOT_SET();

    /// @dev error message for when the array length is zero
    error ZERO_ARR_LENGTH();

    /// @dev error message for when the claimer has already claimed their rewards
    error ALREADY_CLAIMED();

    /// @dev error message for when the claim deadline has passed
    error CLAIM_DEADLINE_PASSED();

    //////////////////////////////////////////////////////////////
    //                      EVENTS                              //
    //////////////////////////////////////////////////////////////

    /// @dev Emitted when tokens are claimed.
    event RewardsClaimed(
        address indexed claimer,
        address indexed receiver,
        uint256 periodId,
        address[] rewardTokens_,
        uint256[] amountsClaimed_
    );

    /// @dev Emitted when new periodic rewards are set.
    event PeriodicRewardsSet(uint256 indexed periodId, bytes32 merkleRoot, uint256 startTimestamp);

    //////////////////////////////////////////////////////////////
    //                      STRUCTS                             //
    //////////////////////////////////////////////////////////////

    struct PeriodicRewardsData {
        uint256 startTimestamp;
        bytes32 merkleRoot;
    }

    //////////////////////////////////////////////////////////////
    //              EXTERNAL WRITE FUNCTIONS                    //
    //////////////////////////////////////////////////////////////

    /// @notice allows owner to set the merkle root for the current period rewards
    /// @param root_ is the merkle root for that period generated offchain
    /// @dev [gas-opt]: function is payable to avoid msg.value checks
    function setPeriodicRewards(bytes32 root_) external payable;

    /// @notice lets an account claim a given quantity of reward tokens.
    /// @param receiver_ is the receiver of the tokens to claim.
    /// @param periodId_ is the specific period to claim
    /// @param rewardTokens_ are the address of the rewards token to claim on the specific period
    /// @param amountsClaimed_ adre the amount of tokens to claim for each reward token
    /// @param proof_ the merkle proof
    function claim(
        address receiver_,
        uint256 periodId_,
        address[] calldata rewardTokens_,
        uint256[] calldata amountsClaimed_,
        bytes32[] calldata proof_
    )
        external;

    /// @notice is a batching version of claim()
    function batchClaim(
        address receiver_,
        uint256[] calldata periodIds_,
        address[][] calldata rewardTokens_,
        uint256[][] calldata amountsClaimed_,
        bytes32[][] calldata proofs_
    )
        external;

    /// @notice allows the owner to rescue any ERC20 tokens sent to the contract
    /// @param rewardTokens_ are the address of the rewards token to claim on the specific period
    /// @param amounts_ are the amount of tokens to claim for each reward token
    function rescueRewards(address[] calldata rewardTokens_, uint256[] calldata amounts_) external;

    /// @notice allows the owner to invalidate a period
    /// @param periodId_ is the period identifier
    function invalidatePeriod(uint256 periodId_) external;

    //////////////////////////////////////////////////////////////
    //              EXTERNAL VIEW FUNCTIONS                     //
    //////////////////////////////////////////////////////////////

    /// @notice helps validate if the claim is valid
    /// @param claimer_ is the address of the claiming wallet
    /// @param periodId_ is the period identifier
    /// @param rewardTokens_ are the address of the rewards token to claim on the specific period
    /// @param amountsClaimed_ adre the amount of tokens to claim for each reward token
    /// @param proof_ is the merkle proof
    /// @dev returns false even if proof is valid and user already claimed their periodic rewards
    function verifyClaim(
        address claimer_,
        uint256 periodId_,
        address[] calldata rewardTokens_,
        uint256[] calldata amountsClaimed_,
        bytes32[] calldata proof_
    )
        external
        view
        returns (bool valid);
}

File 9 of 12 : 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 ERC-20 standard as defined in the ERC.
 */
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);
}

File 10 of 12 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 11 of 12 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

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

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

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

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

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

File 12 of 12 : 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 ERC-165 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;
}

Settings
{
  "remappings": [
    "solmate/=lib/ERC1155A/lib/solmate/src/",
    "ERC1155A/=lib/ERC1155A/src/",
    "@openzeppelin/contracts/=lib/ERC1155A/lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/ds-test/src/",
    "erc4626-tests/=lib/ERC1155A/lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/ERC1155A/lib/openzeppelin-contracts/",
    "pigeon/=lib/pigeon/src/",
    "solady/=lib/pigeon/lib/solady/",
    "super-vaults/=lib/super-vaults/src/",
    "v2-core/=lib/super-vaults/lib/v2-core/contracts/",
    "v2-periphery/=lib/super-vaults/lib/v2-periphery/contracts/",
    "v3-core/=lib/super-vaults/lib/v3-core/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"superRegistry_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ALREADY_CLAIMED","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"BLOCK_CHAIN_ID_OUT_OF_BOUNDS","type":"error"},{"inputs":[],"name":"CLAIM_DEADLINE_PASSED","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"INVALID_BATCH_REQ","type":"error"},{"inputs":[],"name":"INVALID_BATCH_REQ_TOKENS_AMOUNTS","type":"error"},{"inputs":[],"name":"INVALID_CLAIM","type":"error"},{"inputs":[],"name":"INVALID_MERKLE_ROOT","type":"error"},{"inputs":[],"name":"INVALID_RECEIVER","type":"error"},{"inputs":[],"name":"INVALID_REQ_TOKENS_AMOUNTS","type":"error"},{"inputs":[],"name":"MERKLE_ROOT_NOT_SET","type":"error"},{"inputs":[],"name":"NOT_REWARDS_ADMIN","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"ZERO_ADDRESS","type":"error"},{"inputs":[],"name":"ZERO_ARR_LENGTH","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"periodId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"startTimestamp","type":"uint256"}],"name":"PeriodicRewardsSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"claimer","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"periodId","type":"uint256"},{"indexed":false,"internalType":"address[]","name":"rewardTokens_","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"amountsClaimed_","type":"uint256[]"}],"name":"RewardsClaimed","type":"event"},{"inputs":[],"name":"CHAIN_ID","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEADLINE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"uint256[]","name":"periodIds_","type":"uint256[]"},{"internalType":"address[][]","name":"rewardTokens_","type":"address[][]"},{"internalType":"uint256[][]","name":"amountsClaimed_","type":"uint256[][]"},{"internalType":"bytes32[][]","name":"proofs_","type":"bytes32[][]"}],"name":"batchClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"uint256","name":"periodId_","type":"uint256"},{"internalType":"address[]","name":"rewardTokens_","type":"address[]"},{"internalType":"uint256[]","name":"amountsClaimed_","type":"uint256[]"},{"internalType":"bytes32[]","name":"proof_","type":"bytes32[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentPeriodId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"periodId_","type":"uint256"}],"name":"invalidatePeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"periodId","type":"uint256"},{"internalType":"address","name":"claimerAddress","type":"address"}],"name":"periodicRewardsClaimed","outputs":[{"internalType":"bool","name":"claimed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"periodId","type":"uint256"}],"name":"periodicRewardsMerkleRootData","outputs":[{"internalType":"uint256","name":"startTimestamp","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"rewardTokens_","type":"address[]"},{"internalType":"uint256[]","name":"amounts_","type":"uint256[]"}],"name":"rescueRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"root_","type":"bytes32"}],"name":"setPeriodicRewards","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"superRegistry","outputs":[{"internalType":"contract ISuperRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver_","type":"address"},{"internalType":"uint256","name":"periodId_","type":"uint256"},{"internalType":"address[]","name":"rewardTokens_","type":"address[]"},{"internalType":"uint256[]","name":"amountsClaimed_","type":"uint256[]"},{"internalType":"bytes32[]","name":"proof_","type":"bytes32[]"}],"name":"verifyClaim","outputs":[{"internalType":"bool","name":"valid","type":"bool"}],"stateMutability":"view","type":"function"}]

60c060405234801561001057600080fd5b5060405161168f38038061168f83398101604081905261002f9161009c565b6001600160a01b0381166100565760405163538ba4f960e01b815260040160405180910390fd5b6001600160401b0346111561007e57604051637ecdf93360e01b815260040160405180910390fd5b6001600160a01b03166080526001600160401b03461660a0526100cc565b6000602082840312156100ae57600080fd5b81516001600160a01b03811681146100c557600080fd5b9392505050565b60805160a05161157c610113600039600081816101ef0152610c7701526000818160d30152818161030401528181610826015281816109920152610aea015261157c6000f3fe6080604052600436106100a75760003560e01c80637426159111610064578063742615911461019257806385e1f4d0146101dd578063988e65951461022a578063a082c86e1461024e578063b6e5ef1814610266578063e08480d01461028657600080fd5b80632462cbfb146100ac57806324c73dda146100c15780632ad750371461011257806347575953146101325780634cf309ae146101525780635092089414610172575b600080fd5b6100bf6100ba366004611066565b6102cf565b005b3480156100cd57600080fd5b506100f57f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561011e57600080fd5b506100bf61012d3660046110e0565b6104b2565b34801561013e57600080fd5b506100bf61014d366004611196565b61058b565b34801561015e57600080fd5b506100bf61016d366004611066565b6107f1565b34801561017e57600080fd5b506100bf61018d36600461126f565b61095d565b34801561019e57600080fd5b506101cd6101ad3660046112db565b600260209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610109565b3480156101e957600080fd5b506102117f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff9091168152602001610109565b34801561023657600080fd5b5061024060005481565b604051908152602001610109565b34801561025a57600080fd5b506102406301dfe20081565b34801561027257600080fd5b506101cd6102813660046110e0565b610bb8565b34801561029257600080fd5b506102ba6102a1366004611066565b6001602081905260009182526040909120805491015482565b60408051928352602083019190915201610109565b6040516321f8a72160e01b81527f6b50fa17b77d24e42e27a04b69fe50cd6967cfb767d18de0bd5fe7e1a32aa86860048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906321f8a72190602401602060405180830381865afa158015610353573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610377919061130b565b604051632474521560e21b81527fdb6fbae5cd13d8264d7ed12219ef2882c1e83b8b12f47819baa96f32f69a168260048201523360248201526001600160a01b0391909116906391d1485490604401602060405180830381865afa1580156103e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104079190611328565b61042457604051636b950a2760e01b815260040160405180910390fd5b80610442576040516351fe655d60e11b815260040160405180910390fd5b600080548082526001602081905260408320428082559101849055825491929091819061046e90611360565b90915550604080518481526020810183905283917f2a3da266b34544817d84244346155ad671b49cae5d8277fc1c68befe5538928b910160405180910390a2505050565b6001600160a01b0388166104d957604051632b0ddb9160e01b815260040160405180910390fd5b8460008190036104fc57604051637935375d60e01b815260040160405180910390fd5b80841461051c5760405163b070f43760e01b815260040160405180910390fd5b61052d898989898989878a8a610d31565b886001600160a01b0316336001600160a01b03167f98ccd44fec17fcfcde09b0afc6bfc3e943dc858ff079d4c0fc60847f79f2cc1a8a8a8a8a8a6040516105789594939291906113f4565b60405180910390a3505050505050505050565b6001600160a01b0389166105b257604051632b0ddb9160e01b815260040160405180910390fd5b8660008190036105d557604051637935375d60e01b815260040160405180910390fd5b80821480156105e357508086145b80156105ee57508084145b61060b576040516318e168b160e21b815260040160405180910390fd5b60005b818110156107e457600088888381811061062a5761062a61142d565b905060200281019061063c9190611443565b905090508060000361066157604051637935375d60e01b815260040160405180910390fd5b8686838181106106735761067361142d565b90506020028101906106859190611443565b905081146106a65760405163de7215af60e01b815260040160405180910390fd5b6107358c8c8c858181106106bc576106bc61142d565b905060200201358b8b868181106106d5576106d561142d565b90506020028101906106e79190611443565b8b8b888181106106f9576106f961142d565b905060200281019061070b9190611443565b878c8c8b81811061071e5761071e61142d565b90506020028101906107309190611443565b610d31565b6001600160a01b038c16337f98ccd44fec17fcfcde09b0afc6bfc3e943dc858ff079d4c0fc60847f79f2cc1a8d8d868181106107735761077361142d565b905060200201358c8c8781811061078c5761078c61142d565b905060200281019061079e9190611443565b8c8c898181106107b0576107b061142d565b90506020028101906107c29190611443565b6040516107d39594939291906113f4565b60405180910390a35060010161060e565b5050505050505050505050565b6040516321f8a72160e01b81527f6b50fa17b77d24e42e27a04b69fe50cd6967cfb767d18de0bd5fe7e1a32aa86860048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906321f8a72190602401602060405180830381865afa158015610875573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610899919061130b565b604051632474521560e21b81527fdb6fbae5cd13d8264d7ed12219ef2882c1e83b8b12f47819baa96f32f69a168260048201523360248201526001600160a01b0391909116906391d1485490604401602060405180830381865afa158015610905573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109299190611328565b61094657604051636b950a2760e01b815260040160405180910390fd5b600090815260016020819052604082208281550155565b6040516321f8a72160e01b81527f6b50fa17b77d24e42e27a04b69fe50cd6967cfb767d18de0bd5fe7e1a32aa86860048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906321f8a72190602401602060405180830381865afa1580156109e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a05919061130b565b604051632474521560e21b81527fdb6fbae5cd13d8264d7ed12219ef2882c1e83b8b12f47819baa96f32f69a168260048201523360248201526001600160a01b0391909116906391d1485490604401602060405180830381865afa158015610a71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a959190611328565b610ab257604051636b950a2760e01b815260040160405180910390fd5b6040516321f8a72160e01b81527fbddfa8c39a1f6275bcfb3aa5c70638c466999edbf14e6162d81b3492caca9fce60048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906321f8a72190602401602060405180830381865afa158015610b39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5d919061130b565b9050836000819003610b8257604051637935375d60e01b815260040160405180910390fd5b808314610ba25760405163b070f43760e01b815260040160405180910390fd5b610bb0828787878782610da4565b505050505050565b60008781526001602081905260408220015480610be857604051631ddb8b6b60e21b815260040160405180910390fd5b600089815260016020526040812054610c06906301dfe2009061148d565b905080421115610c295760405163712174ff60e11b815260040160405180910390fd5b60008a81526002602090815260408083206001600160a01b038f16845290915290205460ff1615610c6d5760405163a308b6e360e01b815260040160405180910390fd5b60008b8b8b8b8b8b7f0000000000000000000000000000000000000000000000000000000000000000604051602001610cac97969594939291906114a0565b60408051601f1981840301815282825280516020918201209083015201604051602081830303815290604052805190602001209050610d21868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250879250859150610e149050565b9c9b505050505050505050505050565b610d418989898989898888610bb8565b610d5e5760405163095f258360e01b815260040160405180910390fd5b60008881526002602090815260408083206001600160a01b038d1684529091529020805460ff19166001179055610d99898888888888610da4565b505050505050505050565b60005b81811015610e0b57610e0387858584818110610dc557610dc561142d565b90506020020135888885818110610dde57610dde61142d565b9050602002016020810190610df391906114fa565b6001600160a01b03169190610e2c565b600101610da7565b50505050505050565b600082610e218584610e83565b1490505b9392505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610e7e908490610ec8565b505050565b600081815b8451811015610ebe57610eb482868381518110610ea757610ea761142d565b6020026020010151610f30565b9150600101610e88565b5090505b92915050565b6000610edd6001600160a01b03841683610f5c565b90508051600014158015610f02575080806020019051810190610f009190611328565b155b15610e7e57604051635274afe760e01b81526001600160a01b03841660048201526024015b60405180910390fd5b6000818310610f4c576000828152602084905260409020610e25565b5060009182526020526040902090565b6060610e258383600084600080856001600160a01b03168486604051610f829190611517565b60006040518083038185875af1925050503d8060008114610fbf576040519150601f19603f3d011682016040523d82523d6000602084013e610fc4565b606091505b5091509150610fd4868383610fde565b9695505050505050565b606082610ff357610fee8261103a565b610e25565b815115801561100a57506001600160a01b0384163b155b1561103357604051639996b31560e01b81526001600160a01b0385166004820152602401610f27565b5080610e25565b80511561104a5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b50565b60006020828403121561107857600080fd5b5035919050565b6001600160a01b038116811461106357600080fd5b60008083601f8401126110a657600080fd5b50813567ffffffffffffffff8111156110be57600080fd5b6020830191508360208260051b85010111156110d957600080fd5b9250929050565b60008060008060008060008060a0898b0312156110fc57600080fd5b88356111078161107f565b975060208901359650604089013567ffffffffffffffff8082111561112b57600080fd5b6111378c838d01611094565b909850965060608b013591508082111561115057600080fd5b61115c8c838d01611094565b909650945060808b013591508082111561117557600080fd5b506111828b828c01611094565b999c989b5096995094979396929594505050565b600080600080600080600080600060a08a8c0312156111b457600080fd5b89356111bf8161107f565b985060208a013567ffffffffffffffff808211156111dc57600080fd5b6111e88d838e01611094565b909a50985060408c013591508082111561120157600080fd5b61120d8d838e01611094565b909850965060608c013591508082111561122657600080fd5b6112328d838e01611094565b909650945060808c013591508082111561124b57600080fd5b506112588c828d01611094565b915080935050809150509295985092959850929598565b6000806000806040858703121561128557600080fd5b843567ffffffffffffffff8082111561129d57600080fd5b6112a988838901611094565b909650945060208701359150808211156112c257600080fd5b506112cf87828801611094565b95989497509550505050565b600080604083850312156112ee57600080fd5b8235915060208301356113008161107f565b809150509250929050565b60006020828403121561131d57600080fd5b8151610e258161107f565b60006020828403121561133a57600080fd5b81518015158114610e2557600080fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016113725761137261134a565b5060010190565b8183526000602080850194508260005b858110156113b757813561139c8161107f565b6001600160a01b031687529582019590820190600101611389565b509495945050505050565b81835260006001600160fb1b038311156113db57600080fd5b8260051b80836020870137939093016020019392505050565b85815260606020820152600061140e606083018688611379565b82810360408401526114218185876113c2565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261145a57600080fd5b83018035915067ffffffffffffffff82111561147557600080fd5b6020019150600581901b36038213156110d957600080fd5b80820180821115610ec257610ec261134a565b60018060a01b038816815286602082015260a0604082015260006114c860a083018789611379565b82810360608401526114db8186886113c2565b91505067ffffffffffffffff8316608083015298975050505050505050565b60006020828403121561150c57600080fd5b8135610e258161107f565b6000825160005b81811015611538576020818601810151858301520161151e565b50600092019182525091905056fea2646970667358221220241b9e92ed55f629d54163ec0fea64e8fedbdff5a64305db9bcb257e674f828764736f6c6343000817003300000000000000000000000017a332dc7b40ae701485023b219e9d6f493a2514

Deployed Bytecode

0x6080604052600436106100a75760003560e01c80637426159111610064578063742615911461019257806385e1f4d0146101dd578063988e65951461022a578063a082c86e1461024e578063b6e5ef1814610266578063e08480d01461028657600080fd5b80632462cbfb146100ac57806324c73dda146100c15780632ad750371461011257806347575953146101325780634cf309ae146101525780635092089414610172575b600080fd5b6100bf6100ba366004611066565b6102cf565b005b3480156100cd57600080fd5b506100f57f00000000000000000000000017a332dc7b40ae701485023b219e9d6f493a251481565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561011e57600080fd5b506100bf61012d3660046110e0565b6104b2565b34801561013e57600080fd5b506100bf61014d366004611196565b61058b565b34801561015e57600080fd5b506100bf61016d366004611066565b6107f1565b34801561017e57600080fd5b506100bf61018d36600461126f565b61095d565b34801561019e57600080fd5b506101cd6101ad3660046112db565b600260209081526000928352604080842090915290825290205460ff1681565b6040519015158152602001610109565b3480156101e957600080fd5b506102117f000000000000000000000000000000000000000000000000000000000000000181565b60405167ffffffffffffffff9091168152602001610109565b34801561023657600080fd5b5061024060005481565b604051908152602001610109565b34801561025a57600080fd5b506102406301dfe20081565b34801561027257600080fd5b506101cd6102813660046110e0565b610bb8565b34801561029257600080fd5b506102ba6102a1366004611066565b6001602081905260009182526040909120805491015482565b60408051928352602083019190915201610109565b6040516321f8a72160e01b81527f6b50fa17b77d24e42e27a04b69fe50cd6967cfb767d18de0bd5fe7e1a32aa86860048201527f00000000000000000000000017a332dc7b40ae701485023b219e9d6f493a25146001600160a01b0316906321f8a72190602401602060405180830381865afa158015610353573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610377919061130b565b604051632474521560e21b81527fdb6fbae5cd13d8264d7ed12219ef2882c1e83b8b12f47819baa96f32f69a168260048201523360248201526001600160a01b0391909116906391d1485490604401602060405180830381865afa1580156103e3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104079190611328565b61042457604051636b950a2760e01b815260040160405180910390fd5b80610442576040516351fe655d60e11b815260040160405180910390fd5b600080548082526001602081905260408320428082559101849055825491929091819061046e90611360565b90915550604080518481526020810183905283917f2a3da266b34544817d84244346155ad671b49cae5d8277fc1c68befe5538928b910160405180910390a2505050565b6001600160a01b0388166104d957604051632b0ddb9160e01b815260040160405180910390fd5b8460008190036104fc57604051637935375d60e01b815260040160405180910390fd5b80841461051c5760405163b070f43760e01b815260040160405180910390fd5b61052d898989898989878a8a610d31565b886001600160a01b0316336001600160a01b03167f98ccd44fec17fcfcde09b0afc6bfc3e943dc858ff079d4c0fc60847f79f2cc1a8a8a8a8a8a6040516105789594939291906113f4565b60405180910390a3505050505050505050565b6001600160a01b0389166105b257604051632b0ddb9160e01b815260040160405180910390fd5b8660008190036105d557604051637935375d60e01b815260040160405180910390fd5b80821480156105e357508086145b80156105ee57508084145b61060b576040516318e168b160e21b815260040160405180910390fd5b60005b818110156107e457600088888381811061062a5761062a61142d565b905060200281019061063c9190611443565b905090508060000361066157604051637935375d60e01b815260040160405180910390fd5b8686838181106106735761067361142d565b90506020028101906106859190611443565b905081146106a65760405163de7215af60e01b815260040160405180910390fd5b6107358c8c8c858181106106bc576106bc61142d565b905060200201358b8b868181106106d5576106d561142d565b90506020028101906106e79190611443565b8b8b888181106106f9576106f961142d565b905060200281019061070b9190611443565b878c8c8b81811061071e5761071e61142d565b90506020028101906107309190611443565b610d31565b6001600160a01b038c16337f98ccd44fec17fcfcde09b0afc6bfc3e943dc858ff079d4c0fc60847f79f2cc1a8d8d868181106107735761077361142d565b905060200201358c8c8781811061078c5761078c61142d565b905060200281019061079e9190611443565b8c8c898181106107b0576107b061142d565b90506020028101906107c29190611443565b6040516107d39594939291906113f4565b60405180910390a35060010161060e565b5050505050505050505050565b6040516321f8a72160e01b81527f6b50fa17b77d24e42e27a04b69fe50cd6967cfb767d18de0bd5fe7e1a32aa86860048201527f00000000000000000000000017a332dc7b40ae701485023b219e9d6f493a25146001600160a01b0316906321f8a72190602401602060405180830381865afa158015610875573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610899919061130b565b604051632474521560e21b81527fdb6fbae5cd13d8264d7ed12219ef2882c1e83b8b12f47819baa96f32f69a168260048201523360248201526001600160a01b0391909116906391d1485490604401602060405180830381865afa158015610905573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109299190611328565b61094657604051636b950a2760e01b815260040160405180910390fd5b600090815260016020819052604082208281550155565b6040516321f8a72160e01b81527f6b50fa17b77d24e42e27a04b69fe50cd6967cfb767d18de0bd5fe7e1a32aa86860048201527f00000000000000000000000017a332dc7b40ae701485023b219e9d6f493a25146001600160a01b0316906321f8a72190602401602060405180830381865afa1580156109e1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a05919061130b565b604051632474521560e21b81527fdb6fbae5cd13d8264d7ed12219ef2882c1e83b8b12f47819baa96f32f69a168260048201523360248201526001600160a01b0391909116906391d1485490604401602060405180830381865afa158015610a71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a959190611328565b610ab257604051636b950a2760e01b815260040160405180910390fd5b6040516321f8a72160e01b81527fbddfa8c39a1f6275bcfb3aa5c70638c466999edbf14e6162d81b3492caca9fce60048201526000907f00000000000000000000000017a332dc7b40ae701485023b219e9d6f493a25146001600160a01b0316906321f8a72190602401602060405180830381865afa158015610b39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b5d919061130b565b9050836000819003610b8257604051637935375d60e01b815260040160405180910390fd5b808314610ba25760405163b070f43760e01b815260040160405180910390fd5b610bb0828787878782610da4565b505050505050565b60008781526001602081905260408220015480610be857604051631ddb8b6b60e21b815260040160405180910390fd5b600089815260016020526040812054610c06906301dfe2009061148d565b905080421115610c295760405163712174ff60e11b815260040160405180910390fd5b60008a81526002602090815260408083206001600160a01b038f16845290915290205460ff1615610c6d5760405163a308b6e360e01b815260040160405180910390fd5b60008b8b8b8b8b8b7f0000000000000000000000000000000000000000000000000000000000000001604051602001610cac97969594939291906114a0565b60408051601f1981840301815282825280516020918201209083015201604051602081830303815290604052805190602001209050610d21868680806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250879250859150610e149050565b9c9b505050505050505050505050565b610d418989898989898888610bb8565b610d5e5760405163095f258360e01b815260040160405180910390fd5b60008881526002602090815260408083206001600160a01b038d1684529091529020805460ff19166001179055610d99898888888888610da4565b505050505050505050565b60005b81811015610e0b57610e0387858584818110610dc557610dc561142d565b90506020020135888885818110610dde57610dde61142d565b9050602002016020810190610df391906114fa565b6001600160a01b03169190610e2c565b600101610da7565b50505050505050565b600082610e218584610e83565b1490505b9392505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052610e7e908490610ec8565b505050565b600081815b8451811015610ebe57610eb482868381518110610ea757610ea761142d565b6020026020010151610f30565b9150600101610e88565b5090505b92915050565b6000610edd6001600160a01b03841683610f5c565b90508051600014158015610f02575080806020019051810190610f009190611328565b155b15610e7e57604051635274afe760e01b81526001600160a01b03841660048201526024015b60405180910390fd5b6000818310610f4c576000828152602084905260409020610e25565b5060009182526020526040902090565b6060610e258383600084600080856001600160a01b03168486604051610f829190611517565b60006040518083038185875af1925050503d8060008114610fbf576040519150601f19603f3d011682016040523d82523d6000602084013e610fc4565b606091505b5091509150610fd4868383610fde565b9695505050505050565b606082610ff357610fee8261103a565b610e25565b815115801561100a57506001600160a01b0384163b155b1561103357604051639996b31560e01b81526001600160a01b0385166004820152602401610f27565b5080610e25565b80511561104a5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b50565b60006020828403121561107857600080fd5b5035919050565b6001600160a01b038116811461106357600080fd5b60008083601f8401126110a657600080fd5b50813567ffffffffffffffff8111156110be57600080fd5b6020830191508360208260051b85010111156110d957600080fd5b9250929050565b60008060008060008060008060a0898b0312156110fc57600080fd5b88356111078161107f565b975060208901359650604089013567ffffffffffffffff8082111561112b57600080fd5b6111378c838d01611094565b909850965060608b013591508082111561115057600080fd5b61115c8c838d01611094565b909650945060808b013591508082111561117557600080fd5b506111828b828c01611094565b999c989b5096995094979396929594505050565b600080600080600080600080600060a08a8c0312156111b457600080fd5b89356111bf8161107f565b985060208a013567ffffffffffffffff808211156111dc57600080fd5b6111e88d838e01611094565b909a50985060408c013591508082111561120157600080fd5b61120d8d838e01611094565b909850965060608c013591508082111561122657600080fd5b6112328d838e01611094565b909650945060808c013591508082111561124b57600080fd5b506112588c828d01611094565b915080935050809150509295985092959850929598565b6000806000806040858703121561128557600080fd5b843567ffffffffffffffff8082111561129d57600080fd5b6112a988838901611094565b909650945060208701359150808211156112c257600080fd5b506112cf87828801611094565b95989497509550505050565b600080604083850312156112ee57600080fd5b8235915060208301356113008161107f565b809150509250929050565b60006020828403121561131d57600080fd5b8151610e258161107f565b60006020828403121561133a57600080fd5b81518015158114610e2557600080fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016113725761137261134a565b5060010190565b8183526000602080850194508260005b858110156113b757813561139c8161107f565b6001600160a01b031687529582019590820190600101611389565b509495945050505050565b81835260006001600160fb1b038311156113db57600080fd5b8260051b80836020870137939093016020019392505050565b85815260606020820152600061140e606083018688611379565b82810360408401526114218185876113c2565b98975050505050505050565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261145a57600080fd5b83018035915067ffffffffffffffff82111561147557600080fd5b6020019150600581901b36038213156110d957600080fd5b80820180821115610ec257610ec261134a565b60018060a01b038816815286602082015260a0604082015260006114c860a083018789611379565b82810360608401526114db8186886113c2565b91505067ffffffffffffffff8316608083015298975050505050505050565b60006020828403121561150c57600080fd5b8135610e258161107f565b6000825160005b81811015611538576020818601810151858301520161151e565b50600092019182525091905056fea2646970667358221220241b9e92ed55f629d54163ec0fea64e8fedbdff5a64305db9bcb257e674f828764736f6c63430008170033

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

00000000000000000000000017a332dc7b40ae701485023b219e9d6f493a2514

-----Decoded View---------------
Arg [0] : superRegistry_ (address): 0x17A332dC7B40aE701485023b219E9D6f493a2514

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000017a332dc7b40ae701485023b219e9d6f493a2514


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
Chain Token Portfolio % Price Amount Value
BASE51.43%$2.8931,281.241$90,402.79
BASE14.31%$0.040499620,944.7304$25,147.68
BASE1.31%$3,183.960.7226$2,300.62
BASE0.91%$11,601.1752$1,601.18
BASE0.07%$0.294865393.5878$116.06
BASE0.01%$1.0523.2718$24.34
BASE<0.01%$0.009181129.1099$1.19
BASE<0.01%$0.000001740,000$0.8372
ETH17.11%$2.8910,405.6686$30,072.38
ETH3.53%$0.32164319,315.4384$6,212.68
ETH0.37%$3,792.490.1705$646.47
ETH0.36%$0.1120495,602.4977$627.75
ETH0.07%$71.191.7924$127.6
ETH0.07%$0.744794162.5695$121.08
ETH0.01%$0.0121252,129.8782$25.83
ETH0.01%$125.0842$25.08
ETH<0.01%$0.10278658.5213$6.02
ETH<0.01%$3,182.680.00180919$5.76
ETH<0.01%$13.8973$3.91
ETH<0.01%$1.042.7643$2.88
ETH<0.01%$0.9995761.8614$1.86
ETH<0.01%$0.02470848.6676$1.2
ETH<0.01%$2,754.570.00011406$0.3141
OP6.19%$1.457,529.9166$10,882.86
OP0.81%$3,178.260.4492$1,427.57
OP<0.01%$11.6404$1.64
OP<0.01%$10.1427$0.1427
ARB3.39%$0.6509739,167.0441$5,967.5
ARB0.01%$3,183.860.00696235$22.17
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.