Address Contract Verified
Address
0xD2e28229F6f2c235e57De2EbC727025A1D0530FB
Balance
0 ETH
Nonce
1
Code Size
6905 bytes
Creator
Create2 Deployer at tx 0x420a37d7...10c38a
Indexed Transactions
0 (1 on-chain, 1.6% indexed)
Contract Bytecode
6905 bytes
0x60806040526004361015610010575b005b5f3560e01c806223de291461011e57806301ffc9a714610119578063150b7a02146101145780631626ba7e1461010f57806319822f7c1461010a5780631d92e4b61461010557806326da7d881461010057806334fcd5be146100fb57806376276c82146100f65780638626e88b146100f15780639cfd7cff146100ec578063a4c0ed36146100e7578063b0d691fe146100e2578063b61d27f6146100dd578063bc197c81146100d8578063cf21ecab146100d35763f23a6e610361000e57611049565b610fdb565b610f05565b610ee2565b610e9a565b610e7d565b610dcb565b610cef565b610c1a565b610b7f565b610a4f565b610831565b61064b565b6103f5565b610364565b610205565b610173565b73ffffffffffffffffffffffffffffffffffffffff81160361014157565b5f80fd5b9181601f840112156101415782359167ffffffffffffffff8311610141576020838186019501011161014157565b346101415760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610141576101ad600435610123565b6101b8602435610123565b6101c3604435610123565b60843567ffffffffffffffff8111610141576101e3903690600401610145565b505060a43567ffffffffffffffff81116101415761000e903690600401610145565b346101415760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610141576004357fffffffff00000000000000000000000000000000000000000000000000000000811680910361014157807f4e2312e0000000000000000000000000000000000000000000000000000000006102b8921490811561033a575b8115610310575b81156102e6575b81156102bc575b5060405190151581529081906020820190565b0390f35b7f1626ba7e000000000000000000000000000000000000000000000000000000009150145f6102a5565b7f1adb9474000000000000000000000000000000000000000000000000000000008114915061029e565b7f01ffc9a70000000000000000000000000000000000000000000000000000000081149150610297565b7f150b7a020000000000000000000000000000000000000000000000000000000081149150610290565b346101415760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101415761039e600435610123565b6103a9602435610123565b60643567ffffffffffffffff8111610141576103c9903690600401610145565b505060206040517f150b7a02000000000000000000000000000000000000000000000000000000008152f35b346101415760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101415760243560043567ffffffffffffffff82116101415761044a6105c5923690600401610145565b9160405160208101917f31322a37c2a66b24e1088197e5b24fcc050625c13d4b84c3eaa6a8be5270321d835260408201526040815261048a606082611107565b5190206105916105bd60405160208101907fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647282527f906754a21e6afe7233c7ccce2787110e84157e1cbaa80e58656dff779193a5cd60408201527f15124d26d1272f8d4d5266a24ca397811f414b8cd05a53b26b745f63af5ae2fc60608201524660808201523060a08201527f000000000000000000000000d2e28229f6f2c235e57de2ebc727025a1d0530fb60c082015260c0815261054b60e082611107565b5190209260405192839160208301958690916042927f19010000000000000000000000000000000000000000000000000000000000008352600283015260228201520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611107565b519020611827565b15610622576102b87f1626ba7e000000000000000000000000000000000000000000000000000000005b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681529081906020820190565b6102b87fffffffff000000000000000000000000000000000000000000000000000000006105ef565b346101415760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101415760043567ffffffffffffffff8111610141576101207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc823603011261014157602435906044356f71727de22e5e9d8baf0edac6f37da03233036107d8576040517f7e97025600000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006067203e59e681396335940c4f2caf6b002815bc165afa9081156107d3575f91610798575b5015610770576102b8926107609260040161121d565b6040519081529081906020820190565b7fd13d7835000000000000000000000000000000000000000000000000000000005f5260045ffd5b90506020813d6020116107cb575b816107b360209383611107565b8101031261014157518015158103610141575f61074a565b3d91506107a6565b61114d565b7fbd07c551000000000000000000000000000000000000000000000000000000005f5260045ffd5b9181601f840112156101415782359167ffffffffffffffff8311610141576020808501948460051b01011161014157565b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101415760043567ffffffffffffffff81116101415761087b903690600401610800565b9060243567ffffffffffffffff81116101415761089c903690600401610145565b90604051917f627cdcb90000000000000000000000000000000000000000000000000000000083526020836004815f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006067203e59e681396335940c4f2caf6b002815bc165af19182156107d35761093d61094293610946955f916109d3575b506040516109358161059160208201948c8c876114ae565b519020611721565b611827565b1590565b6109ab575f5b82811061095557005b806109a561096e61096960019487876115e7565b611654565b602061097b8488886115e7565b013561099f61099861098e868a8a6115e7565b6040810190611158565b369161169b565b916118ad565b0161094c565b7f8baa579f000000000000000000000000000000000000000000000000000000005f5260045ffd5b6109f5915060203d6020116109fb575b6109ed8183611107565b810190611461565b5f61091d565b503d6109e3565b60207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc820112610141576004359067ffffffffffffffff821161014157610a4b91600401610800565b9091565b610a5836610a02565b6f71727de22e5e9d8baf0edac6f37da03233036107d8575f917fa77908bfab24e6768503125e99551a4fa5c3c75f3106fee5dea5ac0cebc017a45c9182159182610b23575b90610aa7916116d1565b15610ad9575b50610ab457005b5f7fa77908bfab24e6768503125e99551a4fa5c3c75f3106fee5dea5ac0cebc017a455005b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff017fa77908bfab24e6768503125e99551a4fa5c3c75f3106fee5dea5ac0cebc017a45d5f610aad565b9350611a857fa77908bfab24e6768503125e99551a4fa5c3c75f3106fee5dea5ac0cebc017a45403610b5757600193610a9d565b7f33d7b3d6000000000000000000000000000000000000000000000000000000005f5260045ffd5b610b8836610a02565b303303610b985761000e916116d1565b7f14d4a4e8000000000000000000000000000000000000000000000000000000005f5260045ffd5b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261014157600435610bf681610123565b91602435916044359067ffffffffffffffff821161014157610a4b91600401610145565b610c2336610bc0565b9091926f71727de22e5e9d8baf0edac6f37da03233036107d8575f937fa77908bfab24e6768503125e99551a4fa5c3c75f3106fee5dea5ac0cebc017a45c9384159384610c7c575b610aa793929161099f91369161169b565b95509190611a857fa77908bfab24e6768503125e99551a4fa5c3c75f3106fee5dea5ac0cebc017a45403610b575760019591929091610c6b565b60206040818301928281528451809452019201905f5b818110610cd95750505090565b8251845260209384019390920191600101610ccc565b34610141575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610141576040518060207fc473de86d0138e06e4d4918a106463a7cc005258d2e21915272bcb4594c18900549182815201907fc473de86d0138e06e4d4918a106463a7cc005258d2e21915272bcb4594c189005f527fdb3901c0862740f848a4aebebd6b3d645e6b3bc6adf2cf46e83a846b3a343933905f5b818110610db5576102b885610da981870382611107565b60405191829182610cb6565b8254845260209093019260019283019201610d92565b34610141575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610141576040805190610e088183611107565b6016825260208201917f547275737457616c6c65742e42697a2e76312e302e300000000000000000000083527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8351948593602085525180918160208701528686015e5f85828601015201168101030190f35b3461014157610e8b36610bc0565b50505050602060405160018152f35b34610141575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101415760206040516f71727de22e5e9d8baf0edac6f37da0328152f35b610eeb36610bc0565b92919092303303610b985761000e9361099f91369161169b565b346101415760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014157610f3f600435610123565b610f4a602435610123565b60443567ffffffffffffffff811161014157610f6a903690600401610800565b505060643567ffffffffffffffff811161014157610f8c903690600401610800565b505060843567ffffffffffffffff811161014157610fae903690600401610145565b50506040517fbc197c81000000000000000000000000000000000000000000000000000000008152602090f35b34610141575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014157602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000006067203e59e681396335940c4f2caf6b002815bc168152f35b346101415760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014157611083600435610123565b61108e602435610123565b60843567ffffffffffffffff8111610141576110ae903690600401610145565b505060206040517ff23a6e61000000000000000000000000000000000000000000000000000000008152f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761114857604052565b6110da565b6040513d5f823e3d90fd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610141570180359067ffffffffffffffff82116101415760200191813603831361014157565b906004116101415790600490565b919091357fffffffff00000000000000000000000000000000000000000000000000000000811692600481106111eb575050565b7fffffffff00000000000000000000000000000000000000000000000000000000929350829060040360031b1b161690565b9061133c9093929360405160208101917f4f51e7a567f083a31264743067875fc6a7ae45c32c5bd71f6a998c4625b138678352604082015260408152611264606082611107565b51902061059161132560405160208101907fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647282527f906754a21e6afe7233c7ccce2787110e84157e1cbaa80e58656dff779193a5cd60408201527f15124d26d1272f8d4d5266a24ca397811f414b8cd05a53b26b745f63af5ae2fc60608201524660808201523060a08201527f000000000000000000000000d2e28229f6f2c235e57de2ebc727025a1d0530fb60c082015260c0815261054b60e082611107565b519020611336610100840184611158565b91611827565b90606081017f76276c82000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000061139f6113996113938587611158565b906111a9565b906111b7565b1614159182611403575b50506113db57156113d2576113bc611864565b815f925b6113c75750565b5f80808093335af150565b816001926113c0565b7f568becaf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f26da7d880000000000000000000000000000000000000000000000000000000092506113996113937fffffffff000000000000000000000000000000000000000000000000000000009361145793611158565b1614155f806113a9565b90816020910312610141575190565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b93929180604086016040875252606085019060608160051b87010191835f907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1813603015b84831061150857505050505060209150930152565b90919293947fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa08a820301855286358281121561014157830173ffffffffffffffffffffffffffffffffffffffff813561156081610123565b1682526020810135602083015260408101357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18236030181121561014157016020813591019067ffffffffffffffff8111610141578036038213610141576115d8602092839260608681604060019901520191611470565b980197969501930191906114f3565b91908110156116275760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa181360301821215610141570190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b3561165e81610123565b90565b67ffffffffffffffff811161114857601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b9291926116a782611661565b916116b56040519384611107565b829481845281830111610141578281602093845f960137010152565b905f5b8181106116e057505050565b8061171b6116f160019385876115e7565b356116fb81610123565b60206117088487896115e7565b013561099f61099861098e86898b6115e7565b016116d4565b60405160208101917fec429430bbd6d0e373848272230d6fe2bac6319d903762e089c5cae97af53df08352604082015260408152611760606082611107565b51902061059161182160405160208101907fd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac5647282527f906754a21e6afe7233c7ccce2787110e84157e1cbaa80e58656dff779193a5cd60408201527f15124d26d1272f8d4d5266a24ca397811f414b8cd05a53b26b745f63af5ae2fc60608201524660808201523060a08201527f000000000000000000000000d2e28229f6f2c235e57de2ebc727025a1d0530fb60c082015260c0815261054b60e082611107565b51902090565b6118559061184f61185e9373ffffffffffffffffffffffffffffffffffffffff95369161169b565b906118fc565b9092919261196d565b16301490565b60017fa77908bfab24e6768503125e99551a4fa5c3c75f3106fee5dea5ac0cebc017a45c017fa77908bfab24e6768503125e99551a4fa5c3c75f3106fee5dea5ac0cebc017a45d565b915f928392602083519301915af13d156118f4573d906118cc82611661565b916118da6040519384611107565b82523d5f602084013e5b156118ec5750565b602081519101fd5b6060906118e4565b815191906041830361192c576119259250602082015190606060408401519301515f1a90611a34565b9192909190565b50505f9160029190565b6004111561194057565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b61197681611936565b8061197f575050565b61198881611936565b600181036119b8577ff645eedf000000000000000000000000000000000000000000000000000000005f5260045ffd5b6119c181611936565b600281036119f557507ffce698f7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b80611a01600392611936565b14611a095750565b7fd78bce0c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411611ab8579160209360809260ff5f9560405194855216868401526040830152606082015282805260015afa156107d3575f5173ffffffffffffffffffffffffffffffffffffffff811615611aae57905f905f90565b505f906001905f90565b5050505f916003919056fea2646970667358221220c2db6d5abc3511f1c5db8e181b811a52e48e4f0b1fdfee2a9ecbcff3bfb11f5764736f6c634300081c0033
Verified Source Code Full Match
Compiler: v0.8.28+commit.7893614a
EVM: cancun
Optimization: Yes (999999 runs)
Ownable.sol 100 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Ownable2Step.sol 67 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.20;
import {Ownable} from "./Ownable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* This extension of the {Ownable} contract includes a two-step mechanism to transfer
* ownership, where the new owner must call {acceptOwnership} in order to replace the
* old one. This can help prevent common mistakes, such as transfers of ownership to
* incorrect accounts, or to contracts that are unable to interact with the
* permission system.
*
* The initial owner is specified at deployment time in the constructor for `Ownable`. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*
* Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}
ECDSA.sol 180 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(
bytes32 hash,
bytes memory signature
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly ("memory-safe") {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}
Biz.sol 355 lines
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.28;
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {BizGuard} from "./BizGuard.sol";
import {BizHandler} from "./BizHandler.sol";
/**
* @title Biz - A secure smart wallet for delegated EOAs using EIP-7702.
* @dev Most important concepts:
* - Biz is a stateless account implementation. Only relies on BizGuard for 4337 Flag & Nonce.
* - Biz allows 3 distinct validation & execution flows.
* - ERC-4337.
* - Self-Call.
* - Signature based. msg.sender Agnostic.
* - ERC-4337 support is optional and it is controlled by BizGuard for extra layer of security.
* - Biz supports ERC-7779.
* @author David Kim - @PowerStream3604
*/
contract Biz is BizHandler {
/// @dev The packed ERC4337 user operation (userOp) struct.
struct PackedUserOperation {
address sender;
uint256 nonce;
bytes initCode; // Factory address and `factoryData` (or empty).
bytes callData;
bytes32 accountGasLimits; // `verificationGas` (16 bytes) and `callGas` (16 bytes).
uint256 preVerificationGas;
bytes32 gasFees; // `maxPriorityFee` (16 bytes) and `maxFeePerGas` (16 bytes).
bytes paymasterAndData; // Paymaster fields (or empty).
bytes signature;
}
/// @dev Call struct for the `executeBatch` function.
struct Call {
address target;
uint256 value;
bytes data;
}
error OnlyEntryPoint();
error OnlySelf();
error InvalidSignature();
error ERC4337Disabled();
error InvalidERC4337Flag();
error ZeroAddressGuard();
error Invalid4337ExecutionSelector();
// keccak("Biz(bytes32 userOpHash)")
bytes32 private constant BIZ_USEROP_HASH = 0x4f51e7a567f083a31264743067875fc6a7ae45c32c5bd71f6a998c4625b13867;
// keccak("Biz(bytes32 msgHash)")
bytes32 private constant BIZ_MSG_HASH = 0x31322a37c2a66b24e1088197e5b24fcc050625c13d4b84c3eaa6a8be5270321d;
// keccak("Biz(bytes32 execHash)")
bytes32 private constant BIZ_EXEC_HASH = 0xec429430bbd6d0e373848272230d6fe2bac6319d903762e089c5cae97af53df0;
// keccak("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract,bytes32 salt)")
bytes32 private constant BIZ_DOMAIN_SEPARATOR_HASH =
0xd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac56472;
// keccak("Biz(bool Flag4337)")
bytes32 private constant BIZ_4337_FLAG = 0xa77908bfab24e6768503125e99551a4fa5c3c75f3106fee5dea5ac0cebc017a4;
// keccak256("Biz")
bytes32 private constant BIZ_HASH = 0x906754a21e6afe7233c7ccce2787110e84157e1cbaa80e58656dff779193a5cd;
// keccak256("v1.0.0")
bytes32 private constant VERSION_HASH = 0x15124d26d1272f8d4d5266a24ca397811f414b8cd05a53b26b745f63af5ae2fc;
uint256 private constant MAGIC_VALUE = 6789;
bytes4 internal constant ERC1271_SUCCESS = 0x1626ba7e;
bytes4 internal constant ERC1271_FAILURE = 0xffffffff;
BizGuard public immutable bizGuard;
bytes32 private immutable singletonSalt;
constructor(BizGuard _bizGuard) {
if (address(_bizGuard) == address(0)) revert ZeroAddressGuard();
bizGuard = _bizGuard;
singletonSalt = _addressToBytes32(address(this));
}
/// @dev Requires the caller to be EntryPoint.
modifier onlyEntryPoint() {
if (msg.sender != entryPoint()) revert OnlyEntryPoint();
_;
}
/// @dev Requires the caller to be Self.
modifier onlySelf() {
if (msg.sender != address(this)) revert OnlySelf();
_;
}
/// @dev Requires the BizGuard to enable ERC-4337.
modifier checkGuard() {
if (!bizGuard.is4337Enabled()) revert ERC4337Disabled();
_;
}
/**
* @notice Validates if the transient storage flag is set.
* @dev The transient storage tCounter is only set when the validateUserOp() is successful.
* For the validateUserOp() to be successful,
* - BizGuard should enable ERC-4337 flow
* - EntryPoint should be the msg.sender
* - Signature validation should pass
* tCounter is incremented per successful execution of validateUserOp()
* tCounter is decremented per successful execution of 4337 execution functions
* each ERC-4337 validation MUST be coupled with the execution functions. execute4337Op() or execute4337Ops().
*/
modifier check4337Flag() {
uint256 tCounter;
bool sFlagIsMagic;
assembly {
tCounter := tload(BIZ_4337_FLAG)
}
if (tCounter == 0) {
uint256 sFlag;
assembly {
sFlag := sload(BIZ_4337_FLAG)
}
if (sFlag != MAGIC_VALUE) revert InvalidERC4337Flag();
sFlagIsMagic = true;
}
_;
if (tCounter != 0) {
assembly {
tstore(BIZ_4337_FLAG, sub(tCounter, 1))
}
}
if (sFlagIsMagic) {
assembly {
sstore(BIZ_4337_FLAG, 0)
}
}
}
/**
* @notice Returns EntryPoint contract address.
* @return address of EntryPoint v0.7.0.
*/
function entryPoint() public view virtual returns (address) {
return 0x0000000071727De22E5E9d8BAf0edAc6f37da032;
}
/**
* @dev Provides the namespace of the account.
* @return string Biz namespace.
*/
function accountId() external pure override returns (string memory) {
return "TrustWallet.Biz.v1.0.0";
}
/**
* @notice Validates the UserOperation.
* @dev This function can only be called by the EntryPoint.
* It is a prerequisite to have BizGuard enable 4337 Flag.
* @param userOp PackedUserOperation to perform ERC-4337 validation & execution.
* @param userOpHash Bytes32 hash of UserOperation.
* @param missingAccountFunds Uint256 amount of funds to be sent to EntryPoint.
* @return validationData Uint256 validation result from the account.
*/
function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds)
external
onlyEntryPoint
checkGuard
returns (uint256 validationData)
{
bool isValid = _validateSignature(_getEncodedMsgHash(BIZ_USEROP_HASH, userOpHash), userOp.signature);
if (
bytes4(userOp.callData[:4]) != Biz.execute4337Op.selector
&& bytes4(userOp.callData[:4]) != Biz.execute4337Ops.selector
) revert Invalid4337ExecutionSelector();
if (isValid) {
_enable4337Flag();
validationData = 0;
} else {
validationData = 1;
}
assembly {
if missingAccountFunds { pop(call(gas(), caller(), missingAccountFunds, 0, 0, 0, 0)) }
}
}
/**
* @notice Validates if the signature is signed by Biz.
* @dev This function validates the signature if Biz indeed signed the given hash. It uses EIP-712.
* @param hash Bytes32 hash that is signed.
* @param signature Bytes signature to be validated.
* @return isValid Bytes4 indicating the success/failure of validation.
*/
function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4 isValid) {
isValid =
_validateSignature(_getEncodedMsgHash(BIZ_MSG_HASH, hash), signature) ? ERC1271_SUCCESS : ERC1271_FAILURE;
}
/**
* @notice Executes the given data.
* @dev This function performs execution and should only be called by the owner EOA.
* @param target Address to perform execution.
* @param value Uint256 value of native coin.
* @param data Bytes calldata to execute.
*/
function execute(address target, uint256 value, bytes calldata data) external payable onlySelf {
_call(target, value, data);
}
/**
* @notice Batch executes the given data.
* @dev This function executes the array of Calls.
* @param calls Array of execution data
*/
function executeBatch(Call[] calldata calls) external payable onlySelf {
uint256 length = calls.length;
for (uint256 i; i < length; ++i) {
_call(calls[i].target, calls[i].value, calls[i].data);
}
}
/**
* @notice Executes the given data from ERC-4337 EntryPoint.
* @dev This function performs execution and should only be called by the EntryPoint.
* ERC-4337 Flag should be enabled, indicates the success of the coupled validation.
* @param target Address to perform execution.
* @param value Uint256 value of native coin.
* @param data Bytes calldata to execute.
*/
function execute4337Op(address target, uint256 value, bytes calldata data)
external
payable
onlyEntryPoint
check4337Flag
{
_call(target, value, data);
}
/**
* @notice Batch executes the given data from ERC-4337 EntryPoint.
* @dev This function performs execution and should only be called by the EntryPoint.
* ERC-4337 Flag should be enabled, indicates the success of the coupled validation.
* @param calls Array of execution data.
*/
function execute4337Ops(Call[] calldata calls) external payable onlyEntryPoint check4337Flag {
uint256 length = calls.length;
for (uint256 i; i < length; ++i) {
_call(calls[i].target, calls[i].value, calls[i].data);
}
}
/**
* @notice Batch executes the given data after performing signature validation.
* @dev This function performs execution and is only executed if signature validation is successful.
* @param calls Array of execution data.
*/
function executeWithSignature(Call[] calldata calls, bytes calldata signature) external payable {
if (
!_validateSignature(
_getEncodedMsgHash(BIZ_EXEC_HASH, keccak256(abi.encode(calls, bizGuard.incrementNonce()))), signature
)
) {
revert InvalidSignature();
}
uint256 length = calls.length;
for (uint256 i; i < length; ++i) {
_call(calls[i].target, calls[i].value, calls[i].data);
}
}
/**
* @notice Receives native coin without data.
*/
receive() external payable {}
/**
* @notice Accepts incoming calls (with or without value), to mimic an EOA.
*/
fallback() external payable {}
/**
* @notice Validates if the signature is signed by Biz.
* @dev Uses ECDSA from Openzeppelin library.
* @param hash Bytes32 hash that is signed.
* @param signature Bytes signature to be validated.
* @return isValid Bytes4 indicating the success/failure of validation.
*/
function _validateSignature(bytes32 hash, bytes calldata signature) private view returns (bool isValid) {
isValid = (address(this) == ECDSA.recover(hash, signature));
}
/**
* @notice Generate encoded message hash from raw hash.
* @dev Uses EIP-712 encoding to wrap hash with typehash & domain separator.
* @param typeHash Bytes32 of Biz message.
* @param hash Bytes32 original hash.
* @return encodedMsgHash Encoded message hash.
*/
function _getEncodedMsgHash(bytes32 typeHash, bytes32 hash) private view returns (bytes32 encodedMsgHash) {
bytes32 messageHash = keccak256(abi.encode(typeHash, hash));
encodedMsgHash = keccak256(abi.encodePacked("\x19\x01", _domainSeparator(), messageHash));
}
/**
* @notice Returns the domain separator
* @dev Includes the address of singleton for signature resilience when re-delegation happens.
* @return domainSeparator Bytes32 domain separator
*/
function _domainSeparator() private view returns (bytes32 domainSeparator) {
return keccak256(
abi.encode(BIZ_DOMAIN_SEPARATOR_HASH, BIZ_HASH, VERSION_HASH, block.chainid, address(this), singletonSalt)
);
}
/**
* @notice Executes the given data.
* @dev This function performs execution and should only be called by the owner EOA.
* @param target Address to perform execution.
* @param value Uint256 value of native coin.
* @param data Bytes calldata to execute.
*/
function _call(address target, uint256 value, bytes memory data) private {
(bool success, bytes memory result) = target.call{value: value}(data);
if (!success) {
assembly {
revert(add(result, 32), mload(result))
}
}
}
/**
* @notice Enable 4337 Flag in transient storage.
* @dev 4337 Flag can only be enabled when
* - BizGuard is enabled
* - Signature validation is successful
* - Validation call is from EntryPoint
*/
function _enable4337Flag() private {
assembly {
tstore(BIZ_4337_FLAG, add(tload(BIZ_4337_FLAG), 1))
}
}
/**
* @notice Converts address to Bytes32
* @dev Zero bytes are padded left. Address is positioned right.
* @param _address Address to be converted to Bytes32
*/
function _addressToBytes32(address _address) private pure returns (bytes32 result) {
assembly {
result := _address
}
}
}
BizGuard.sol 56 lines
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.28;
import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol";
/**
* @title BizGuard - Guard contract for Biz.
* @dev Most important concepts:
* - BizGuard maintains the nonce of all Biz for signature validation.
* - BizGuard is an ownable smart contract with 4337 flag to enable/disable ERC-4337 of Biz.
* @author David Kim - @PowerStream3604
*/
contract BizGuard is Ownable2Step {
event FlagSet(bool flag);
mapping(address => uint256) public accountNonce;
bool erc4337Flag;
/**
* @notice constructor
* @dev Sets the initial owner of the account.
* @param owner address.
*/
constructor(address owner) Ownable(owner) {}
/**
* @notice Increment nonce of the msg.sender.
* @dev Nonce can only increment and not decrement.
* @return nonce uint256 nonce of the msg.sender.
*/
function incrementNonce() external returns (uint256 nonce) {
nonce = accountNonce[msg.sender];
unchecked {
++accountNonce[msg.sender];
}
}
/**
* @notice Return if the 4337 flag is enabled.
* @dev This view function is called by validateUserOp() in all Biz wallet.
* @return isEnabled bool flag whether 4337 is enabled.
*/
function is4337Enabled() external view returns (bool isEnabled) {
isEnabled = erc4337Flag;
}
/**
* @notice Set function to set 4337 Flag.
* @dev This function can only be called by the owner.
* @param flag bool value of the flag.
*/
function set4337Flag(bool flag) external onlyOwner {
erc4337Flag = flag;
emit FlagSet(flag);
}
}
BizHandler.sol 98 lines
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.28;
import {ERC721TokenReceiver} from "./interfaces/ERC721TokenReceiver.sol";
import {ERC1155TokenReceiver} from "./interfaces/ERC1155TokenReceiver.sol";
import {IERC165} from "./interfaces/IERC165.sol";
import {IERC7779} from "./interfaces/IERC7779.sol";
import {IERC1271} from "./interfaces/IERC1271.sol";
/**
* @title BizHandler - Handler contract for Biz.
* @author David Kim - @PowerStream3604
*/
abstract contract BizHandler is IERC7779, IERC165, ERC1155TokenReceiver, ERC721TokenReceiver {
// keccak256(abi.encode(uint256(keccak256(bytes("InteroperableDelegatedAccount.ERC.Storage"))) - 1)) & ~bytes32(uint256(0xff));
bytes32 internal constant ERC7779_STORAGE_BASE = 0xc473de86d0138e06e4d4918a106463a7cc005258d2e21915272bcb4594c18900;
struct ERC7779Storage {
bytes32[] storageBases;
}
/**
* @notice Returns if the interfaceId is supported by Biz.
* @param interfaceId Bytes4 interface id.
* @return bool Bool representing if interface id is supported.
*/
function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) {
return interfaceId == type(ERC1155TokenReceiver).interfaceId
|| interfaceId == type(ERC721TokenReceiver).interfaceId || interfaceId == type(IERC165).interfaceId
|| interfaceId == type(IERC7779).interfaceId || interfaceId == type(IERC1271).interfaceId;
}
/**
* @notice Handles ERC721 Token callback.
* @return bytes4 Standardized onERC721Received selector.
*/
function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) {
return this.onERC721Received.selector;
}
/**
* @notice Handles ERC1155 Token callback.
* @return bytes4 Standardized onERC1155Received selector.
*/
function onERC1155Received(address, address, uint256, uint256, bytes calldata)
external
pure
override
returns (bytes4)
{
return this.onERC1155Received.selector;
}
/**
* @notice Handles ERC1155 Token batch callback.
* @return bytes4 Standardized onERC1155BatchReceived selector.
*/
function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata)
external
pure
override
returns (bytes4)
{
return this.onERC1155BatchReceived.selector;
}
/**
* @notice Handles ERC777 Token callback.
* Does not return value, empty implementation.
*/
function tokensReceived(address, address, address, uint256, bytes calldata, bytes calldata) external pure {}
/**
* @notice Handles ERC677 Token callback.
* @return bool true.
*/
function onTokenTransfer(address, uint256, bytes calldata) external pure returns (bool) {
return true;
}
/**
* @dev Provides the namespace of the account.
* @return string Biz namespace.
*/
function accountId() external pure virtual returns (string memory) {}
/**
* @dev Provides the array of storage bases.
* @return bytes32[] of storage bases.
*/
function accountStorageBases() external view returns (bytes32[] memory) {
ERC7779Storage storage $;
assembly {
$.slot := ERC7779_STORAGE_BASE
}
return $.storageBases;
}
}
ERC1155TokenReceiver.sol 43 lines
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.28;
// Note: The ERC-165 identifier for this interface is 0x4e2312e0.
interface ERC1155TokenReceiver {
/**
* @notice Handle the receipt of a single ERC1155 token type.
* @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated.
* This function MUST return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` (i.e. 0xf23a6e61) if it accepts the transfer.
* This function MUST revert if it rejects the transfer.
* Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.
* @param _operator The address which initiated the transfer (i.e. msg.sender).
* @param _from The address which previously owned the token.
* @param _id The ID of the token being transferred.
* @param _value The amount of tokens being transferred.
* @param _data Additional data with no specified format.
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`.
*/
function onERC1155Received(address _operator, address _from, uint256 _id, uint256 _value, bytes calldata _data)
external
returns (bytes4);
/**
* @notice Handle the receipt of multiple ERC1155 token types.
* @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated.
* This function MUST return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` (i.e. 0xbc197c81) if it accepts the transfer(s).
* This function MUST revert if it rejects the transfer(s).
* Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.
* @param _operator The address which initiated the batch transfer (i.e. msg.sender).
* @param _from The address which previously owned the token.
* @param _ids An array containing ids of each token being transferred (order and length must match _values array).
* @param _values An array containing amounts of each token being transferred (order and length must match _ids array).
* @param _data Additional data with no specified format.
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`.
*/
function onERC1155BatchReceived(
address _operator,
address _from,
uint256[] calldata _ids,
uint256[] calldata _values,
bytes calldata _data
) external returns (bytes4);
}
ERC721TokenReceiver.sol 23 lines
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.28;
/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.
interface ERC721TokenReceiver {
/**
* @notice Handle the receipt of an NFT
* @dev The ERC721 smart contract calls this function on the recipient
* after a `transfer`. This function MAY throw to revert and reject the
* transfer. Return of other than the magic value MUST result in the
* transaction being reverted.
* Note: the contract address is always the message sender.
* @param _operator The address which called `safeTransferFrom` function.
* @param _from The address which previously owned the token.
* @param _tokenId The NFT identifier which is being transferred.
* @param _data Additional data with no specified format.
* @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
* unless throwing
*/
function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data)
external
returns (bytes4);
}
IERC1271.sol 15 lines
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.28;
interface IERC1271 {
/**
* @dev Should return whether the signature provided is valid for the provided hash
* @param _hash Hash of the data to be signed
* @param _signature Signature byte array associated with _hash
*
* MUST return the bytes4 magic value 0x1626ba7e when function passes.
* MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
* MUST allow external calls
*/
function isValidSignature(bytes32 _hash, bytes memory _signature) external view returns (bytes4);
}
IERC165.sol 15 lines
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.28;
/// @notice More details at https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/introspection/IERC165.sol
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by `interfaceId`.
* See the corresponding EIP section
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
IERC7779.sol 25 lines
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.28;
interface IERC7779 {
/*
* @dev Provides the namespace of the account.
* namespace of accounts can possibly include, account version, account name, wallet vendor name, etc
* @notice this standard does not standardize the namespace format
* e.g., "v0.1.2.7702Account.WalletProjectA"
*/
function accountId() external view returns (string memory);
/*
* @dev Externally shares the storage bases that has been used throughout the account.
* Majority of 7702 accounts will have their distinctive storage base to reduce the chance of storage collision.
* This allows the external entities to know what the storage base is of the account.
* Wallets willing to redelegate already-delegated accounts should call accountStorageBase() to check if it confirms with the account it plans to redelegate.
*
* The bytes32 array should be stored at the storage slot: keccak(keccak('InteroperableDelegatedAccount.ERC.Storage')-1) & ~0xff
* This is an append-only array so newly redelegated accounts should not overwrite the storage at this slot, but just append their base to the array.
* This append operation should be done during the initialization of the account.
* This array should return a value of keccak hash unless using external storage.
*/
function accountStorageBases() external view returns (bytes32[] memory);
}
Read Contract
accountId 0x9cfd7cff → string
accountStorageBases 0x8626e88b → bytes32[]
bizGuard 0xcf21ecab → address
entryPoint 0xb0d691fe → address
isValidSignature 0x1626ba7e → bytes4
onERC1155BatchReceived 0xbc197c81 → bytes4
onERC1155Received 0xf23a6e61 → bytes4
onERC721Received 0x150b7a02 → bytes4
onTokenTransfer 0xa4c0ed36 → bool
supportsInterface 0x01ffc9a7 → bool
tokensReceived 0x0023de29
Write Contract 6 functions
These functions modify contract state and require a wallet transaction to execute.
execute 0xb61d27f6
address target
uint256 value
bytes data
execute4337Op 0x76276c82
address target
uint256 value
bytes data
execute4337Ops 0x3e1a0339
tuple[] calls
executeBatch 0xe3f3e7ec
tuple[] calls
executeWithSignature 0xcc7cb962
tuple[] calls
bytes signature
validateUserOp 0x50b589d2
tuple userOp
bytes32 userOpHash
uint256 missingAccountFunds
returns: uint256
Token Balances (1) $240.00
View Transfers →| Token | Balance | Price | Value |
|---|---|---|---|
| USDC | 240 | $1.00 | $240.00 |
Recent Transactions
This address has 1 on-chain transactions, but only 1.6% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →