// SPDX-License-Identifier: CC0-1.0
pragma solidity 0.8.23;
/// @notice `ERC6538Registry` contract to map accounts to their stealth meta-address. See
/// [ERC-6538](https://eips.ethereum.org/EIPS/eip-6538) to learn more.
contract ERC6538Registry {
/// @notice Emitted when an invalid signature is provided to `registerKeysOnBehalf`.
error ERC6538Registry__InvalidSignature();
/// @notice Next nonce expected from `user` to use when signing for `registerKeysOnBehalf`.
/// @dev `registrant` may be a standard 160-bit address or any other identifier.
/// @dev `schemeId` is an integer identifier for the stealth address scheme.
mapping(address registrant => mapping(uint256 schemeId => bytes)) public stealthMetaAddressOf;
/// @notice A nonce used to ensure a signature can only be used once.
/// @dev `registrant` is the user address.
/// @dev `nonce` will be incremented after each valid `registerKeysOnBehalf` call.
mapping(address registrant => uint256) public nonceOf;
/// @notice The EIP-712 type hash used in `registerKeysOnBehalf`.
bytes32 public constant ERC6538REGISTRY_ENTRY_TYPE_HASH =
keccak256("Erc6538RegistryEntry(uint256 schemeId,bytes stealthMetaAddress,uint256 nonce)");
/// @notice The chain ID where this contract is initially deployed.
uint256 internal immutable INITIAL_CHAIN_ID;
/// @notice The domain separator used in this contract.
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
/// @notice Emitted when a registrant updates their stealth meta-address.
/// @param registrant The account that registered the stealth meta-address.
/// @param schemeId Identifier corresponding to the applied stealth address scheme, e.g. 1 for
/// secp256k1, as specified in ERC-5564.
/// @param stealthMetaAddress The stealth meta-address.
/// [ERC-5564](https://eips.ethereum.org/EIPS/eip-5564) bases the format for stealth
/// meta-addresses on [ERC-3770](https://eips.ethereum.org/EIPS/eip-3770) and specifies them as:
/// st:<shortName>:0x<spendingPubKey>:<viewingPubKey>
/// The chain (`shortName`) is implicit based on the chain the `ERC6538Registry` is deployed on,
/// therefore this `stealthMetaAddress` is just the compressed `spendingPubKey` and
/// `viewingPubKey` concatenated.
event StealthMetaAddressSet(
address indexed registrant, uint256 indexed schemeId, bytes stealthMetaAddress
);
/// @notice Emitted when a registrant increments their nonce.
/// @param registrant The account that incremented the nonce.
/// @param newNonce The new nonce value.
event NonceIncremented(address indexed registrant, uint256 newNonce);
constructor() {
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator();
}
/// @notice Sets the caller's stealth meta-address for the given scheme ID.
/// @param schemeId Identifier corresponding to the applied stealth address scheme, e.g. 1 for
/// secp256k1, as specified in ERC-5564.
/// @param stealthMetaAddress The stealth meta-address to register.
function registerKeys(uint256 schemeId, bytes calldata stealthMetaAddress) external {
stealthMetaAddressOf[msg.sender][schemeId] = stealthMetaAddress;
emit StealthMetaAddressSet(msg.sender, schemeId, stealthMetaAddress);
}
/// @notice Sets the `registrant`'s stealth meta-address for the given scheme ID.
/// @param registrant Address of the registrant.
/// @param schemeId Identifier corresponding to the applied stealth address scheme, e.g. 1 for
/// secp256k1, as specified in ERC-5564.
/// @param signature A signature from the `registrant` authorizing the registration.
/// @param stealthMetaAddress The stealth meta-address to register.
/// @dev Supports both EOA signatures and EIP-1271 signatures.
/// @dev Reverts if the signature is invalid.
function registerKeysOnBehalf(
address registrant,
uint256 schemeId,
bytes memory signature,
bytes calldata stealthMetaAddress
) external {
bytes32 dataHash;
address recoveredAddress;
unchecked {
dataHash = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
ERC6538REGISTRY_ENTRY_TYPE_HASH,
schemeId,
keccak256(stealthMetaAddress),
nonceOf[registrant]++
)
)
)
);
}
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
assembly ("memory-safe") {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
recoveredAddress = ecrecover(dataHash, v, r, s);
}
if (
(
(recoveredAddress == address(0) || recoveredAddress != registrant)
&& (
IERC1271(registrant).isValidSignature(dataHash, signature)
!= IERC1271.isValidSignature.selector
)
)
) revert ERC6538Registry__InvalidSignature();
stealthMetaAddressOf[registrant][schemeId] = stealthMetaAddress;
emit StealthMetaAddressSet(registrant, schemeId, stealthMetaAddress);
}
/// @notice Increments the nonce of the sender to invalidate existing signatures.
function incrementNonce() external {
unchecked {
nonceOf[msg.sender]++;
}
emit NonceIncremented(msg.sender, nonceOf[msg.sender]);
}
/// @notice Returns the domain separator used in this contract.
/// @dev The domain separator is re-computed if there's a chain fork.
function DOMAIN_SEPARATOR() public view returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : _computeDomainSeparator();
}
/// @notice Computes the domain separator for this contract.
function _computeDomainSeparator() internal view returns (bytes32) {
return keccak256(
abi.encode(
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
),
keccak256("ERC6538Registry"),
keccak256("1.0"),
block.chainid,
address(this)
)
);
}
}
/// @notice Interface of the ERC1271 standard signature validation method for contracts as defined
/// in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
interface IERC1271 {
/// @notice Should return whether the signature provided is valid for the provided data
/// @param hash Hash of the data to be signed
/// @param signature Signature byte array associated with _data
function isValidSignature(bytes32 hash, bytes memory signature)
external
view
returns (bytes4 magicValue);
}[
{
"type": "constructor",
"inputs": [],
"stateMutability": "nonpayable"
},
{
"name": "ERC6538Registry__InvalidSignature",
"type": "error",
"inputs": []
},
{
"name": "NonceIncremented",
"type": "event",
"inputs": [
{
"name": "registrant",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "newNonce",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
}
],
"anonymous": false
},
{
"name": "StealthMetaAddressSet",
"type": "event",
"inputs": [
{
"name": "registrant",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "schemeId",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
},
{
"name": "stealthMetaAddress",
"type": "bytes",
"indexed": false,
"internalType": "bytes"
}
],
"anonymous": false
},
{
"name": "DOMAIN_SEPARATOR",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "bytes32",
"internalType": "bytes32"
}
],
"stateMutability": "view"
},
{
"name": "ERC6538REGISTRY_ENTRY_TYPE_HASH",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "bytes32",
"internalType": "bytes32"
}
],
"stateMutability": "view"
},
{
"name": "incrementNonce",
"type": "function",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "nonceOf",
"type": "function",
"inputs": [
{
"name": "registrant",
"type": "address",
"internalType": "address"
}
],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "registerKeys",
"type": "function",
"inputs": [
{
"name": "schemeId",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "stealthMetaAddress",
"type": "bytes",
"internalType": "bytes"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "registerKeysOnBehalf",
"type": "function",
"inputs": [
{
"name": "registrant",
"type": "address",
"internalType": "address"
},
{
"name": "schemeId",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "signature",
"type": "bytes",
"internalType": "bytes"
},
{
"name": "stealthMetaAddress",
"type": "bytes",
"internalType": "bytes"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "stealthMetaAddressOf",
"type": "function",
"inputs": [
{
"name": "registrant",
"type": "address",
"internalType": "address"
},
{
"name": "schemeId",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [
{
"name": "",
"type": "bytes",
"internalType": "bytes"
}
],
"stateMutability": "view"
}
]0x608060405234801561001057600080fd5b506004361061007d5760003560e01c8063627cdcb91161005b578063627cdcb9146100c55780637aa8b5ad146100cd578063ed2a2d64146100ed578063fe04b1061461010d57600080fd5b8063042c7aa3146100825780633644e51514610097578063428d3d0b146100b2575b600080fd5b610095610090366004610743565b610134565b005b61009f6101ae565b6040519081526020015b60405180910390f35b6100956100c03660046107e7565b6102a9565b61009561060a565b6100e06100db3660046108fc565b610658565b6040516100a9919061098a565b61009f6100fb3660046109a4565b60016020526000908152604090205481565b61009f7fad167d3025c204a322703b7e9c41f6179d0d174570f484391f50080b960d41d681565b336000908152602081815260408083208684529091529020610157828483610a63565b50823373ffffffffffffffffffffffffffffffffffffffff167f4e739a47dfa4fd3cfa92f8fe760cebe125565927e5c422cb28e7aa388a067af984846040516101a1929190610b7e565b60405180910390a3505050565b60007f000000000000000000000000000000000000000000000000000000000000123746146102845761027f604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f6124ff9f656d31cbb8918f3698282fe3b3527cc4dede357f0fbf535d197bbb7f918101919091527fe6bbd6277e1bf288eed5e8d1780f9a50b239e86b153736bceebccf4ea79d90b360608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b905090565b507fb4b198312994e495647cd27bed0033671c4d015953b9c93de02425b3ab9f4cc790565b6000806102b46101ae565b7fad167d3025c204a322703b7e9c41f6179d0d174570f484391f50080b960d41d68786866040516102e6929190610bcb565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff8d166000908152600160208181529390912080549182019055610344959493919290910193845260208401929092526040830152606082015260800190565b6040516020818303038152906040528051906020012060405160200161039c9291907f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b604051602081830303815290604052805190602001209150845160410361042d576020858101516040808801516060808a015183516000808252968101808652899052951a928501839052840183905260808401819052919260019060a0016020604051602081039080840390855afa15801561041d573d6000803e3d6000fd5b5050506020604051035193505050505b73ffffffffffffffffffffffffffffffffffffffff8116158061047c57508673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b801561053f57506040517f1626ba7e000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff891690631626ba7e906104d99086908a90600401610bdb565b602060405180830381865afa1580156104f6573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061051a9190610bfc565b7fffffffff000000000000000000000000000000000000000000000000000000001614155b15610576576040517fc5c2e66100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff871660009081526020818152604080832089845290915290206105af848683610a63565b50858773ffffffffffffffffffffffffffffffffffffffff167f4e739a47dfa4fd3cfa92f8fe760cebe125565927e5c422cb28e7aa388a067af986866040516105f9929190610b7e565b60405180910390a350505050505050565b3360008181526001602081815260409283902080549092019182905591519081527fa82a649bbd060c9099cd7b7326e2b0dc9e9af0836480e0f849dc9eaa79710b3b910160405180910390a2565b600060208181529281526040808220909352908152208054610679906109bf565b80601f01602080910402602001604051908101604052809291908181526020018280546106a5906109bf565b80156106f25780601f106106c7576101008083540402835291602001916106f2565b820191906000526020600020905b8154815290600101906020018083116106d557829003601f168201915b505050505081565b60008083601f84011261070c57600080fd5b50813567ffffffffffffffff81111561072457600080fd5b60208301915083602082850101111561073c57600080fd5b9250929050565b60008060006040848603121561075857600080fd5b83359250602084013567ffffffffffffffff81111561077657600080fd5b610782868287016106fa565b9497909650939450505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146107b357600080fd5b919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000806000608086880312156107ff57600080fd5b6108088661078f565b945060208601359350604086013567ffffffffffffffff8082111561082c57600080fd5b818801915088601f83011261084057600080fd5b813581811115610852576108526107b8565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715610898576108986107b8565b816040528281528b60208487010111156108b157600080fd5b8260208601602083013760006020848301015280975050505060608801359150808211156108de57600080fd5b506108eb888289016106fa565b969995985093965092949392505050565b6000806040838503121561090f57600080fd5b6109188361078f565b946020939093013593505050565b6000815180845260005b8181101561094c57602081850181015186830182015201610930565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061099d6020830184610926565b9392505050565b6000602082840312156109b657600080fd5b61099d8261078f565b600181811c908216806109d357607f821691505b602082108103610a0c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115610a5e576000816000526020600020601f850160051c81016020861015610a3b5750805b601f850160051c820191505b81811015610a5a57828155600101610a47565b5050505b505050565b67ffffffffffffffff831115610a7b57610a7b6107b8565b610a8f83610a8983546109bf565b83610a12565b6000601f841160018114610ae15760008515610aab5750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355610b77565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015610b305786850135825560209485019460019092019101610b10565b5086821015610b6b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555b5050505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b8183823760009101908152919050565b828152604060208201526000610bf46040830184610926565b949350505050565b600060208284031215610c0e57600080fd5b81517fffffffff000000000000000000000000000000000000000000000000000000008116811461099d57600080fdfea164736f6c6343000817000a
| Token | Symbol | Balance | Price | Value |
|---|---|---|---|---|
| no token holdings | ||||
| Block | Age | Parent Transaction Hash | Type | Method | From | To | Value | |
|---|---|---|---|---|---|---|---|---|
| no internal transactions found for this address yet (traced blocks + on-demand) | ||||||||
| Type | Age | Block | Details |
|---|---|---|---|
| no cross-chain L1↔L2 transactions for this address | |||
| Txn Hash | Age | Event | Topics / Data |
|---|---|---|---|
| 0x017686…967e3c | 7 days agoMon, 10 Aug 2026 14:12:15 UTC | 0x4e739a…7af9 | [0] 0x000000000000…6bbe9443 [1] 0x000000000000…00000001 data: 0x000000000000000000…00000000 |
| 0x6206f4…0a8149 | 7 days agoMon, 10 Aug 2026 14:04:03 UTC | 0x4e739a…7af9 | [0] 0x000000000000…6bbe9443 [1] 0x000000000000…00000001 data: 0x000000000000000000…00000000 |
| 0x6991b4…55498f | 26 days agoWed, 22 Jul 2026 05:04:01 UTC | 0x4e739a…7af9 | [0] 0x000000000000…deca7d03 [1] 0x000000000000…00000001 data: 0x000000000000000000…00000000 |
| 0xb56df4…b747e9 | 26 days agoWed, 22 Jul 2026 04:47:01 UTC | 0x4e739a…7af9 | [0] 0x000000000000…f5e70223 [1] 0x000000000000…00000001 data: 0x000000000000000000…00000000 |
| 0x54d7c1…bcd32b | 29 days agoSun, 19 Jul 2026 03:09:42 UTC | 0x4e739a…7af9 | [0] 0x000000000000…e691096d [1] 0x000000000000…00000001 data: 0x000000000000000000…00000000 |
| Transaction Hash | Method | Block | Age | From | To | Type | Item | ||
|---|---|---|---|---|---|---|---|---|---|
| no NFT transfers for this address yet | |||||||||
| Transaction Hash | Method | Block | Age | From | To | Amount | Token | ||
|---|---|---|---|---|---|---|---|---|---|
| no token transfers for this address yet | |||||||||
| Transaction Hash | Method ? | Block | Age | From | To | Amount | Txn Fee ? | ||
|---|---|---|---|---|---|---|---|---|---|
| 0x017686…967e3c | registerKeys | 32,860,651 | 7 days agoMon, 10 Aug 2026 14:12:15 UTC | 0x9ad0…9443 | IN | ERC6538Registry | $0.000 ETH | 0.00000116 | |
| 0x6206f4…0a8149 | registerKeys | 32,855,741 | 7 days agoMon, 10 Aug 2026 14:04:03 UTC | 0x9ad0…9443 | IN | ERC6538Registry | $0.000 ETH | 0.00000297 | |
| 0x6991b4…55498f | registerKeys | 16,159,411 | 26 days agoWed, 22 Jul 2026 05:04:01 UTC | 0x2df2…7d03 | IN | ERC6538Registry | $0.000 ETH | 0.00000870 | |
| 0xb56df4…b747e9 | registerKeys | 16,149,245 | 26 days agoWed, 22 Jul 2026 04:47:01 UTC | 0x7168…0223 | IN | ERC6538Registry | $0.000 ETH | 0.00000870 | |
| 0x54d7c1…bcd32b | registerKeys | 13,507,146 | 29 days agoSun, 19 Jul 2026 03:09:42 UTC | 0xf1c3…096d | IN | ERC6538Registry | $0.000 ETH | 0.00000726 |