Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0x0aC76EcE9b73311Beed88eDbE5E5D586682Aa53E
Balance 0 ETH
Nonce 907
Code Size 3368 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

3368 bytes
0x6080604052600436101561001257600080fd5b60003560e01c80633875f3dc1461011b57634229ea131461003257600080fd5b3461011657610040366101e9565b610049816102d8565b8051156100ec57805160009160200182f53d15198115166100e05773ffffffffffffffffffffffffffffffffffffffff1680156100b657807faf354defc104ba9267634f156652b1f1cfbd10746c329e2bdd48abd4c9cff9296020809451604051908152a2604051908152f35b7fb06ebf3d0000000000000000000000000000000000000000000000000000000060005260046000fd5b6040513d6000823e3d90fd5b7f4ca249dc0000000000000000000000000000000000000000000000000000000060005260046000fd5b600080fd5b3461011657604073ffffffffffffffffffffffffffffffffffffffff6055600b61014c610147366101e9565b6102d8565b6020815191012084519085820152600060208201523081520160ff81532016803b82519182526020820152f35b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176101ba57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8201126101165760043567ffffffffffffffff811161011657816023820112156101165780600401359167ffffffffffffffff83116101ba578260051b916040519361025b6020850186610179565b84526024602085019382010191821161011657602401915b8183106102805750505090565b823573ffffffffffffffffffffffffffffffffffffffff8116810361011657815260209283019201610273565b9081519160005b8381106102c5575050016000815290565b80602080928401015181850152016102b4565b8051156103d457604051906108c06102f36020820184610179565b80835261043360208401396040519060408201602080840152815180915260206060840192019060005b8181106103a85750505091610379826103636103a59461037396037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610179565b60405194859360208501906102ad565b906102ad565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282610179565b90565b825173ffffffffffffffffffffffffffffffffffffffff1684526020938401939092019160010161031d565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f4e6f20746f6b656e732070726f766964656400000000000000000000000000006044820152fdfe60a0604052346100d7576108c0803803809161001a826100f2565b60a03960208160a00191126100d75760a051906001600160401b0382116100d7578060bf830112156100d75760a0820151906001600160401b0382116100dc578160051b92604051926100706020860185610118565b835260c060208401948201019182116100d75760c001925b8184106100b75761009883610180565b6040516105a99081610317823960805181818161012901526104570152f35b83516001600160a01b03811681036100d757815260209384019301610088565b600080fd5b634e487b7160e01b600052604160045260246000fd5b60a0601f91909101601f19168101906001600160401b038211908210176100dc57604052565b601f909101601f19168101906001600160401b038211908210176100dc57604052565b6001600160401b0381116100dc57601f01601f191660200190565b805182101561016a5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b90815160148102908082046014149015171561022f5761019f8161013b565b906101ad6040519283610118565b8082526101bc601f199161013b565b0136602083013760005b835181101561021e578061020e6101fe6101f26101e560019589610156565b516001600160a01b031690565b6001600160a01b031690565b60601b6001600160601b03191690565b60206014830285010152016101c6565b5061022a919250610270565b608052565b634e487b7160e01b600052601160045260246000fd5b9081519160005b83811061025d575050016000815290565b806020809284010151818501520161024c565b61029c61028e91604051928391600060208401526021830190610245565b03601f198101835282610118565b6040516102c68161028e60208201946a600b5981380380925939f360a81b8652602b830190610245565b51906000f0906001600160a01b038216156102dd57565b60405162461bcd60e51b81526020600482015260116024820152701111541313d65351539517d19052531151607a1b6044820152606490fdfe6080604052600436101561001257600080fd5b60003560e01c80632a5c792a146100475780632f5f3b3c146100425763764f3aa81461003d57600080fd5b610187565b6100de565b346100d95760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100d95761007e610455565b60405180916020820160208352815180915260206040840192019060005b8181106100aa575050500390f35b825173ffffffffffffffffffffffffffffffffffffffff1684528594506020938401939092019160010161009c565b600080fd5b346100d95760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100d957602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b602060408183019282815284518094520192019060005b8181106101715750505090565b8251845260209384019390920191600101610164565b346100d95760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126100d95760043573ffffffffffffffffffffffffffffffffffffffff811681036100d9576101de610455565b80516101f16101ec8261054a565b6103c3565b9160005b82811061021e57505061020d61021a93319183610412565b526040519182918261014d565b0390f35b61026161024861022e8385610412565b5173ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff1690565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff871660048201529190602090839060249082905afa8015610302576001926000916102d4575b506102cd8287610412565b52016101f5565b6102f5915060203d81116102fb575b6102ed8183610365565b810190610558565b386102c2565b503d6102e3565b610567565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176103a657604052565b610336565b67ffffffffffffffff81116103a65760051b60200190565b906103cd826103ab565b6103da6040519182610365565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061040882946103ab565b0190602036910137565b80518210156104265760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f0000000000000000000000000000000000000000000000000000000000000000803b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820190828211610545576001907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603e604051950116840160405282845260208401903c8051601490046104ed816103c3565b9160005b8281106104fe5750505090565b8061053f61051a61024860206014600196028701015160601c90565b6105248388610412565b9073ffffffffffffffffffffffffffffffffffffffff169052565b016104f1565b610307565b906001820180921161054557565b908160209103126100d9575190565b6040513d6000823e3d90fdfea2646970667358221220d9ade8c1f2e60a71c6463dd8fbc1b7ca4ab1f7568d3ff6395caeeb3c07f133c464736f6c634300081a0033a2646970667358221220dd8b086ab8f08ee86ec63d7058ded80c11e6ccfcf24f976fb74c3471da8d5d8564736f6c634300081a0033

