ETH Price: $1,959.27 (+1.06%)
Gas: 0.03 Gwei
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Claim230295282025-07-30 4:22:35206 days ago1753849355IN
0x4E48B226...503Eb9687
0 ETH0.000231363.36659911
Claim229521052025-07-19 8:38:35216 days ago1752914315IN
0x4E48B226...503Eb9687
0 ETH0.000080890.94278102
Claim228393592025-07-03 14:41:47232 days ago1751553707IN
0x4E48B226...503Eb9687
0 ETH0.000245912.86560491
Claim226388182025-06-05 13:50:59260 days ago1749131459IN
0x4E48B226...503Eb9687
0 ETH0.000603917.03647791
Claim225848902025-05-29 0:39:35268 days ago1748479175IN
0x4E48B226...503Eb9687
0 ETH0.000250832.92236956
Claim224866132025-05-15 6:04:11281 days ago1747289051IN
0x4E48B226...503Eb9687
0 ETH0.00007951.15724485
Claim223540572025-04-26 15:18:11300 days ago1745680691IN
0x4E48B226...503Eb9687
0 ETH0.000056251.76848603
Claim223540542025-04-26 15:17:35300 days ago1745680655IN
0x4E48B226...503Eb9687
0 ETH0.000049581.55884302
Claim221126152025-03-23 22:36:11334 days ago1742769371IN
0x4E48B226...503Eb9687
0 ETH0.000020090.38923507
Claim220579922025-03-16 7:36:23341 days ago1742110583IN
0x4E48B226...503Eb9687
0 ETH0.000030410.95596837
Claim219394502025-02-27 18:25:11358 days ago1740680711IN
0x4E48B226...503Eb9687
0 ETH0.000036291.14143803
Claim218069542025-02-09 5:45:23376 days ago1739079923IN
0x4E48B226...503Eb9687
0 ETH0.000111751.30229968
Claim214355932024-12-19 9:12:23428 days ago1734599543IN
0x4E48B226...503Eb9687
0 ETH0.0005251210.17851494
Claim214010062024-12-14 13:18:59433 days ago1734182339IN
0x4E48B226...503Eb9687
0 ETH0.0007056910.26856266
Claim213504292024-12-07 11:50:59440 days ago1733572259IN
0x4E48B226...503Eb9687
0 ETH0.0010471612.20551666
Claim213499902024-12-07 10:22:11440 days ago1733566931IN
0x4E48B226...503Eb9687
0 ETH0.0009969711.61954218
Claim212346642024-11-21 7:38:11456 days ago1732174691IN
0x4E48B226...503Eb9687
0 ETH0.000708510.42147157
Transfer Ownersh...209374042024-10-10 19:48:23498 days ago1728589703IN
0x4E48B226...503Eb9687
0 ETH0.0004844810.16759091

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
TrsyFeeDistributor

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 200 runs

Other Settings:
cancun EvmVersion
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.20;

/// Utils /////
import {ERC20, SafeTransferLib} from "solmate/utils/SafeTransferLib.sol";
import {MerkleProof} from "openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol";
import {Ownable} from "src/utils/Ownable.sol";

