Address Contract Verified
Address
0x0aC76EcE9b73311Beed88eDbE5E5D586682Aa53E
Balance
0 ETH
Nonce
907
Code Size
3368 bytes
Creator
Create2 Deployer at tx 0x62e9c0d2...79b04a
Indexed Transactions
0
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