Verified Source Code Full Match

Compiler: v0.8.26+commit.8a97fa7a EVM: london Optimization: Yes (999999 runs)
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.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);
}
IERC20Metadata.sol 26 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

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

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

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

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}
Create2.sol 92 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Create2.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.
 * `CREATE2` can be used to compute in advance the address where a smart
 * contract will be deployed, which allows for interesting new mechanisms known
 * as 'counterfactual interactions'.
 *
 * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more
 * information.
 */
library Create2 {
    /**
     * @dev There's no code to deploy.
     */
    error Create2EmptyBytecode();

    /**
     * @dev Deploys a contract using `CREATE2`. The address where the contract
     * will be deployed can be known in advance via {computeAddress}.
     *
     * The bytecode for a contract can be obtained from Solidity with
     * `type(contractName).creationCode`.
     *
     * Requirements:
     *
     * - `bytecode` must not be empty.
     * - `salt` must have not been used for `bytecode` already.
     * - the factory must have a balance of at least `amount`.
     * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.
     */
    function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }
        if (bytecode.length == 0) {
            revert Create2EmptyBytecode();
        }
        assembly ("memory-safe") {
            addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
            // if no address was created, and returndata is not empty, bubble revert
            if and(iszero(addr), not(iszero(returndatasize()))) {
                let p := mload(0x40)
                returndatacopy(p, 0, returndatasize())
                revert(p, returndatasize())
            }
        }
        if (addr == address(0)) {
            revert Errors.FailedDeployment();
        }
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the
     * `bytecodeHash` or `salt` will result in a new destination address.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {
        return computeAddress(salt, bytecodeHash, address(this));
    }

    /**
     * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at
     * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.
     */
    function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {
        assembly ("memory-safe") {
            let ptr := mload(0x40) // Get free memory pointer

            // |                   | ↓ ptr ...  ↓ ptr + 0x0B (start) ...  ↓ ptr + 0x20 ...  ↓ ptr + 0x40 ...   |
            // |-------------------|---------------------------------------------------------------------------|
            // | bytecodeHash      |                                                        CCCCCCCCCCCCC...CC |
            // | salt              |                                      BBBBBBBBBBBBB...BB                   |
            // | deployer          | 000000...0000AAAAAAAAAAAAAAAAAAA...AA                                     |
            // | 0xFF              |            FF                                                             |
            // |-------------------|---------------------------------------------------------------------------|
            // | memory            | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |
            // | keccak(start, 85) |            ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |

            mstore(add(ptr, 0x40), bytecodeHash)
            mstore(add(ptr, 0x20), salt)
            mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes
            let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
            mstore8(start, 0xff)
            addr := and(keccak256(start, 85), 0xffffffffffffffffffffffffffffffffffffffff)
        }
    }
}
Errors.sol 34 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of common custom errors used in multiple contracts
 *
 * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
 * It is recommended to avoid relying on the error API for critical functionality.
 *
 * _Available since v5.1._
 */