/// @title FeeDistributor
/// @notice This contract takes fees generated by the FYDE protocol denominated in TRSY, and
///         distributes them to veFYDE holders.
///         This contract was based on the UniversalRewardsDistributor by MerlinEgalite:
///         https://github.com/MerlinEgalite/universal-rewards-distributor
contract TrsyFeeDistributor is Ownable {
  using SafeTransferLib for ERC20;

  /*////////////////////////////////////////////////////////////// 
                            Storage
    //////////////////////////////////////////////////////////////*/

  /// @notice TRSY token
  address public immutable TRSY;

  /// @notice The merkle tree's root of the current rewards distribution.
  bytes32 public root;

  /// @notice The `amount` TRSY already claimed by `account`.
  mapping(address account => uint256 amount) public claimed;

  /// @notice The total amount of fees deposited into the contract
  uint256 public cumulativeFees;

  /*////////////////////////////////////////////////////////////// 
                            EVENTS
    //////////////////////////////////////////////////////////////*/

  /// @notice Emitted when the merkle tree's root is updated.
  /// @param newRoot The new merkle tree's root.
  event RootUpdated(bytes32 newRoot);

  /// @notice Emitted when rewards are claimed.
  /// @param account The address for which rewards are claimed rewards for.
  /// @param amount The amount of reward token claimed.
  event RewardsClaimed(address account, uint256 amount);

  /*////////////////////////////////////////////////////////////// 
                            ERRORS
    //////////////////////////////////////////////////////////////*/

  /// @notice Thrown when the merkle proof is invalid or expired.
  error ProofInvalidOrExpired();

  /// @notice Thrown when the rewards have already been claimed.
  error AlreadyClaimed();

  /*//////////////////////////////////////////////////////////////
                            CONSTRUCTOR 
    //////////////////////////////////////////////////////////////*/

  constructor(address _TRSY) Ownable(msg.sender) {
    TRSY = _TRSY;
  }

  /*////////////////////////////////////////////////////////////// 
                            OWNER
    //////////////////////////////////////////////////////////////*/

  /// @notice Updates the current merkle tree's root.
  /// @param newRoot The new merkle tree's root.
  function updateRoot(bytes32 newRoot) external onlyOwner {
    root = newRoot;
    emit RootUpdated(newRoot);
  }

  ///@notice Recover asset from the contract in case of emergency
  function recoverAsset(address asset, address to, uint256 amount) external onlyOwner {
    ERC20(asset).safeTransfer(to, amount);
  }

  ///@notice deposit fees into the contract
  function deposit(address from, uint256 amount) external onlyOwner {
    ERC20(TRSY).safeTransferFrom(from, address(this), amount);
    cumulativeFees += amount;
  }

  /*////////////////////////////////////////////////////////////// 
                            USER
    //////////////////////////////////////////////////////////////*/

  /// @notice Claims rewards.
  /// @param account The address to claim rewards for.
  /// @param claimable The overall claimable amount of token rewards.
  /// @param proof The merkle proof that validates this claim.
  ///@dev Claimable is a cummulative number from the epochs, so in the backend we should compute
  /// claimable - claimed to see if there are reward that can be claimed
  function claim(address account, uint256 claimable, bytes32[] calldata proof) external {
    if (
      !MerkleProof.verifyCalldata(
        proof, root, keccak256(bytes.concat(keccak256(abi.encode(account, claimable))))
      )
    ) revert ProofInvalidOrExpired();

    uint256 amount = claimable - claimed[account];
    if (amount == 0) revert AlreadyClaimed();

    claimed[account] = claimable;

    ERC20(TRSY).safeTransfer(account, amount);
    emit RewardsClaimed(account, amount);
  }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
    /*//////////////////////////////////////////////////////////////
                             ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Transfer the ETH and store if it succeeded or not.
            success := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(success, "ETH_TRANSFER_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                            ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
            )
        }

        require(success, "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool success;

        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata into memory, beginning with the function selector.
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.

            success := and(
                // Set success to whether the call reverted, if not we check it either
                // returned exactly 1 (can't just be non-zero data), or had no return data.
                or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
                // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
                // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
                // Counterintuitively, this call must be positioned second to the or() call in the
                // surrounding and() call or else returndatasize() will be zero during the computation.
                call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
            )
        }

        require(success, "APPROVE_FAILED");
    }
}

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

pragma solidity ^0.8.20;

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

/**
 * @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 = Hashes.commutativeKeccak256(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 = Hashes.commutativeKeccak256(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] = Hashes.commutativeKeccak256(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] = Hashes.commutativeKeccak256(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];
        }
    }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

///@title Ownable contract
/// @notice Simple 2step owner authorization combining solmate and OZ implementation
abstract contract Ownable {
  /*//////////////////////////////////////////////////////////////
                             STORAGE
    //////////////////////////////////////////////////////////////*/

  ///@notice Address of the owner
  address public owner;

  ///@notice Address of the pending owner
  address public pendingOwner;

  /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

  event OwnershipTransferred(address indexed user, address indexed newOner);
  event OwnershipTransferStarted(address indexed user, address indexed newOwner);
  event OwnershipTransferCanceled(address indexed pendingOwner);

  /*//////////////////////////////////////////////////////////////
                                 ERROR
    //////////////////////////////////////////////////////////////*/

  error Unauthorized();

  /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

  constructor(address _owner) {
    owner = _owner;

    emit OwnershipTransferred(address(0), _owner);
  }

  /*//////////////////////////////////////////////////////////////
                             OWNERSHIP LOGIC
    //////////////////////////////////////////////////////////////*/

  ///@notice Transfer ownership to a new address
  ///@param newOwner address of the new owner
  ///@dev newOwner have to acceptOwnership
  function transferOwnership(address newOwner) external onlyOwner {
    pendingOwner = newOwner;
    emit OwnershipTransferStarted(msg.sender, pendingOwner);
  }

  ///@notice NewOwner accept the ownership, it transfer the ownership to newOwner
  function acceptOwnership() external {
    if (msg.sender != pendingOwner) revert Unauthorized();
    address oldOwner = owner;
    owner = pendingOwner;
    delete pendingOwner;
    emit OwnershipTransferred(oldOwner, owner);
  }

  ///@notice Cancel the ownership transfer
  function cancelTransferOwnership() external onlyOwner {
    emit OwnershipTransferCanceled(pendingOwner);
    delete pendingOwner;
  }

  modifier onlyOwner() {
    if (msg.sender != owner) revert Unauthorized();
    _;
  }
}

// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*//////////////////////////////////////////////////////////////
                            METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*//////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*//////////////////////////////////////////////////////////////
                               ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Library of standard hash functions.
 */
library Hashes {
    /**
     * @dev Commutative Keccak256 hash of a sorted pair of bytes32. Frequently used when working with merkle proofs.
     *
     * NOTE: Equivalent to the `standardNodeHash` in our https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
     */
    function commutativeKeccak256(bytes32 a, bytes32 b) internal pure returns (bytes32) {
        return a < b ? _efficientKeccak256(a, b) : _efficientKeccak256(b, a);
    }

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

Settings
{
  "remappings": [
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/solmate/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
    "murky/=lib/murky/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
    "solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/",
    "solmate/=lib/solmate/src/",
    "surl/=lib/surl/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_TRSY","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyClaimed","type":"error"},{"inputs":[],"name":"ProofInvalidOrExpired","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipTransferCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"newRoot","type":"bytes32"}],"name":"RootUpdated","type":"event"},{"inputs":[],"name":"TRSY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelTransferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"claimable","type":"uint256"},{"internalType":"bytes32[]","name":"proof","type":"bytes32[]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"claimed","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cumulativeFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"root","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"newRoot","type":"bytes32"}],"name":"updateRoot","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a0604052348015600e575f80fd5b506040516109ed3803806109ed833981016040819052602b91607b565b5f80546001600160a01b031916339081178255604051909182917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3506001600160a01b031660805260a6565b5f60208284031215608a575f80fd5b81516001600160a01b0381168114609f575f80fd5b9392505050565b6080516109216100cc5f395f818161010f01528181610370015261041601526109215ff3fe608060405234801561000f575f80fd5b50600436106100cb575f3560e01c8063829c670311610088578063c884ef8311610063578063c884ef831461019a578063e30c3978146101b9578063ebf0c717146101cc578063f2fde38b146101d5575f80fd5b8063829c6703146101695780638da5cb5b1461018057806392fede0014610192575f80fd5b806321ff9970146100cf57806329d3cb35146100e45780633d13f874146100f757806345e166bd1461010a57806347e7ef241461014e57806379ba509714610161575b5f80fd5b6100e26100dd36600461076a565b6101e8565b005b6100e26100f236600461079c565b61024c565b6100e26101053660046107d6565b61028e565b6101317f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6100e261015c36600461085c565b6103e0565b6100e2610458565b61017260045481565b604051908152602001610145565b5f54610131906001600160a01b031681565b6100e26104db565b6101726101a8366004610884565b60036020525f908152604090205481565b600154610131906001600160a01b031681565b61017260025481565b6100e26101e3366004610884565b61054d565b5f546001600160a01b03163314610211576040516282b42960e81b815260040160405180910390fd5b60028190556040518181527f2cbc14f49c068133583f7cb530018af451c87c1cf1327cf2a4ff4698c4730aa49060200160405180910390a150565b5f546001600160a01b03163314610275576040516282b42960e81b815260040160405180910390fd5b6102896001600160a01b03841683836105c1565b505050565b600254604080516001600160a01b03871660208201529081018590526102ee91849184919060600160408051601f198184030181528282528051602091820120908301520160405160208183030381529060405280519060200120610649565b61030b5760405163f542095760e01b815260040160405180910390fd5b6001600160a01b0384165f9081526003602052604081205461032d90856108b1565b9050805f0361034f57604051630c8d9eab60e31b815260040160405180910390fd5b6001600160a01b038086165f908152600360205260409020859055610397907f00000000000000000000000000000000000000000000000000000000000000001686836105c1565b604080516001600160a01b0387168152602081018390527ffc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe910160405180910390a15050505050565b5f546001600160a01b03163314610409576040516282b42960e81b815260040160405180910390fd5b61043e6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016833084610660565b8060045f82825461044f91906108c4565b90915550505050565b6001546001600160a01b03163314610482576040516282b42960e81b815260040160405180910390fd5b5f8054600180546001600160a01b038082166001600160a01b031980861682178755909216909255604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b5f546001600160a01b03163314610504576040516282b42960e81b815260040160405180910390fd5b6001546040516001600160a01b03909116907f6ecd4842251bedd053b09547c0fabaab9ec98506ebf24469e8dd5560412ed37f905f90a2600180546001600160a01b0319169055565b5f546001600160a01b03163314610576576040516282b42960e81b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700905f90a350565b5f60405163a9059cbb60e01b81526001600160a01b038416600482015282602482015260205f6044835f895af13d15601f3d1160015f5114161716915050806106435760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064015b60405180910390fd5b50505050565b5f826106568686856106f8565b1495945050505050565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af13d15601f3d1160015f5114161716915050806106f15760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b604482015260640161063a565b5050505050565b5f81815b84811015610730576107268287878481811061071a5761071a6108d7565b90506020020135610739565b91506001016106fc565b50949350505050565b5f818310610753575f828152602084905260409020610761565b5f8381526020839052604090205b90505b92915050565b5f6020828403121561077a575f80fd5b5035919050565b80356001600160a01b0381168114610797575f80fd5b919050565b5f805f606084860312156107ae575f80fd5b6107b784610781565b92506107c560208501610781565b929592945050506040919091013590565b5f805f80606085870312156107e9575f80fd5b6107f285610781565b935060208501359250604085013567ffffffffffffffff811115610814575f80fd5b8501601f81018713610824575f80fd5b803567ffffffffffffffff81111561083a575f80fd5b8760208260051b840101111561084e575f80fd5b949793965060200194505050565b5f806040838503121561086d575f80fd5b61087683610781565b946020939093013593505050565b5f60208284031215610894575f80fd5b61076182610781565b634e487b7160e01b5f52601160045260245ffd5b818103818111156107645761076461089d565b808201808211156107645761076461089d565b634e487b7160e01b5f52603260045260245ffdfea26469706673582212207f58871c777e5f1124e664c0472855e2c159b19ae12dc3a5fc8c85a22694528964736f6c634300081a003300000000000000000000000087cc45fff5c0933bb6af6bae7fc013b7ec7df2ee

Deployed Bytecode

0x608060405234801561000f575f80fd5b50600436106100cb575f3560e01c8063829c670311610088578063c884ef8311610063578063c884ef831461019a578063e30c3978146101b9578063ebf0c717146101cc578063f2fde38b146101d5575f80fd5b8063829c6703146101695780638da5cb5b1461018057806392fede0014610192575f80fd5b806321ff9970146100cf57806329d3cb35146100e45780633d13f874146100f757806345e166bd1461010a57806347e7ef241461014e57806379ba509714610161575b5f80fd5b6100e26100dd36600461076a565b6101e8565b005b6100e26100f236600461079c565b61024c565b6100e26101053660046107d6565b61028e565b6101317f00000000000000000000000087cc45fff5c0933bb6af6bae7fc013b7ec7df2ee81565b6040516001600160a01b0390911681526020015b60405180910390f35b6100e261015c36600461085c565b6103e0565b6100e2610458565b61017260045481565b604051908152602001610145565b5f54610131906001600160a01b031681565b6100e26104db565b6101726101a8366004610884565b60036020525f908152604090205481565b600154610131906001600160a01b031681565b61017260025481565b6100e26101e3366004610884565b61054d565b5f546001600160a01b03163314610211576040516282b42960e81b815260040160405180910390fd5b60028190556040518181527f2cbc14f49c068133583f7cb530018af451c87c1cf1327cf2a4ff4698c4730aa49060200160405180910390a150565b5f546001600160a01b03163314610275576040516282b42960e81b815260040160405180910390fd5b6102896001600160a01b03841683836105c1565b505050565b600254604080516001600160a01b03871660208201529081018590526102ee91849184919060600160408051601f198184030181528282528051602091820120908301520160405160208183030381529060405280519060200120610649565b61030b5760405163f542095760e01b815260040160405180910390fd5b6001600160a01b0384165f9081526003602052604081205461032d90856108b1565b9050805f0361034f57604051630c8d9eab60e31b815260040160405180910390fd5b6001600160a01b038086165f908152600360205260409020859055610397907f00000000000000000000000087cc45fff5c0933bb6af6bae7fc013b7ec7df2ee1686836105c1565b604080516001600160a01b0387168152602081018390527ffc30cddea38e2bf4d6ea7d3f9ed3b6ad7f176419f4963bd81318067a4aee73fe910160405180910390a15050505050565b5f546001600160a01b03163314610409576040516282b42960e81b815260040160405180910390fd5b61043e6001600160a01b037f00000000000000000000000087cc45fff5c0933bb6af6bae7fc013b7ec7df2ee16833084610660565b8060045f82825461044f91906108c4565b90915550505050565b6001546001600160a01b03163314610482576040516282b42960e81b815260040160405180910390fd5b5f8054600180546001600160a01b038082166001600160a01b031980861682178755909216909255604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a350565b5f546001600160a01b03163314610504576040516282b42960e81b815260040160405180910390fd5b6001546040516001600160a01b03909116907f6ecd4842251bedd053b09547c0fabaab9ec98506ebf24469e8dd5560412ed37f905f90a2600180546001600160a01b0319169055565b5f546001600160a01b03163314610576576040516282b42960e81b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b03831690811790915560405133907f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700905f90a350565b5f60405163a9059cbb60e01b81526001600160a01b038416600482015282602482015260205f6044835f895af13d15601f3d1160015f5114161716915050806106435760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064015b60405180910390fd5b50505050565b5f826106568686856106f8565b1495945050505050565b5f6040516323b872dd60e01b81526001600160a01b03851660048201526001600160a01b038416602482015282604482015260205f6064835f8a5af13d15601f3d1160015f5114161716915050806106f15760405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b604482015260640161063a565b5050505050565b5f81815b84811015610730576107268287878481811061071a5761071a6108d7565b90506020020135610739565b91506001016106fc565b50949350505050565b5f818310610753575f828152602084905260409020610761565b5f8381526020839052604090205b90505b92915050565b5f6020828403121561077a575f80fd5b5035919050565b80356001600160a01b0381168114610797575f80fd5b919050565b5f805f606084860312156107ae575f80fd5b6107b784610781565b92506107c560208501610781565b929592945050506040919091013590565b5f805f80606085870312156107e9575f80fd5b6107f285610781565b935060208501359250604085013567ffffffffffffffff811115610814575f80fd5b8501601f81018713610824575f80fd5b803567ffffffffffffffff81111561083a575f80fd5b8760208260051b840101111561084e575f80fd5b949793965060200194505050565b5f806040838503121561086d575f80fd5b61087683610781565b946020939093013593505050565b5f60208284031215610894575f80fd5b61076182610781565b634e487b7160e01b5f52601160045260245ffd5b818103818111156107645761076461089d565b808201808211156107645761076461089d565b634e487b7160e01b5f52603260045260245ffdfea26469706673582212207f58871c777e5f1124e664c0472855e2c159b19ae12dc3a5fc8c85a22694528964736f6c634300081a0033

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

00000000000000000000000087cc45fff5c0933bb6af6bae7fc013b7ec7df2ee

-----Decoded View---------------
Arg [0] : _TRSY (address): 0x87Cc45fFF5c0933bb6aF6bAe7Fc013b7eC7df2Ee

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000087cc45fff5c0933bb6af6bae7fc013b7ec7df2ee


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.