library Errors {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error InsufficientBalance(uint256 balance, uint256 needed);

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

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();

    /**
     * @dev A necessary precompile is missing.
     */
    error MissingPrecompile(address);
}
SSTORE2.sol 101 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Read and write to persistent storage at a fraction of the cost.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol)
/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol)
library SSTORE2 {
    uint256 internal constant DATA_OFFSET = 1; // We skip the first byte as it's a STOP opcode to ensure the contract can't be called.

    /*//////////////////////////////////////////////////////////////
                               WRITE LOGIC
    //////////////////////////////////////////////////////////////*/

    function write(bytes memory data) internal returns (address pointer) {
        // Prefix the bytecode with a STOP opcode to ensure it cannot be called.
        bytes memory runtimeCode = abi.encodePacked(hex"00", data);

        bytes memory creationCode = abi.encodePacked(
            //---------------------------------------------------------------------------------------------------------------//
            // Opcode  | Opcode + Arguments  | Description  | Stack View                                                     //
            //---------------------------------------------------------------------------------------------------------------//
            // 0x60    |  0x600B             | PUSH1 11     | codeOffset                                                     //
            // 0x59    |  0x59               | MSIZE        | 0 codeOffset                                                   //
            // 0x81    |  0x81               | DUP2         | codeOffset 0 codeOffset                                        //
            // 0x38    |  0x38               | CODESIZE     | codeSize codeOffset 0 codeOffset                               //
            // 0x03    |  0x03               | SUB          | (codeSize - codeOffset) 0 codeOffset                           //
            // 0x80    |  0x80               | DUP          | (codeSize - codeOffset) (codeSize - codeOffset) 0 codeOffset   //
            // 0x92    |  0x92               | SWAP3        | codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset)   //
            // 0x59    |  0x59               | MSIZE        | 0 codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) //
            // 0x39    |  0x39               | CODECOPY     | 0 (codeSize - codeOffset)                                      //
            // 0xf3    |  0xf3               | RETURN       |                                                                //
            //---------------------------------------------------------------------------------------------------------------//
            hex"60_0B_59_81_38_03_80_92_59_39_F3", // Returns all code in the contract except for the first 11 (0B in hex) bytes.
            runtimeCode // The bytecode we want the contract to have after deployment. Capped at 1 byte less than the code size limit.
        );

        /// @solidity memory-safe-assembly
        assembly {
            // Deploy a new contract with the generated creation code.
            // We start 32 bytes into the code to avoid copying the byte length.
            pointer := create(0, add(creationCode, 32), mload(creationCode))
        }

        require(pointer != address(0), "DEPLOYMENT_FAILED");
    }

    /*//////////////////////////////////////////////////////////////
                               READ LOGIC
    //////////////////////////////////////////////////////////////*/

    function read(address pointer) internal view returns (bytes memory) {
        return readBytecode(pointer, DATA_OFFSET, pointer.code.length - DATA_OFFSET);
    }

    function read(address pointer, uint256 start) internal view returns (bytes memory) {
        start += DATA_OFFSET;

        return readBytecode(pointer, start, pointer.code.length - start);
    }

    function read(
        address pointer,
        uint256 start,
        uint256 end
    ) internal view returns (bytes memory) {
        start += DATA_OFFSET;
        end += DATA_OFFSET;

        require(pointer.code.length >= end, "OUT_OF_BOUNDS");

        return readBytecode(pointer, start, end - start);
    }

    /*//////////////////////////////////////////////////////////////
                          INTERNAL HELPER LOGIC
    //////////////////////////////////////////////////////////////*/

    function readBytecode(
        address pointer,
        uint256 start,
        uint256 size
    ) private view returns (bytes memory data) {
        /// @solidity memory-safe-assembly
        assembly {
            // Get a pointer to some free memory.
            data := mload(0x40)

            // Update the free memory pointer to prevent overriding our data.
            // We use and(x, not(31)) as a cheaper equivalent to sub(x, mod(x, 32)).
            // Adding 31 to size and running the result through the logic above ensures
            // the memory pointer remains word-aligned, following the Solidity convention.
            mstore(0x40, add(data, and(add(add(size, 32), 31), not(31))))

            // Store the size of the data in the first 32 byte chunk of free memory.
            mstore(data, size)

            // Copy the code into memory right after the 32 bytes we used to store the size.
            extcodecopy(pointer, add(data, 32), start, size)
        }
    }
}
PayBalanceReader.sol 90 lines
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.12;

import "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "openzeppelin-contracts/contracts/utils/Create2.sol";
import "solmate/utils/SSTORE2.sol";

/// Factory to deploy PayBalanceReader contracts at deterministic addresses.
contract PayBalanceFactory {
    bytes32 private constant SALT = bytes32(0);

    /// Emitted when a new PayBalanceReader is deployed
    event Deploy(address indexed reader, uint256 nTokens);

    /// Predicts the address where a PayBalanceReader will be deployed.
    function getBalanceReader(
        IERC20[] memory _tokens
    ) public view returns (address addr, uint256 codeSize) {
        bytes memory bytecode = _getCreationBytecode(_tokens);
        addr = Create2.computeAddress(SALT, keccak256(bytecode));
        codeSize = addr.code.length;
    }

    /// Deploys a PayBalanceReader deterministically, using CREATE2.
    function deployBalanceReader(
        IERC20[] memory _tokens
    ) public returns (address) {
        bytes memory bytecode = _getCreationBytecode(_tokens);
        address reader = Create2.deploy(0, SALT, bytecode);
        emit Deploy(reader, _tokens.length);
        return reader;
    }

    function _getCreationBytecode(
        IERC20[] memory _tokens
    ) private pure returns (bytes memory) {
        require(_tokens.length > 0, "No tokens provided");
        bytes memory creationBytecode = type(PayBalanceReader).creationCode;
        return abi.encodePacked(creationBytecode, abi.encode(_tokens));
    }
}

/// Efficiently fetches token balances using SSTORE2 for address storage.
contract PayBalanceReader {
    /// Pointer to SSTORE2 storage containing packed token addresses
    address public immutable pointer;

    constructor(IERC20[] memory _tokens) {
        bytes memory packed = new bytes(_tokens.length * 20);
        for (uint256 i = 0; i < _tokens.length; ++i) {
            bytes20 tokenAddr = bytes20(address(_tokens[i]));
            assembly {
                mstore(add(add(packed, 32), mul(i, 20)), tokenAddr)
            }
        }
        pointer = SSTORE2.write(packed);
    }

    /// Returns list of ERC-20 tokens by reading from SSTORE2 storage
    function getAllTokens() public view returns (IERC20[] memory) {
        bytes memory packed = SSTORE2.read(pointer);
        uint256 n = packed.length / 20;
        IERC20[] memory tokens = new IERC20[](n);
        for (uint256 i = 0; i < n; ++i) {
            bytes20 tokenAddr;
            assembly {
                tokenAddr := mload(add(add(packed, 32), mul(i, 20)))
            }
            tokens[i] = IERC20(address(tokenAddr));
        }
        return tokens;
    }

    /// Get the balances for all saved tokens and the balance of the native
    /// asset (the last array element) for a given owner.
    function getTokenBalances(
        address owner
    ) public view returns (uint256[] memory balances) {
        IERC20[] memory tokens = getAllTokens();
        uint256 n = tokens.length;

        balances = new uint256[](n + 1);
        for (uint256 i = 0; i < n; ++i) {
            balances[i] = tokens[i].balanceOf(owner);
        }

        balances[n] = owner.balance;
    }
}

Read Contract

getBalanceReader 0x3875f3dc → address, uint256

Write Contract 1 functions

These functions modify contract state and require a wallet transaction to execute.

deployBalanceReader 0x4229ea13
address[] _tokens
returns: address

Recent Transactions

No transactions found for this address