Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 65 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Trusted Register | 13052972 | 272 days ago | IN | 0 ETH | 0.00318543 | ||||
Trusted Register | 13041244 | 272 days ago | IN | 0 ETH | 0.00009197 | ||||
Trusted Register | 12990718 | 273 days ago | IN | 0 ETH | 0.00000495 | ||||
Trusted Register | 12950394 | 274 days ago | IN | 0 ETH | 0.00000048 | ||||
Trusted Register | 12949949 | 274 days ago | IN | 0 ETH | 0.00000048 | ||||
Trusted Register | 12949728 | 274 days ago | IN | 0 ETH | 0.00000048 | ||||
Trusted Register | 12831731 | 277 days ago | IN | 0 ETH | 0.00000048 | ||||
Trusted Register | 12831693 | 277 days ago | IN | 0 ETH | 0.00000048 | ||||
Trusted Register | 12831661 | 277 days ago | IN | 0 ETH | 0.00000048 | ||||
Trusted Register | 12830508 | 277 days ago | IN | 0 ETH | 0.00000048 | ||||
Trusted Register | 12821356 | 277 days ago | IN | 0 ETH | 0.00000048 | ||||
Trusted Register | 12816840 | 277 days ago | IN | 0 ETH | 0.00000048 | ||||
Trusted Register | 12816548 | 277 days ago | IN | 0 ETH | 0.00000041 | ||||
Trusted Register | 12816473 | 277 days ago | IN | 0 ETH | 0.00000034 | ||||
Trusted Register | 12816365 | 277 days ago | IN | 0 ETH | 0.00000029 | ||||
Trusted Register | 12816324 | 277 days ago | IN | 0 ETH | 0.00000028 | ||||
Trusted Register | 12816317 | 277 days ago | IN | 0 ETH | 0.00000028 | ||||
Trusted Register | 12816241 | 277 days ago | IN | 0 ETH | 0.00000028 | ||||
Trusted Register | 12816194 | 277 days ago | IN | 0 ETH | 0.00000029 | ||||
Trusted Register | 12816118 | 277 days ago | IN | 0 ETH | 0.0000003 | ||||
Trusted Register | 12816076 | 277 days ago | IN | 0 ETH | 0.0000003 | ||||
Trusted Register | 12816037 | 277 days ago | IN | 0 ETH | 0.00000031 | ||||
Trusted Register | 12815874 | 277 days ago | IN | 0 ETH | 0.00000033 | ||||
Trusted Register | 12815625 | 277 days ago | IN | 0 ETH | 0.00000038 | ||||
Trusted Register | 12788472 | 278 days ago | IN | 0 ETH | 0.00000024 |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
Bundler
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 500000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {IdRegistry} from "./IdRegistry.sol"; import {KeyRegistry} from "./KeyRegistry.sol"; import {IBundler} from "./interfaces/IBundler.sol"; import {Trust} from "./abstract/Trust.sol"; /** * @title River Bundler * @dev Forked from Farcaster Bundler.sol */ contract Bundler is IBundler, Trust { /*////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ /// @dev Revert if the caller does not have the authority to perform the action. error Unauthorized(); /// @dev Revert if the caller attempts to rent zero storage units. error InvalidAmount(); /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ /** * @dev Contract version specified using River protocol version scheme. */ string public constant VERSION = "2024.07.11"; /*////////////////////////////////////////////////////////////// IMMUTABLES //////////////////////////////////////////////////////////////*/ /** * @dev Address of the IdRegistry contract */ IdRegistry public immutable idRegistry; /** * @dev Address of the KeyRegistry contract */ KeyRegistry public immutable keyRegistry; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ /** * @notice Configure the addresses of the Registry contracts * * @param _idRegistry Address of the IdRegistry contract * @param _keyRegistry Address of the KeyRegistry contract * @param _initialOwner Address of the KeyRegistry contract */ constructor( address _idRegistry, address _keyRegistry, address _initialOwner ) Trust(_initialOwner) { idRegistry = IdRegistry(_idRegistry); keyRegistry = KeyRegistry(_keyRegistry); // address[] memory trustedAccounts = new address[](1); // bool[] memory statuses = new bool[](1); // trustedAccounts[0] = _initialOwner; // statuses[0] = true; // // setTrustedCallers(trustedAccounts, statuses); } /** * @notice Register an rid and multiple signers in a single transaction. * * @param registration Struct containing registration parameters: to, recovery, deadline, and signature. * @param signers Array of structs containing signer parameters: keyType, key, metadataType, * metadata, deadline, and signature. * */ function trustedRegister( RegistrationParams calldata registration, SignerParams[] calldata signers ) external payable onlyTrustedCaller { uint256 rid = idRegistry.trustedRegisterFor(registration.to, registration.recovery); uint256 signersLen = signers.length; for (uint256 i; i < signersLen;) { SignerParams calldata signer = signers[i]; keyRegistry.trustedAddFor( registration.to, signer.keyType, signer.key, signer.metadataType, signer.metadata, signer.deadline, signer.sig ); // We know this will not overflow because it's less than the length of the array, which is a `uint256`. unchecked { ++i; } } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {Pausable} from "@openzeppelin/utils/Pausable.sol"; import {IIdRegistry} from "./interfaces/IIdRegistry.sol"; import {Signatures} from "./abstract/Signatures.sol"; import {EIP712} from "./abstract/EIP712.sol"; import {Nonces} from "./abstract/Nonces.sol"; import {Trust} from "./abstract/Trust.sol"; /** * @title IdRegistry * @author Lifeworld * @notice This contract is a fork of Farcaster IdRegistry v3.0.0 */ contract IdRegistry is IIdRegistry, Trust, Pausable, Signatures, EIP712, Nonces { //////////////////////////////////////////////////////////////// // CONSTANTS //////////////////////////////////////////////////////////////// string public constant NAME = "River Id Registry"; // TODO: update string public constant VERSION = "2024.07.11"; bytes32 public constant REGISTER_TYPEHASH = keccak256("Register(address to,address recovery,uint256 nonce,uint256 deadline)"); bytes32 public constant TRANSFER_TYPEHASH = keccak256("Transfer(uint256 rid,address to,uint256 nonce,uint256 deadline)"); bytes32 public constant TRANSFER_AND_CHANGE_RECOVERY_TYPEHASH = keccak256("TransferAndChangeRecovery(uint256 rid,address to,address recovery,uint256 nonce,uint256 deadline)"); bytes32 public constant CHANGE_RECOVERY_ADDRESS_TYPEHASH = keccak256("ChangeRecoveryAddress(uint256 rid,address from,address to,uint256 nonce,uint256 deadline)"); //////////////////////////////////////////////////////////////// // STORAGE //////////////////////////////////////////////////////////////// uint256 public idCounter; mapping(address owner => uint256 rid) public idOf; mapping(uint256 rid => address owner) public custodyOf; mapping(uint256 rid => address recovery) public recoveryOf; //////////////////////////////////////////////////////////////// // CONSTRUCTOR //////////////////////////////////////////////////////////////// /** * @notice Set the owner of the contract to the provided _initialOwner. * * @param _initialOwner Initial owner address. * */ // solhint-disable-next-line no-empty-blocks constructor(address _initialOwner) Trust(_initialOwner) EIP712("River IdRegistry", "1") {} //////////////////////////////////////////////////////////////// // REGISTER LOGIC //////////////////////////////////////////////////////////////// function trustedRegisterFor( address to, address recovery ) external onlyTrustedCaller returns (uint256 rid) { // NOTE: not perform any signature checks for rid recipient return _register(to, recovery); } function register(address recovery) external whenNotTrustedOnly returns (uint256 rid) { return _register(msg.sender, recovery); } function registerFor( address to, address recovery, uint256 deadline, bytes calldata sig ) external whenNotTrustedOnly returns (uint256 rid) { /* Revert if signature is invalid */ _verifyRegisterSig({to: to, recovery: recovery, deadline: deadline, sig: sig}); return _register(to, recovery); } /** * @dev Will revert if msg.sender is not a trusted caller */ function _register(address to, address recovery) internal returns (uint256 rid) { rid = _unsafeRegister(to, recovery); emit Register(to, idCounter, recovery); } /// @dev will revert if contract is paused function _unsafeRegister(address to, address recovery) internal whenNotPaused returns (uint256 rid) { /* Revert if the target(to) has an rid */ if (idOf[to] != 0) revert Has_Id(); /* Incrementing before assignment ensures that no one gets the 0 rid. */ rid = ++idCounter; /* Register id */ idOf[to] = rid; custodyOf[rid] = to; recoveryOf[rid] = recovery; } //////////////////////////////////////////////////////////////// // TRANSFER LOGIC //////////////////////////////////////////////////////////////// function transfer(address to, uint256 deadline, bytes calldata toSig) external { uint256 fromId = _validateTransfer(msg.sender, to); /* Revert if signature is invalid */ _verifyTransferSig({rid: fromId, to: to, deadline: deadline, signer: to, sig: toSig}); _unsafeTransfer(fromId, msg.sender, to); } function transferFor( address from, address to, uint256 fromDeadline, bytes calldata fromSig, uint256 toDeadline, bytes calldata toSig ) external { uint256 fromId = _validateTransfer(from, to); /* Revert if either signature is invalid */ _verifyTransferSig({rid: fromId, to: to, deadline: fromDeadline, signer: from, sig: fromSig}); _verifyTransferSig({rid: fromId, to: to, deadline: toDeadline, signer: to, sig: toSig}); _unsafeTransfer(fromId, from, to); } function transferAndChangeRecovery(address to, address recovery, uint256 deadline, bytes calldata sig) external { uint256 fromId = _validateTransfer(msg.sender, to); /* Revert if signature is invalid */ _verifyTransferAndChangeRecoverySig({ rid: fromId, to: to, recovery: recovery, deadline: deadline, signer: to, sig: sig }); _unsafeTransfer(fromId, msg.sender, to); _unsafeChangeRecovery(fromId, recovery); } function transferAndChangeRecoveryFor( address from, address to, address recovery, uint256 fromDeadline, bytes calldata fromSig, uint256 toDeadline, bytes calldata toSig ) external { uint256 fromId = _validateTransfer(from, to); /* Revert if either signature is invalid */ _verifyTransferAndChangeRecoverySig({ rid: fromId, to: to, recovery: recovery, deadline: fromDeadline, signer: from, sig: fromSig }); _verifyTransferAndChangeRecoverySig({ rid: fromId, to: to, recovery: recovery, deadline: toDeadline, signer: to, sig: toSig }); _unsafeTransfer(fromId, from, to); _unsafeChangeRecovery(fromId, recovery); } /** * @dev Retrieve rid and validate sender/recipient */ function _validateTransfer(address from, address to) internal view returns (uint256 fromId) { fromId = idOf[from]; /* Revert if the sender has no id */ if (fromId == 0) revert Has_No_Id(); /* Revert if recipient has an id */ if (idOf[to] != 0) revert Has_Id(); } /** * @dev Transfer the rid to another address without checking invariants. * @dev Will revert if contract is paused */ function _unsafeTransfer(uint256 id, address from, address to) internal whenNotPaused { idOf[to] = id; custodyOf[id] = to; delete idOf[from]; emit Transfer(from, to, id); } //////////////////////////////////////////////////////////////// // RECOVERY LOGIC //////////////////////////////////////////////////////////////// function changeRecoveryAddress(address recovery) external whenNotPaused { /* Revert if the caller does not own an rid */ uint256 ownerId = idOf[msg.sender]; if (ownerId == 0) revert Has_No_Id(); _unsafeChangeRecovery(ownerId, recovery); } function changeRecoveryAddressFor( address owner, address recovery, uint256 deadline, bytes calldata sig ) external whenNotPaused { /* Revert if the caller does not own an rid */ uint256 ownerId = idOf[owner]; if (ownerId == 0) revert Has_No_Id(); _verifyChangeRecoveryAddressSig({ rid: ownerId, from: recoveryOf[ownerId], to: recovery, deadline: deadline, signer: owner, sig: sig }); _unsafeChangeRecovery(ownerId, recovery); } /** * @dev Change recovery address without checking invariants. * @dev Will revert if contract is paused */ function _unsafeChangeRecovery(uint256 id, address recovery) internal whenNotPaused { /* Change the recovery address */ recoveryOf[id] = recovery; emit ChangeRecoveryAddress(id, recovery); } function recover(address from, address to, uint256 deadline, bytes calldata toSig) external { /* Revert if from does not own an rid */ uint256 fromId = idOf[from]; if (fromId == 0) revert Has_No_Id(); /* Revert if the caller is not the recovery address */ address caller = msg.sender; if (recoveryOf[fromId] != caller) revert Unauthorized(); /* Revert if destination(to) already has an rid */ if (idOf[to] != 0) revert Has_Id(); /* Revert if signature is invalid */ _verifyTransferSig({rid: fromId, to: to, deadline: deadline, signer: to, sig: toSig}); emit Recover(from, to, fromId); _unsafeTransfer(fromId, from, to); } function recoverFor( address from, address to, uint256 recoveryDeadline, bytes calldata recoverySig, uint256 toDeadline, bytes calldata toSig ) external { /* Revert if from does not own an rid */ uint256 fromId = idOf[from]; if (fromId == 0) revert Has_No_Id(); /* Revert if destination(to) already has an rid */ if (idOf[to] != 0) revert Has_Id(); /* Revert if either signature is invalid */ _verifyTransferSig({ rid: fromId, to: to, deadline: recoveryDeadline, signer: recoveryOf[fromId], sig: recoverySig }); _verifyTransferSig({rid: fromId, to: to, deadline: toDeadline, signer: to, sig: toSig}); emit Recover(from, to, fromId); _unsafeTransfer(fromId, from, to); } //////////////////////////////////////////////////////////////// // PERMISSIONED ACTIONS //////////////////////////////////////////////////////////////// function pause() external onlyOwner { _pause(); } function unpause() external onlyOwner { _unpause(); } //////////////////////////////////////////////////////////////// // VIEWS //////////////////////////////////////////////////////////////// // TODO: need to test if this works // also what will it look like on etherscan? a write call that always reverts? // do we need to add the revert in ourselves? function verifyRidSignature( address custodyAddress, uint256 rid, bytes32 digest, bytes calldata sig ) external returns (bool isValid) { isValid = idOf[custodyAddress] == rid && _verifySigWithReturn(digest, custodyAddress, sig); } //////////////////////////////////////////////////////////////// // SIGNATURE VERIFICATION HELPERS //////////////////////////////////////////////////////////////// function _verifyRegisterSig(address to, address recovery, uint256 deadline, bytes memory sig) internal { _verifySigWithDeadline( _hashTypedDataV4(keccak256(abi.encode(REGISTER_TYPEHASH, to, recovery, _useNonce(to), deadline))), to, deadline, sig ); } function _verifyTransferSig(uint256 rid, address to, uint256 deadline, address signer, bytes memory sig) internal { _verifySigWithDeadline( _hashTypedDataV4(keccak256(abi.encode(TRANSFER_TYPEHASH, rid, to, _useNonce(signer), deadline))), signer, deadline, sig ); } function _verifyTransferAndChangeRecoverySig( uint256 rid, address to, address recovery, uint256 deadline, address signer, bytes memory sig ) internal { _verifySigWithDeadline( _hashTypedDataV4( keccak256( abi.encode(TRANSFER_AND_CHANGE_RECOVERY_TYPEHASH, rid, to, recovery, _useNonce(signer), deadline) ) ), signer, deadline, sig ); } function _verifyChangeRecoveryAddressSig( uint256 rid, address from, address to, uint256 deadline, address signer, bytes memory sig ) internal { _verifySigWithDeadline( _hashTypedDataV4( keccak256(abi.encode(CHANGE_RECOVERY_ADDRESS_TYPEHASH, rid, from, to, _useNonce(signer), deadline)) ), signer, deadline, sig ); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {Pausable} from "@openzeppelin/utils/Pausable.sol"; import {IKeyRegistry} from "./interfaces/IKeyRegistry.sol"; import {IMetadataValidator} from "./interfaces/IMetadataValidator.sol"; import {IdRegistryLike} from "./interfaces/IdRegistryLike.sol"; import {Signatures} from "./abstract/Signatures.sol"; import {EIP712} from "./abstract/EIP712.sol"; import {Nonces} from "./abstract/Nonces.sol"; import {Trust} from "./abstract/Trust.sol"; import {EnumerableKeySet, KeySet} from "./libraries/EnumerableKeySet.sol"; /** * @title KeyRegistry * @author Lifeworld * @notice This contract is a fork of Farcaster KeyRegistry v3.1.0 */ contract KeyRegistry is IKeyRegistry, Trust, Pausable, Signatures, EIP712, Nonces { using EnumerableKeySet for KeySet; //////////////////////////////////////////////////////////////// // CONSTANTS //////////////////////////////////////////////////////////////// string public constant NAME = "River Key Registry"; string public constant VERSION = "2024.07.11"; bytes32 public constant ADD_TYPEHASH = keccak256( "Add(address owner,uint32 keyType,bytes key,uint8 metadataType,bytes metadata,uint256 nonce,uint256 deadline)" ); //////////////////////////////////////////////////////////////// // STORAGE //////////////////////////////////////////////////////////////// IdRegistryLike public idRegistry; uint256 public maxKeysPerRid; /** * @dev Internal enumerable set tracking active keys by rid. */ mapping(uint256 rid => KeySet activeKeys) internal _activeKeysByRid; /** * @dev Internal enumerable set tracking removed keys by rid. */ mapping(uint256 rid => KeySet removedKeys) internal _removedKeysByRid; /** * @dev Mapping of rid to a key to the key's data. * * @custom:param rid The rid associated with the key. * @custom:param key Bytes of the key. * @custom:param data Struct with the state and key type. In the initial migration * all keys will have data.keyType == 1. */ mapping(uint256 rid => mapping(bytes key => KeyData data)) public keys; /** * @dev Mapping of keyType to metadataType to validator contract. * * @custom:param keyType Numeric keyType. * @custom:param metadataType Metadata metadataType. * @custom:param validator Validator contract implementing IMetadataValidator. */ mapping(uint32 keyType => mapping(uint8 metadataType => IMetadataValidator validator)) public validators; //////////////////////////////////////////////////////////////// // CONSTRUCTOR //////////////////////////////////////////////////////////////// /** * @notice Set the IdRegistry and owner. * * @param _idRegistry IdRegistry contract address. * @param _initialOwner Initial owner address. * @param _maxKeysPerRid Maximum number of keys per rid. * */ // solhint-disable-next-line no-empty-blocks constructor( address _idRegistry, address _initialOwner, uint256 _maxKeysPerRid ) Trust(_initialOwner) EIP712("River KeyRegistry", "1") { idRegistry = IdRegistryLike(_idRegistry); maxKeysPerRid = _maxKeysPerRid; emit SetIdRegistry(address(0), _idRegistry); emit SetMaxKeysPerRid(0, _maxKeysPerRid); } //////////////////////////////////////////////////////////////// // REGISTRATION //////////////////////////////////////////////////////////////// function trustedAddFor( address ridOwner, uint32 keyType, bytes calldata key, uint8 metadataType, bytes calldata metadata, uint256 deadline, bytes calldata sig ) external onlyTrustedCaller { // NOTE: not perform any signature checks for rid recipient _add(_ridOf(ridOwner), keyType, key, metadataType, metadata); } function add( uint32 keyType, bytes calldata key, uint8 metadataType, bytes calldata metadata ) external whenNotTrustedOnly { _add(_ridOf(msg.sender), keyType, key, metadataType, metadata); } function addFor( address ridOwner, uint32 keyType, bytes calldata key, uint8 metadataType, bytes calldata metadata, uint256 deadline, bytes calldata sig ) external whenNotTrustedOnly { _verifyAddSig(ridOwner, keyType, key, metadataType, metadata, deadline, sig); _add(_ridOf(ridOwner), keyType, key, metadataType, metadata); } function _add( uint256 rid, uint32 keyType, bytes calldata key, uint8 metadataType, bytes calldata metadata ) internal whenNotPaused { _add(rid, keyType, key, metadataType, metadata, true); } function _add( uint256 rid, uint32 keyType, bytes calldata key, uint8 metadataType, bytes calldata metadata, bool validate ) internal { KeyData storage keyData = keys[rid][key]; if (keyData.state != KeyState.NULL) revert InvalidState(); if (totalKeys(rid, KeyState.ADDED) >= maxKeysPerRid) revert ExceedsMaximum(); IMetadataValidator validator = validators[keyType][metadataType]; if (validator == IMetadataValidator(address(0))) { revert ValidatorNotFound(keyType, metadataType); } _addToKeySet(rid, key); keyData.state = KeyState.ADDED; keyData.keyType = keyType; emit Add(rid, keyType, key, key, metadataType, metadata); // if (validate) { // bool isValid = validator.validate(rid, key, metadata); // if (!isValid) revert InvalidMetadata(); // } } //////////////////////////////////////////////////////////////// // MIGRATION //////////////////////////////////////////////////////////////// // TODO //////////////////////////////////////////////////////////////// // VIEWS //////////////////////////////////////////////////////////////// /** * @inheritdoc IKeyRegistry */ function totalKeys(uint256 rid, KeyState state) public view virtual returns (uint256) { return _keysByState(rid, state).length(); } /** * @inheritdoc IKeyRegistry */ function keyAt(uint256 rid, KeyState state, uint256 index) external view returns (bytes memory) { return _keysByState(rid, state).at(index); } /** * @inheritdoc IKeyRegistry */ function keysOf(uint256 rid, KeyState state) external view returns (bytes[] memory) { return _keysByState(rid, state).values(); } /** * @inheritdoc IKeyRegistry */ function keysOf( uint256 rid, KeyState state, uint256 startIdx, uint256 batchSize ) external view returns (bytes[] memory page, uint256 nextIdx) { KeySet storage _keys = _keysByState(rid, state); uint256 len = _keys.length(); if (startIdx >= len) return (new bytes[](0), 0); uint256 remaining = len - startIdx; uint256 adjustedBatchSize = remaining < batchSize ? remaining : batchSize; page = new bytes[](adjustedBatchSize); for (uint256 i = 0; i < adjustedBatchSize; i++) { page[i] = _keys.at(startIdx + i); } nextIdx = startIdx + adjustedBatchSize; if (nextIdx >= len) nextIdx = 0; return (page, nextIdx); } /** * @inheritdoc IKeyRegistry */ function keyDataOf(uint256 rid, bytes calldata key) external view returns (KeyData memory) { return keys[rid][key]; } //////////////////////////////////////////////////////////////// // REMOVE //////////////////////////////////////////////////////////////// // TODO //////////////////////////////////////////////////////////////// // PERMISSIONED ACTIONS //////////////////////////////////////////////////////////////// /** * @inheritdoc IKeyRegistry */ function setValidator(uint32 keyType, uint8 metadataType, IMetadataValidator validator) external onlyOwner { if (keyType == 0) revert InvalidKeyType(); if (metadataType == 0) revert InvalidMetadataType(); emit SetValidator(keyType, metadataType, address(validators[keyType][metadataType]), address(validator)); validators[keyType][metadataType] = validator; } /** * @inheritdoc IKeyRegistry */ function setIdRegistry(address _idRegistry) external onlyOwner { emit SetIdRegistry(address(idRegistry), _idRegistry); idRegistry = IdRegistryLike(_idRegistry); } /** * @inheritdoc IKeyRegistry */ function setMaxKeysPerRid(uint256 _maxKeysPerRid) external onlyOwner { if (_maxKeysPerRid <= maxKeysPerRid) revert InvalidMaxKeys(); emit SetMaxKeysPerRid(maxKeysPerRid, _maxKeysPerRid); maxKeysPerRid = _maxKeysPerRid; } function pause() external onlyOwner { _pause(); } function unpause() external onlyOwner { _unpause(); } //////////////////////////////////////////////////////////////// // RID HELPERS //////////////////////////////////////////////////////////////// function _ridOf(address ridOwner) internal view returns (uint256 rid) { rid = idRegistry.idOf(ridOwner); if (rid == 0) revert Unauthorized(); } //////////////////////////////////////////////////////////////// // KEY SET HELPERS //////////////////////////////////////////////////////////////// function _addToKeySet(uint256 rid, bytes calldata key) internal virtual { _activeKeysByRid[rid].add(key); } function _removeFromKeySet(uint256 rid, bytes calldata key) internal virtual { _activeKeysByRid[rid].remove(key); _removedKeysByRid[rid].add(key); } function _resetFromKeySet(uint256 rid, bytes calldata key) internal virtual { _activeKeysByRid[rid].remove(key); } function _keysByState(uint256 rid, KeyState state) internal view returns (KeySet storage) { if (state == KeyState.ADDED) { return _activeKeysByRid[rid]; } else if (state == KeyState.REMOVED) { return _removedKeysByRid[rid]; } else { revert InvalidState(); } } //////////////////////////////////////////////////////////////// // SIGNATURE VERIFICATION HELPERS //////////////////////////////////////////////////////////////// function _verifyAddSig( address ridOwner, uint32 keyType, bytes memory key, uint8 metadataType, bytes memory metadata, uint256 deadline, bytes memory sig ) internal { _verifySigWithDeadline( _hashTypedDataV4( keccak256( abi.encode( ADD_TYPEHASH, ridOwner, keyType, keccak256(key), metadataType, keccak256(metadata), _useNonce(ridOwner), deadline ) ) ), ridOwner, deadline, sig ); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; interface IBundler { /*////////////////////////////////////////////////////////////// STRUCTS //////////////////////////////////////////////////////////////*/ /// @notice Data needed to trusted register a signer with the key registry struct SignerData { uint32 keyType; bytes key; uint8 metadataType; bytes metadata; } /// @notice Data needed to register an rid with signature. struct RegistrationParams { address to; address recovery; uint256 deadline; bytes sig; } /// @notice Data needed to add a signer with signature. struct SignerParams { uint32 keyType; bytes key; uint8 metadataType; bytes metadata; uint256 deadline; bytes sig; } /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ /** * @notice Contract version specified in the River protocol version scheme. */ function VERSION() external view returns (string memory); /*////////////////////////////////////////////////////////////// REGISTRATION //////////////////////////////////////////////////////////////*/ /** * @notice Register an rid and multiple signers to an address in a single transaction. * * @param registration Struct containing registration parameters: to, recovery, deadline, and signature. * @param signers Array of structs containing signer parameters: keyType, key, metadataType, metadata, deadline, and signature. * */ function trustedRegister( RegistrationParams calldata registration, SignerParams[] calldata signers ) external payable; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {Ownable2Step} from "@openzeppelin/access/Ownable2Step.sol"; import {Ownable} from "@openzeppelin/access/Ownable.sol"; abstract contract Trust is Ownable2Step { /*////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ /// @dev Revert on array length mismatch error Input_Length_Mismatch(); /// @dev Revert if public register is invoked before trustedCallerOnly is disabled. error Registratable(); /// @dev Revert when an unauthorized caller calls a trusted function. error Only_Trusted(); /// @dev Revert when an invalid address is provided as input. error Invalid_Address(); /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ /** * @dev Emit an event when the trusted caller is modified. * * @param account The address of target account * @param status The status of target account * @param owner The address of the owner setting the new caller. */ event SetTrustedCaller(address indexed account, bool indexed status, address owner); /** * @dev Emit an event when the trustedOnly state is disabled. */ event DisableTrustedOnly(); /*////////////////////////////////////////////////////////////// STORAGE //////////////////////////////////////////////////////////////*/ /** * @dev The privileged address that is allowed to call trusted functions. */ mapping(address => bool) public isTrustedCaller; /** * @dev Allows calling trusted functions when set 1, and disables trusted * functions when set to 0. The value is set to 1 and can be changed to 0, * but never back to 1. */ uint256 public trustedOnly = 1; /*////////////////////////////////////////////////////////////// MODIFIERS //////////////////////////////////////////////////////////////*/ /** * @dev Allow only the trusted caller to call the modified function. */ modifier onlyTrustedCaller() { if (!isTrustedCaller[msg.sender]) revert Only_Trusted(); _; } /** * @dev Allow only the trusted caller to call the modified function. */ modifier whenNotTrustedOnly() { if(!isTrustedCaller[msg.sender]) { if (trustedOnly == 1) revert Registratable(); } _; } /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ /** * @param _initialOwner Initial contract owner address. */ constructor(address _initialOwner) Ownable(_initialOwner) {} /*////////////////////////////////////////////////////////////// PERMISSIONED ACTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Change the trusted caller by calling this from the contract's owner. * * @param accounts Accounts to update trusted caller status * @param statuses Boolean values to update accounts with */ function setTrustedCallers(address[] memory accounts, bool[] memory statuses) public onlyOwner { _setTrustedCallers(accounts, statuses); } /** * @notice Disable trustedOnly mode. Must be called by the contract's owner. */ function disableTrustedOnly() external onlyOwner { delete trustedOnly; emit DisableTrustedOnly(); } /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ /** * @dev Internal helper to set trusted caller. Can be used internally * to set the trusted caller at construction time. */ function _setTrustedCallers(address[] memory _accounts, bool[] memory _statuses) internal { address sender = msg.sender; if (_accounts.length != _statuses.length) revert Input_Length_Mismatch(); for (uint256 i = 0; i < _accounts.length; ++i) { if (_accounts[i] == address(0)) revert Invalid_Address(); isTrustedCaller[_accounts[i]] = _statuses[i]; emit SetTrustedCaller(_accounts[i], _statuses[i], sender); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which allows children to implement an emergency stop * mechanism that can be triggered by an authorized account. * * This module is used through inheritance. It will make available the * modifiers `whenNotPaused` and `whenPaused`, which can be applied to * the functions of your contract. Note that they will not be pausable by * simply including this module, only once the modifiers are put in place. */ abstract contract Pausable is Context { bool private _paused; /** * @dev Emitted when the pause is triggered by `account`. */ event Paused(address account); /** * @dev Emitted when the pause is lifted by `account`. */ event Unpaused(address account); /** * @dev The operation failed because the contract is paused. */ error EnforcedPause(); /** * @dev The operation failed because the contract is not paused. */ error ExpectedPause(); /** * @dev Initializes the contract in unpaused state. */ constructor() { _paused = false; } /** * @dev Modifier to make a function callable only when the contract is not paused. * * Requirements: * * - The contract must not be paused. */ modifier whenNotPaused() { _requireNotPaused(); _; } /** * @dev Modifier to make a function callable only when the contract is paused. * * Requirements: * * - The contract must be paused. */ modifier whenPaused() { _requirePaused(); _; } /** * @dev Returns true if the contract is paused, and false otherwise. */ function paused() public view virtual returns (bool) { return _paused; } /** * @dev Throws if the contract is paused. */ function _requireNotPaused() internal view virtual { if (paused()) { revert EnforcedPause(); } } /** * @dev Throws if the contract is not paused. */ function _requirePaused() internal view virtual { if (!paused()) { revert ExpectedPause(); } } /** * @dev Triggers stopped state. * * Requirements: * * - The contract must not be paused. */ function _pause() internal virtual whenNotPaused { _paused = true; emit Paused(_msgSender()); } /** * @dev Returns to normal state. * * Requirements: * * - The contract must be paused. */ function _unpause() internal virtual whenPaused { _paused = false; emit Unpaused(_msgSender()); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; /** * @title IIdRegistry * @author Lifeworld */ interface IIdRegistry { ////////////////////////////////////////////////// // ERRORS ////////////////////////////////////////////////// /// @dev Revert when the caller does not have the authority to perform the action. error Unauthorized(); /// @dev Revert when the destination must be empty but has an rid. error Has_Id(); /// @dev Revert when the caller must have an rid but does not have one. error Has_No_Id(); ////////////////////////////////////////////////// // EVENTS ////////////////////////////////////////////////// /** * @dev Emit an event when a new River ID is registered. * * Hubs listen for this and update their address-to-rid mapping by adding `to` as the * current owner of `id`. Hubs assume the invariants: * * 1. Two Register events can never emit with the same `id` * * 2. Two Register(alice, ..., ...) cannot emit unless a Transfer(alice, bob, ...) emits * in between, where bob != alice. * * @param to The custody address that owns the rid * @param id The rid that was registered. * @param recovery The address that can initiate a recovery request for the rid. */ event Register(address indexed to, uint256 id, address recovery); /** * @dev Emit an event when an rid is transferred to a new custody address. * * Hubs listen to this event and atomically change the current owner of `id` * from `from` to `to` in their address-to-rid mapping. Hubs assume the invariants: * * 1. A Transfer(..., alice, ...) cannot emit if the most recent event for alice is * Register (alice, ..., ...) * * 2. A Transfer(alice, ..., id) cannot emit unless the most recent event with that id is * Transfer(..., alice, id) or Register(alice, id, ...) * * @param from The custody address that previously owned the rid. * @param to The custody address that now owns the rid. * @param id The rid that was transferred. */ event Transfer(address indexed from, address indexed to, uint256 indexed id); /** * @dev Emit an event when an rid is recovered. * * @param from The custody address that previously owned the rid. * @param to The custody address that now owns the rid. * @param id The rid that was recovered. */ event Recover(address indexed from, address indexed to, uint256 indexed id); /** * @dev Emit an event when a River ID's recovery address changes. It is possible for this * event to emit multiple times in a row with the same recovery address. * * @param id The rid whose recovery address was changed. * @param recovery The new recovery address. */ event ChangeRecoveryAddress(uint256 indexed id, address indexed recovery); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {SignatureCheckerLib} from "@solady/utils/SignatureCheckerLib.sol"; abstract contract Signatures { ////////////////////////////////////////////////// // ERRORS ////////////////////////////////////////////////// /// @dev Revert when the signature provided is invalid. error InvalidSignature(); /// @dev Revert when the block.timestamp is ahead of the signature deadline. error SignatureExpired(); ////////////////////////////////////////////////// // GENERIC HELPERS ////////////////////////////////////////////////// function _verifySig(bytes32 digest, address signer, bytes memory sig) internal { // ERC1271 sig validation for EOAs or accounts with code if (!SignatureCheckerLib.isValidSignatureNow(signer, digest, sig)) { // ERC6492 sig validation for predeploy accounts if (!SignatureCheckerLib.isValidERC6492SignatureNow(signer, digest, sig)) { revert InvalidSignature(); } } } function _verifySigWithDeadline(bytes32 digest, address signer, uint256 deadline, bytes memory sig) internal { if (block.timestamp > deadline) revert SignatureExpired(); // ERC1271 sig validation for EOAs or accounts with code if (!SignatureCheckerLib.isValidSignatureNow(signer, digest, sig)) { // ERC6492 sig validation for predeploy accounts if (!SignatureCheckerLib.isValidERC6492SignatureNow(signer, digest, sig)) { revert InvalidSignature(); } } } function _verifySigWithReturn(bytes32 digest, address signer, bytes memory sig) internal returns (bool) { // ERC1271 sig validation for EOAs or accounts with code if (SignatureCheckerLib.isValidSignatureNow(signer, digest, sig)) return true; // ERC6492 sig validation for predeploy accounts if (SignatureCheckerLib.isValidERC6492SignatureNow(signer, digest, sig)) return true; // Both sig verification attempts failed. Return false return false; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {EIP712 as EIP712Base} from "@openzeppelin/utils/cryptography/EIP712.sol"; abstract contract EIP712 is EIP712Base { constructor(string memory name, string memory version) EIP712Base(name, version) {} ////////////////////////////////////////////////// // EIP-712 HELPERS ////////////////////////////////////////////////// /** * @notice Helper view to read EIP-712 domain separator. * * @return bytes32 domain separator hash. */ function domainSeparatorV4() external view returns (bytes32) { return _domainSeparatorV4(); } /** * @notice Helper view to hash EIP-712 typed data onchain. * * @param structHash EIP-712 typed data hash. * * @return bytes32 EIP-712 message digest. */ function hashTypedDataV4(bytes32 structHash) external view returns (bytes32) { return _hashTypedDataV4(structHash); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; import {Nonces as NoncesBase} from "@openzeppelin/utils/Nonces.sol"; abstract contract Nonces is NoncesBase { ////////////////////////////////////////////////// // NONCE MANAGEMENT ////////////////////////////////////////////////// /** * @notice Increase caller's nonce, invalidating previous signatures. * * @return uint256 The caller's new nonce. */ function useNonce() external returns (uint256) { return _useNonce(msg.sender); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import {IMetadataValidator} from "./IMetadataValidator.sol"; import {IdRegistryLike} from "./IdRegistryLike.sol"; interface IKeyRegistry { /*////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ /// @dev Revert if a key violates KeyState transition rules. error InvalidState(); /// @dev Revert if adding a key exceeds the maximum number of allowed keys per fid. error ExceedsMaximum(); /// @dev Revert if a validator has not been registered for this keyType and metadataType. error ValidatorNotFound(uint32 keyType, uint8 metadataType); /// @dev Revert if metadata validation failed. error InvalidMetadata(); /// @dev Revert if the admin sets a validator for keyType 0. error InvalidKeyType(); /// @dev Revert if the admin sets a validator for metadataType 0. error InvalidMetadataType(); /// @dev Revert if the caller does not have the authority to perform the action. error Unauthorized(); /// @dev Revert if the owner sets maxKeysPerFid equal to or below its current value. error InvalidMaxKeys(); // /// @dev Revert when the gateway dependency is permanently frozen. // error GatewayFrozen(); /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ /** * @dev Emit an event when an admin or rid adds a new key. * * Hubs listen for this, validate that keyBytes is an EdDSA pub key and keyType == 1 and * add keyBytes to its SignerStore. Messages signed by keyBytes with `rid` are now valid * and accepted over gossip, sync and client apis. Hubs assume the invariants: * * 1. Add(rid, ..., key, keyBytes, ...) cannot emit if there is an earlier emit with * Add(rid, ..., key, keyBytes, ...) and no AdminReset(rid, key, keyBytes) inbetween. * * 2. Add(rid, ..., key, keyBytes, ...) cannot emit if there is an earlier emit with * Remove(rid, key, keyBytes). * * 3. For all Add(..., ..., key, keyBytes, ...), key = keccak(keyBytes) * * @param rid The rid associated with the key. * @param keyType The type of the key. * @param key The key being registered. (indexed as hash) * @param keyBytes The bytes of the key being registered. * @param metadataType The type of the metadata. * @param metadata Metadata about the key. */ event Add( uint256 indexed rid, uint32 indexed keyType, bytes indexed key, bytes keyBytes, uint8 metadataType, bytes metadata ); // /** // * @dev Emit an event when an rid removes an added key. // * // * Hubs listen for this, validate that keyType == 1 and keyBytes exists in its SignerStore. // * keyBytes is marked as removed, messages signed by keyBytes with `rid` are invalid, // * dropped immediately and no longer accepted. Hubs assume the invariants: // * // * 1. Remove(rid, key, keyBytes) cannot emit if there is no earlier emit with // * Add(rid, ..., key, keyBytes, ...) // * // * 2. Remove(rid, key, keyBytes) cannot emit if there is an earlier emit with // * Remove(rid, key, keyBytes) // * // * 3. For all Remove(..., key, keyBytes), key = keccak(keyBytes) // * // * @param rid The rid associated with the key. // * @param key The key being registered. (indexed as hash) // * @param keyBytes The bytes of the key being registered. // */ // event Remove(uint256 indexed rid, bytes indexed key, bytes keyBytes); /** * @dev Emit an event when an admin resets an added key. * * Hubs listen for this, validate that keyType == 1 and that keyBytes exists in its SignerStore. * keyBytes is no longer tracked, messages signed by keyBytes with `rid` are invalid, dropped * immediately and not accepted. Hubs assume the following invariants: * * 1. AdminReset(rid, key, keyBytes) cannot emit unless the most recent event for the rid * was Add(rid, ..., key, keyBytes, ...). * * 2. For all AdminReset(..., key, keyBytes), key = keccak(keyBytes). * * 3. AdminReset() cannot emit after Migrated(). * * @param rid The rid associated with the key. * @param key The key being reset. (indexed as hash) * @param keyBytes The bytes of the key being registered. */ event AdminReset(uint256 indexed rid, bytes indexed key, bytes keyBytes); /** * @dev Emit an event when the admin sets a metadata validator contract for a given * keyType and metadataType. * * @param keyType The numeric keyType associated with this validator. * @param metadataType The metadataType associated with this validator. * @param oldValidator The previous validator contract address. * @param newValidator The new validator contract address. */ event SetValidator(uint32 keyType, uint8 metadataType, address oldValidator, address newValidator); /** * @dev Emit an event when the admin sets a new IdRegistry contract address. * * @param oldIdRegistry The previous IdRegistry address. * @param newIdRegistry The new IdRegistry address. */ event SetIdRegistry(address oldIdRegistry, address newIdRegistry); // /** // * @dev Emit an event when the admin sets a new KeyGateway address. // * // * @param oldKeyGateway The previous KeyGateway address. // * @param newKeyGateway The new KeyGateway address. // */ // event SetKeyGateway(address oldKeyGateway, address newKeyGateway); /** * @dev Emit an event when the admin sets a new maximum keys per rid. * * @param oldMax The previous maximum. * @param newMax The new maximum. */ event SetMaxKeysPerRid(uint256 oldMax, uint256 newMax); // /** // * @dev Emit an event when the contract owner permanently freezes the KeyGateway address. // * // * @param keyGateway The permanent KeyGateway address. // */ // event FreezeKeyGateway(address keyGateway); /*////////////////////////////////////////////////////////////// STRUCTS //////////////////////////////////////////////////////////////*/ /** * @notice State enumeration for a key in the registry. During migration, an admin can change * the state of any rids key from NULL to ADDED or ADDED to NULL. After migration, an * rid can change the state of a key from NULL to ADDED or ADDED to REMOVED only. * * - NULL: The key is not in the registry. * - ADDED: The key has been added to the registry. * - REMOVED: The key was added to the registry but is now removed. */ enum KeyState { NULL, ADDED, REMOVED } /** * @notice Data about a key. * * @param state The current state of the key. * @param keyType Numeric ID representing the manner in which the key should be used. */ struct KeyData { KeyState state; uint32 keyType; } /** * @dev Struct argument for bulk add function, representing an RID * and its associated keys. * * @param rid Rid associated with provided keys to add. * @param keys Array of BulkAddKey structs, including key and metadata. */ struct BulkAddData { uint256 rid; BulkAddKey[] keys; } /** * @dev Struct argument for bulk add function, representing a key * and its associated metadata. * * @param key Bytes of the signer key. * @param keys Metadata metadata of the signer key. */ struct BulkAddKey { bytes key; bytes metadata; } /** * @dev Struct argument for bulk reset function, representing an RID * and its associated keys. * * @param rid Rid associated with provided keys to reset. * @param keys Array of keys to reset. */ struct BulkResetData { uint256 rid; bytes[] keys; } /*////////////////////////////////////////////////////////////// CONSTANTS //////////////////////////////////////////////////////////////*/ /** * @notice Contract version specified in the River protocol version scheme. */ function VERSION() external view returns (string memory); // /** // * @notice EIP-712 typehash for Remove signatures. // */ // function REMOVE_TYPEHASH() external view returns (bytes32); /*////////////////////////////////////////////////////////////// STORAGE //////////////////////////////////////////////////////////////*/ /** * @notice The IdRegistry contract. */ function idRegistry() external view returns (IdRegistryLike); // /** // * @notice The KeyGateway address. // */ // function keyGateway() external view returns (address); // /** // * @notice Whether the KeyGateway address is permanently frozen. // */ // function gatewayFrozen() external view returns (bool); /** * @notice Maximum number of keys per rid. */ function maxKeysPerRid() external view returns (uint256); /*////////////////////////////////////////////////////////////// VIEWS //////////////////////////////////////////////////////////////*/ /** * @notice Return number of active keys for a given rid. * * @param rid the rid associated with the keys. * * @return uint256 total number of active keys associated with the rid. */ function totalKeys(uint256 rid, KeyState state) external view returns (uint256); /** * @notice Return key at the given index in the rid's key set. Can be * called to enumerate all active keys for a given rid. * * @param rid the rid associated with the key. * @param index index of the key in the rid's key set. Must be a value * less than totalKeys(rid). Note that because keys are * stored in an underlying enumerable set, the ordering of * keys is not guaranteed to be stable. * * @return bytes Bytes of the key. */ function keyAt(uint256 rid, KeyState state, uint256 index) external view returns (bytes memory); /** * @notice Return an array of all active keys for a given rid. * @dev WARNING: This function will copy the entire key set to memory, * which can be quite expensive. This is intended to be called * offchain with eth_call, not onchain. * * @param rid the rid associated with the keys. * * @return bytes[] Array of all keys. */ function keysOf(uint256 rid, KeyState state) external view returns (bytes[] memory); /** * @notice Return an array of all active keys for a given rid, * paged by index and batch size. * * @param rid The rid associated with the keys. * @param startIdx Start index of lookup. * @param batchSize Number of items to return. * * @return page Array of keys. * @return nextIdx Next index in the set of all keys. */ function keysOf( uint256 rid, KeyState state, uint256 startIdx, uint256 batchSize ) external view returns (bytes[] memory page, uint256 nextIdx); /** * @notice Retrieve state and type data for a given key. * * @param rid The rid associated with the key. * @param key Bytes of the key. * * @return KeyData struct that contains the state and keyType. */ function keyDataOf(uint256 rid, bytes calldata key) external view returns (KeyData memory); /*////////////////////////////////////////////////////////////// REMOVE KEYS //////////////////////////////////////////////////////////////*/ // /** // * @notice Remove a key associated with the caller's rid, setting the key state to REMOVED. // * The key must be in the ADDED state. // * // * @param key Bytes of the key to remove. // */ // function remove(bytes calldata key) external; // /** // * @notice Remove a key on behalf of another rid owner, setting the key state to REMOVED. // * caller must supply a valid EIP-712 Remove signature from the rid owner. // * // * @param ridOwner The rid owner address. // * @param key Bytes of the key to remove. // * @param deadline Deadline after which the signature expires. // * @param sig EIP-712 Remove signature generated by rid owner. // */ // function removeFor(address ridOwner, bytes calldata key, uint256 deadline, bytes calldata sig) external; /*////////////////////////////////////////////////////////////// PERMISSIONED ACTIONS //////////////////////////////////////////////////////////////*/ /** * @notice Add a key associated with the caller's rid, setting the key state to ADDED. * * @param keyType The key's numeric keyType. * @param key Bytes of the key to add. * @param metadataType Metadata type ID. * @param metadata Metadata about the key, which is not stored and only emitted in an event. */ function add(uint32 keyType, bytes calldata key, uint8 metadataType, bytes calldata metadata) external; /** * @notice Add a key on behalf of another rid owner, setting the key state to ADDED. * caller must supply a valid EIP-712 Add signature from the rid owner. * * @param ridOwner The rid owner address. * @param keyType The key's numeric keyType. * @param key Bytes of the key to add. * @param metadataType Metadata type ID. * @param metadata Metadata about the key, which is not stored and only emitted in an event. * @param deadline Deadline after which the signature expires. * @param sig EIP-712 Add signature generated by rid owner. */ function addFor( address ridOwner, uint32 keyType, bytes calldata key, uint8 metadataType, bytes calldata metadata, uint256 deadline, bytes calldata sig ) external; // /** // * @notice Add multiple keys as part of the initial migration. Only callable by the contract owner. // * // * @param items An array of BulkAddData structs including rid and array of BulkAddKey structs. // */ // function bulkAddKeysForMigration(BulkAddData[] calldata items) external; // /** // * @notice Reset multiple keys as part of the initial migration. Only callable by the contract owner. // * Reset is not the same as removal: this function sets the key state back to NULL, // * rather than REMOVED. This allows the owner to correct any errors in the initial migration until // * the grace period expires. // * // * @param items A list of BulkResetData structs including an rid and array of keys. // */ // function bulkResetKeysForMigration(BulkResetData[] calldata items) external; /** * @notice Set a metadata validator contract for the given keyType and metadataType. Only callable by owner. * * @param keyType The numeric key type ID associated with this validator. * @param metadataType The numeric metadata type ID associated with this validator. * @param validator Contract implementing IMetadataValidator. */ function setValidator(uint32 keyType, uint8 metadataType, IMetadataValidator validator) external; /** * @notice Set the IdRegistry contract address. Only callable by owner. * * @param _idRegistry The new IdRegistry address. */ function setIdRegistry(address _idRegistry) external; // /** // * @notice Set the KeyGateway address allowed to add keys. Only callable by owner. // * // * @param _keyGateway The new KeyGateway address. // */ // function setKeyGateway(address _keyGateway) external; // /** // * @notice Permanently freeze the KeyGateway address. Only callable by owner. // */ // function freezeKeyGateway() external; /** * @notice Set the maximum number of keys allowed per rid. Only callable by owner. * * @param _maxKeysPerRid The new max keys per rid. */ function setMaxKeysPerRid(uint256 _maxKeysPerRid) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; interface IMetadataValidator { /** * @notice Validate metadata associated with a key. * * @param userRid The rid associated with the key. * @param key Bytes of the key. * @param metadata Metadata about the key. * * @return bool Whether the provided key and metadata are valid. */ function validate(uint256 userRid, bytes memory key, bytes memory metadata) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; /** * @dev Minimal interface for IdRegistry, used by the KeyRegistry. */ interface IdRegistryLike { /*////////////////////////////////////////////////////////////// STORAGE //////////////////////////////////////////////////////////////*/ /** * @notice Maps each address to an rid, or zero if it does not own an rid. */ function idOf(address ridOwner) external view returns (uint256); /*////////////////////////////////////////////////////////////// VIEWS //////////////////////////////////////////////////////////////*/ /** * @notice Verify that a signature was produced by the custody address that owns an rid. * * @param custodyAddress The address to check the signature of. * @param rid The rid to check the signature of. * @param digest The digest that was signed. * @param sig The signature to check. * * @return isValid Whether provided signature is valid. */ function verifyRidSignature( address custodyAddress, uint256 rid, bytes32 digest, bytes calldata sig ) external view returns (bool isValid); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.23; struct KeySet { // Storage of set values bytes[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes => uint256) _indexes; } /** * @dev Modified from OpenZeppelin v4.9.3 EnumerableSet */ library EnumerableKeySet { /** * @dev Add a key to the set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(KeySet storage set, bytes calldata value) internal returns (bool) { if (!contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a key from the set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(KeySet storage set, bytes calldata value) internal returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; if (lastIndex != toDeleteIndex) { bytes memory lastValue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastValue; // Update the index for the moved value set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex } // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function contains(KeySet storage set, bytes calldata value) internal view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values in the set. O(1). */ function length(KeySet storage set) internal view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(KeySet storage set, uint256 index) internal view returns (bytes memory) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(KeySet storage set) internal view returns (bytes[] memory) { return set._values; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.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. */ 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); } }
// 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); } }
// 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; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Signature verification helper that supports both ECDSA signatures from EOAs /// and ERC1271 signatures from smart contract wallets like Argent and Gnosis safe. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SignatureCheckerLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol) /// /// @dev Note: /// - The signature checking functions use the ecrecover precompile (0x1). /// - The `bytes memory signature` variants use the identity precompile (0x4) /// to copy memory internally. /// - Unlike ECDSA signatures, contract signatures are revocable. /// - As of Solady version 0.0.134, all `bytes signature` variants accept both /// regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures. /// See: https://eips.ethereum.org/EIPS/eip-2098 /// This is for calldata efficiency on smart accounts prevalent on L2s. /// /// WARNING! Do NOT use signatures as unique identifiers: /// - Use a nonce in the digest to prevent replay attacks on the same contract. /// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts. /// EIP-712 also enables readable signing of typed data for better user safety. /// This implementation does NOT check if a signature is non-malleable. library SignatureCheckerLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIGNATURE CHECKING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `signature` is valid for `signer` and `hash`. /// If `signer` is a smart contract, the signature is validated with ERC1271. /// Otherwise, the signature is validated with `ECDSA.recover`. function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits of `signer` in case they are dirty. for { signer := shr(96, shl(96, signer)) } signer {} { let m := mload(0x40) mstore(0x00, hash) mstore(0x40, mload(add(signature, 0x20))) // `r`. if eq(mload(signature), 64) { let vs := mload(add(signature, 0x40)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x60, shr(1, shl(1, vs))) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } if eq(mload(signature), 65) { mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. mstore(0x60, mload(add(signature, 0x40))) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. // Copy the `signature` over. let n := add(0x20, mload(signature)) pop(staticcall(gas(), 4, signature, n, add(m, 0x44), n)) // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. add(returndatasize(), 0x44), // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) break } } } /// @dev Returns whether `signature` is valid for `signer` and `hash`. /// If `signer` is a smart contract, the signature is validated with ERC1271. /// Otherwise, the signature is validated with `ECDSA.recover`. function isValidSignatureNowCalldata(address signer, bytes32 hash, bytes calldata signature) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits of `signer` in case they are dirty. for { signer := shr(96, shl(96, signer)) } signer {} { let m := mload(0x40) mstore(0x00, hash) if eq(signature.length, 64) { let vs := calldataload(add(signature.offset, 0x20)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, calldataload(signature.offset)) // `r`. mstore(0x60, shr(1, shl(1, vs))) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } if eq(signature.length, 65) { mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. calldatacopy(0x40, signature.offset, 0x40) // `r`, `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), signature.length) // Copy the `signature` over. calldatacopy(add(m, 0x64), signature.offset, signature.length) // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. add(signature.length, 0x64), // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) break } } } /// @dev Returns whether the signature (`r`, `vs`) is valid for `signer` and `hash`. /// If `signer` is a smart contract, the signature is validated with ERC1271. /// Otherwise, the signature is validated with `ECDSA.recover`. function isValidSignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits of `signer` in case they are dirty. for { signer := shr(96, shl(96, signer)) } signer {} { let m := mload(0x40) mstore(0x00, hash) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, r) // `r`. mstore(0x60, shr(1, shl(1, vs))) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), mload(0x60)) // `s`. mstore8(add(m, 0xa4), mload(0x20)) // `v`. // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. 0xa5, // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } } /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `signer` and `hash`. /// If `signer` is a smart contract, the signature is validated with ERC1271. /// Otherwise, the signature is validated with `ECDSA.recover`. function isValidSignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits of `signer` in case they are dirty. for { signer := shr(96, shl(96, signer)) } signer {} { let m := mload(0x40) mstore(0x00, hash) mstore(0x20, and(v, 0xff)) // `v`. mstore(0x40, r) // `r`. mstore(0x60, s) // `s`. let t := staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) { isValid := 1 mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), s) // `s`. mstore8(add(m, 0xa4), v) // `v`. // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. 0xa5, // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1271 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: These ERC1271 operations do NOT have an ECDSA fallback. // These functions are intended to be used with the regular `isValidSignatureNow` functions // or other signature verification functions (e.g. P256). /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract. function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. // Copy the `signature` over. let n := add(0x20, mload(signature)) pop(staticcall(gas(), 4, signature, n, add(m, 0x44), n)) // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. add(returndatasize(), 0x44), // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) } } /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract. function isValidERC1271SignatureNowCalldata( address signer, bytes32 hash, bytes calldata signature ) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), signature.length) // Copy the `signature` over. calldatacopy(add(m, 0x64), signature.offset, signature.length) // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. add(signature.length, 0x64), // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) } } /// @dev Returns whether the signature (`r`, `vs`) is valid for `hash` /// for an ERC1271 `signer` contract. function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`. mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`. // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. 0xa5, // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) } } /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `hash` /// for an ERC1271 `signer` contract. function isValidERC1271SignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), s) // `s`. mstore8(add(m, 0xa4), v) // `v`. // forgefmt: disable-next-item isValid := and( // Whether the returndata is the magic value `0x1626ba7e` (left-aligned). eq(mload(d), f), // Whether the staticcall does not revert. // This must be placed at the end of the `and` clause, // as the arguments are evaluated from right to left. staticcall( gas(), // Remaining gas. signer, // The `signer` address. m, // Offset of calldata in memory. 0xa5, // Length of calldata in memory. d, // Offset of returndata. 0x20 // Length of returndata to write. ) ) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC6492 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: These ERC6492 operations do NOT have an ECDSA fallback. // These functions are intended to be used with the regular `isValidSignatureNow` functions // or other signature verification functions (e.g. P256). // The calldata variants are excluded for brevity. /// @dev Returns whether `signature` is valid for `hash`. /// If the signature is postfixed with the ERC6492 magic number, it will attempt to /// deploy / prepare the `signer` smart account before doing a regular ERC1271 check. /// Note: This function is NOT reentrancy safe. function isValidERC6492SignatureNowAllowSideEffects( address signer, bytes32 hash, bytes memory signature ) internal returns (bool isValid) { /// @solidity memory-safe-assembly assembly { function callIsValidSignature(signer_, hash_, signature_) -> _isValid { let m_ := mload(0x40) let f_ := shl(224, 0x1626ba7e) mstore(m_, f_) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m_, 0x04), hash_) let d_ := add(m_, 0x24) mstore(d_, 0x40) // The offset of the `signature` in the calldata. let n_ := add(0x20, mload(signature_)) pop(staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_)) _isValid := and( eq(mload(d_), f_), staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20) ) } for { let n := mload(signature) } 1 {} { if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) { isValid := callIsValidSignature(signer, hash, signature) break } let o := add(signature, 0x20) // Signature bytes. let d := add(o, mload(add(o, 0x20))) // Factory calldata. if iszero(extcodesize(signer)) { if iszero(call(gas(), mload(o), 0, add(d, 0x20), mload(d), codesize(), 0x00)) { break } } let s := add(o, mload(add(o, 0x40))) // Inner signature. isValid := callIsValidSignature(signer, hash, s) if iszero(isValid) { if call(gas(), mload(o), 0, add(d, 0x20), mload(d), codesize(), 0x00) { isValid := callIsValidSignature(signer, hash, s) } } break } } } /// @dev Returns whether `signature` is valid for `hash`. /// If the signature is postfixed with the ERC6492 magic number, it will attempt /// to use a reverting verifier to deploy / prepare the `signer` smart account /// and do a `isValidSignature` check via the reverting verifier. /// Note: This function is reentrancy safe. /// The reverting verifier must be deployed. /// Otherwise, the function will return false if `signer` is not yet deployed / prepared. /// See: https://gist.github.com/Vectorized/846a474c855eee9e441506676800a9ad function isValidERC6492SignatureNow(address signer, bytes32 hash, bytes memory signature) internal returns (bool isValid) { /// @solidity memory-safe-assembly assembly { function callIsValidSignature(signer_, hash_, signature_) -> _isValid { let m_ := mload(0x40) let f_ := shl(224, 0x1626ba7e) mstore(m_, f_) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m_, 0x04), hash_) let d_ := add(m_, 0x24) mstore(d_, 0x40) // The offset of the `signature` in the calldata. let n_ := add(0x20, mload(signature_)) pop(staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_)) _isValid := and( eq(mload(d_), f_), staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20) ) } for { let n := mload(signature) } 1 {} { if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) { isValid := callIsValidSignature(signer, hash, signature) break } if extcodesize(signer) { let o := add(signature, 0x20) // Signature bytes. isValid := callIsValidSignature(signer, hash, add(o, mload(add(o, 0x40)))) if isValid { break } } let m := mload(0x40) mstore(m, signer) mstore(add(m, 0x20), hash) let willBeZeroIfRevertingVerifierExists := call( gas(), // Remaining gas. 0x00007bd799e4A591FeA53f8A8a3E9f931626Ba7e, // Reverting verifier. 0, // Send zero ETH. m, // Start of memory. add(returndatasize(), 0x40), // Length of calldata in memory. staticcall(gas(), 4, add(signature, 0x20), n, add(m, 0x40), n), // 1. 0x00 // Length of returndata to write. ) isValid := gt(returndatasize(), willBeZeroIfRevertingVerifierExists) break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HASHING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an Ethereum Signed Message, created from a `hash`. /// This produces a hash corresponding to the one signed with the /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) /// JSON-RPC method as part of EIP-191. function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, hash) // Store into scratch space for keccak256. mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes. result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`. } } /// @dev Returns an Ethereum Signed Message, created from `s`. /// This produces a hash corresponding to the one signed with the /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) /// JSON-RPC method as part of EIP-191. /// Note: Supports lengths of `s` up to 999999 bytes. function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let sLength := mload(s) let o := 0x20 mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded. mstore(0x00, 0x00) // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`. for { let temp := sLength } 1 {} { o := sub(o, 1) mstore8(o, add(48, mod(temp, 10))) temp := div(temp, 10) if iszero(temp) { break } } let n := sub(0x3a, o) // Header length: `26 + 32 - o`. // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes. returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20)) mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header. result := keccak256(add(s, sub(0x20, n)), add(n, sLength)) mstore(s, sLength) // Restore the length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EMPTY CALLDATA HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an empty calldata bytes. function emptySignature() internal pure returns (bytes calldata signature) { /// @solidity memory-safe-assembly assembly { signature.length := 0 } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol) pragma solidity ^0.8.20; import {MessageHashUtils} from "./MessageHashUtils.sol"; import {ShortStrings, ShortString} from "../ShortStrings.sol"; import {IERC5267} from "../../interfaces/IERC5267.sol"; /** * @dev https://eips.ethereum.org/EIPS/eip-712[EIP-712] is a standard for hashing and signing of typed structured data. * * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`. * * This contract implements the EIP-712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA * ({_hashTypedDataV4}). * * The implementation of the domain separator was designed to be as efficient as possible while still properly updating * the chain id to protect against replay attacks on an eventual fork of the chain. * * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask]. * * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the * separator from the immutable values, which is cheaper than accessing a cached version in cold storage. * * @custom:oz-upgrades-unsafe-allow state-variable-immutable */ abstract contract EIP712 is IERC5267 { using ShortStrings for *; bytes32 private constant TYPE_HASH = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to // invalidate the cached domain separator if the chain id changes. bytes32 private immutable _cachedDomainSeparator; uint256 private immutable _cachedChainId; address private immutable _cachedThis; bytes32 private immutable _hashedName; bytes32 private immutable _hashedVersion; ShortString private immutable _name; ShortString private immutable _version; string private _nameFallback; string private _versionFallback; /** * @dev Initializes the domain separator and parameter caches. * * The meaning of `name` and `version` is specified in * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP-712]: * * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. * - `version`: the current major version of the signing domain. * * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart * contract upgrade]. */ constructor(string memory name, string memory version) { _name = name.toShortStringWithFallback(_nameFallback); _version = version.toShortStringWithFallback(_versionFallback); _hashedName = keccak256(bytes(name)); _hashedVersion = keccak256(bytes(version)); _cachedChainId = block.chainid; _cachedDomainSeparator = _buildDomainSeparator(); _cachedThis = address(this); } /** * @dev Returns the domain separator for the current chain. */ function _domainSeparatorV4() internal view returns (bytes32) { if (address(this) == _cachedThis && block.chainid == _cachedChainId) { return _cachedDomainSeparator; } else { return _buildDomainSeparator(); } } function _buildDomainSeparator() private view returns (bytes32) { return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); } /** * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this * function returns the hash of the fully encoded EIP712 message for this domain. * * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: * * ```solidity * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( * keccak256("Mail(address to,string contents)"), * mailTo, * keccak256(bytes(mailContents)) * ))); * address signer = ECDSA.recover(digest, signature); * ``` */ function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash); } /** * @dev See {IERC-5267}. */ function eip712Domain() public view virtual returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { return ( hex"0f", // 01111 _EIP712Name(), _EIP712Version(), block.chainid, address(this), bytes32(0), new uint256[](0) ); } /** * @dev The name parameter for the EIP712 domain. * * NOTE: By default this function reads _name which is an immutable value. * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). */ // solhint-disable-next-line func-name-mixedcase function _EIP712Name() internal view returns (string memory) { return _name.toStringWithFallback(_nameFallback); } /** * @dev The version parameter for the EIP712 domain. * * NOTE: By default this function reads _version which is an immutable value. * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). */ // solhint-disable-next-line func-name-mixedcase function _EIP712Version() internal view returns (string memory) { return _version.toStringWithFallback(_versionFallback); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol) pragma solidity ^0.8.20; /** * @dev Provides tracking nonces for addresses. Nonces will only increment. */ abstract contract Nonces { /** * @dev The nonce used for an `account` is not the expected current nonce. */ error InvalidAccountNonce(address account, uint256 currentNonce); mapping(address account => uint256) private _nonces; /** * @dev Returns the next unused nonce for an address. */ function nonces(address owner) public view virtual returns (uint256) { return _nonces[owner]; } /** * @dev Consumes a nonce. * * Returns the current value and increments nonce. */ function _useNonce(address owner) internal virtual returns (uint256) { // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be // decremented or reset. This guarantees that the nonce never overflows. unchecked { // It is important to do x++ and not ++x here. return _nonces[owner]++; } } /** * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`. */ function _useCheckedNonce(address owner, uint256 nonce) internal virtual { uint256 current = _useNonce(owner); if (nonce != current) { revert InvalidAccountNonce(owner, current); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol) pragma solidity ^0.8.20; import {Strings} from "../Strings.sol"; /** * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. * * The library provides methods for generating a hash of a message that conforms to the * https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] * specifications. */ library MessageHashUtils { /** * @dev Returns the keccak256 digest of an ERC-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing a bytes32 `messageHash` with * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with * keccak256, although any bytes32 value can be safely used because the final digest will * be re-hashed. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20) } } /** * @dev Returns the keccak256 digest of an ERC-191 signed data with version * `0x45` (`personal_sign` messages). * * The digest is calculated by prefixing an arbitrary `message` with * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. * * See {ECDSA-recover}. */ function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) { return keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message)); } /** * @dev Returns the keccak256 digest of an ERC-191 signed data with version * `0x00` (data with intended validator). * * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended * `validator` address. Then hashing the result. * * See {ECDSA-recover}. */ function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { return keccak256(abi.encodePacked(hex"19_00", validator, data)); } /** * @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`). * * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with * `\x19\x01` and hashing the result. It corresponds to the hash signed by the * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. * * See {ECDSA-recover}. */ function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(ptr, hex"19_01") mstore(add(ptr, 0x02), domainSeparator) mstore(add(ptr, 0x22), structHash) digest := keccak256(ptr, 0x42) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol) pragma solidity ^0.8.20; import {StorageSlot} from "./StorageSlot.sol"; // | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | // | length | 0x BB | type ShortString is bytes32; /** * @dev This library provides functions to convert short memory strings * into a `ShortString` type that can be used as an immutable variable. * * Strings of arbitrary length can be optimized using this library if * they are short enough (up to 31 bytes) by packing them with their * length (1 byte) in a single EVM word (32 bytes). Additionally, a * fallback mechanism can be used for every other case. * * Usage example: * * ```solidity * contract Named { * using ShortStrings for *; * * ShortString private immutable _name; * string private _nameFallback; * * constructor(string memory contractName) { * _name = contractName.toShortStringWithFallback(_nameFallback); * } * * function name() external view returns (string memory) { * return _name.toStringWithFallback(_nameFallback); * } * } * ``` */ library ShortStrings { // Used as an identifier for strings longer than 31 bytes. bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; error StringTooLong(string str); error InvalidShortString(); /** * @dev Encode a string of at most 31 chars into a `ShortString`. * * This will trigger a `StringTooLong` error is the input string is too long. */ function toShortString(string memory str) internal pure returns (ShortString) { bytes memory bstr = bytes(str); if (bstr.length > 31) { revert StringTooLong(str); } return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length)); } /** * @dev Decode a `ShortString` back to a "normal" string. */ function toString(ShortString sstr) internal pure returns (string memory) { uint256 len = byteLength(sstr); // using `new string(len)` would work locally but is not memory safe. string memory str = new string(32); /// @solidity memory-safe-assembly assembly { mstore(str, len) mstore(add(str, 0x20), sstr) } return str; } /** * @dev Return the length of a `ShortString`. */ function byteLength(ShortString sstr) internal pure returns (uint256) { uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; if (result > 31) { revert InvalidShortString(); } return result; } /** * @dev Encode a string into a `ShortString`, or write it to storage if it is too long. */ function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) { if (bytes(value).length < 32) { return toShortString(value); } else { StorageSlot.getStringSlot(store).value = value; return ShortString.wrap(FALLBACK_SENTINEL); } } /** * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}. */ function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) { if (ShortString.unwrap(value) != FALLBACK_SENTINEL) { return toString(value); } else { return store; } } /** * @dev Return the length of a string that was encoded to `ShortString` or written to storage using * {setWithFallback}. * * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of * actual characters as the UTF-8 encoding of a single character can span over multiple bytes. */ function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) { if (ShortString.unwrap(value) != FALLBACK_SENTINEL) { return byteLength(value); } else { return bytes(store).length; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol) pragma solidity ^0.8.20; interface IERC5267 { /** * @dev MAY be emitted to signal that the domain could have changed. */ event EIP712DomainChanged(); /** * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712 * signature. */ function eip712Domain() external view returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) pragma solidity ^0.8.20; import {Math} from "./math/Math.sol"; import {SignedMath} from "./math/SignedMath.sol"; /** * @dev String operations. */ library Strings { bytes16 private constant HEX_DIGITS = "0123456789abcdef"; uint8 private constant ADDRESS_LENGTH = 20; /** * @dev The `value` string doesn't fit in the specified `length`. */ error StringsInsufficientHexLength(uint256 value, uint256 length); /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = Math.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toStringSigned(int256 value) internal pure returns (string memory) { return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, Math.log256(value) + 1); } } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. */ function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { uint256 localValue = value; bytes memory buffer = new bytes(2 * length + 2); buffer[0] = "0"; buffer[1] = "x"; for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_DIGITS[localValue & 0xf]; localValue >>= 4; } if (localValue != 0) { revert StringsInsufficientHexLength(value, length); } return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal * representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol) // This file was procedurally generated from scripts/generate/templates/StorageSlot.js. pragma solidity ^0.8.20; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC-1967 implementation slot: * ```solidity * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(newImplementation.code.length > 0); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } struct StringSlot { string value; } struct BytesSlot { bytes value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` with member `value` located at `slot`. */ function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `StringSlot` representation of the string storage pointer `store`. */ function getStringSlot(string storage store) internal pure returns (StringSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } /** * @dev Returns an `BytesSlot` with member `value` located at `slot`. */ function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`. */ function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := store.slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) pragma solidity ^0.8.20; import {Panic} from "../Panic.sol"; import {SafeCast} from "./SafeCast.sol"; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Floor, // Toward negative infinity Ceil, // Toward positive infinity Trunc, // Toward zero Expand // Away from zero } /** * @dev Returns the addition of two unsigned integers, with an success flag (no overflow). */ function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { uint256 c = a + b; if (c < a) return (false, 0); return (true, c); } } /** * @dev Returns the subtraction of two unsigned integers, with an success flag (no overflow). */ function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b > a) return (false, 0); return (true, a - b); } } /** * @dev Returns the multiplication of two unsigned integers, with an success flag (no overflow). */ function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) return (true, 0); uint256 c = a * b; if (c / a != b) return (false, 0); return (true, c); } } /** * @dev Returns the division of two unsigned integers, with a success flag (no division by zero). */ function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a / b); } } /** * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero). */ function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) { unchecked { if (b == 0) return (false, 0); return (true, a % b); } } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds towards infinity instead * of rounding towards zero. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { if (b == 0) { // Guarantee the same behavior as in a regular Solidity division. Panic.panic(Panic.DIVISION_BY_ZERO); } // The following calculation ensures accurate ceiling division without overflow. // Since a is non-zero, (a - 1) / b will not overflow. // The largest possible result occurs when (a - 1) / b is type(uint256).max, // but the largest value we can obtain is type(uint256).max - 1, which happens // when a = type(uint256).max and b = 1. unchecked { return a == 0 ? 0 : (a - 1) / b + 1; } } /** * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or * denominator == 0. * * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by * Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2²⁵⁶ + prod0. uint256 prod0 = x * y; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0. if (denominator <= prod1) { Panic.panic(denominator == 0 ? Panic.DIVISION_BY_ZERO : Panic.UNDER_OVERFLOW); } /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. uint256 twos = denominator & (0 - denominator); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv ≡ 1 mod 2⁴. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also // works in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2⁸ inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶ inverse *= 2 - denominator * inverse; // inverse mod 2³² inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴ inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸ inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶ // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @dev Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0); } /** * @dev Calculate the modular multiplicative inverse of a number in Z/nZ. * * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, expect 0. * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible. * * If the input value is not inversible, 0 is returned. * * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Ferma's little theorem and get the * inverse using `Math.modExp(a, n - 2, n)`. */ function invMod(uint256 a, uint256 n) internal pure returns (uint256) { unchecked { if (n == 0) return 0; // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version) // Used to compute integers x and y such that: ax + ny = gcd(a, n). // When the gcd is 1, then the inverse of a modulo n exists and it's x. // ax + ny = 1 // ax = 1 + (-y)n // ax ≡ 1 (mod n) # x is the inverse of a modulo n // If the remainder is 0 the gcd is n right away. uint256 remainder = a % n; uint256 gcd = n; // Therefore the initial coefficients are: // ax + ny = gcd(a, n) = n // 0a + 1n = n int256 x = 0; int256 y = 1; while (remainder != 0) { uint256 quotient = gcd / remainder; (gcd, remainder) = ( // The old remainder is the next gcd to try. remainder, // Compute the next remainder. // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd // where gcd is at most n (capped to type(uint256).max) gcd - remainder * quotient ); (x, y) = ( // Increment the coefficient of a. y, // Decrement the coefficient of n. // Can overflow, but the result is casted to uint256 so that the // next value of y is "wrapped around" to a value between 0 and n - 1. x - y * int256(quotient) ); } if (gcd != 1) return 0; // No inverse exists. return x < 0 ? (n - uint256(-x)) : uint256(x); // Wrap the result if it's negative. } } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m) * * Requirements: * - modulus can't be zero * - underlying staticcall to precompile must succeed * * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make * sure the chain you're using it on supports the precompiled contract for modular exponentiation * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, * the underlying function will succeed given the lack of a revert, but the result may be incorrectly * interpreted as 0. */ function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) { (bool success, uint256 result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m). * It includes a success flag indicating if the operation succeeded. Operation will be marked has failed if trying * to operate modulo 0 or if the underlying precompile reverted. * * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack * of a revert, but the result may be incorrectly interpreted as 0. */ function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) { if (m == 0) return (false, 0); /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) // | Offset | Content | Content (Hex) | // |-----------|------------|--------------------------------------------------------------------| // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 | // | 0x60:0x7f | value of b | 0x<.............................................................b> | // | 0x80:0x9f | value of e | 0x<.............................................................e> | // | 0xa0:0xbf | value of m | 0x<.............................................................m> | mstore(ptr, 0x20) mstore(add(ptr, 0x20), 0x20) mstore(add(ptr, 0x40), 0x20) mstore(add(ptr, 0x60), b) mstore(add(ptr, 0x80), e) mstore(add(ptr, 0xa0), m) // Given the result < m, it's guaranteed to fit in 32 bytes, // so we can use the memory scratch space located at offset 0. success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20) result := mload(0x00) } } /** * @dev Variant of {modExp} that supports inputs of arbitrary length. */ function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) { (bool success, bytes memory result) = tryModExp(b, e, m); if (!success) { Panic.panic(Panic.DIVISION_BY_ZERO); } return result; } /** * @dev Variant of {tryModExp} that supports inputs of arbitrary length. */ function tryModExp( bytes memory b, bytes memory e, bytes memory m ) internal view returns (bool success, bytes memory result) { if (_zeroBytes(m)) return (false, new bytes(0)); uint256 mLen = m.length; // Encode call args in result and move the free memory pointer result = abi.encodePacked(b.length, e.length, mLen, b, e, m); /// @solidity memory-safe-assembly assembly { let dataPtr := add(result, 0x20) // Write result on top of args to avoid allocating extra memory. success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen) // Overwrite the length. // result.length > returndatasize() is guaranteed because returndatasize() == m.length mstore(result, mLen) // Set the memory pointer after the returned data. mstore(0x40, add(dataPtr, mLen)) } } /** * @dev Returns whether the provided byte array is zero. */ function _zeroBytes(bytes memory byteArray) private pure returns (bool) { for (uint256 i = 0; i < byteArray.length; ++i) { if (byteArray[i] != 0) { return false; } } return true; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded * towards zero. * * This method is based on Newton's method for computing square roots; the algorithm is restricted to only * using integer operations. */ function sqrt(uint256 a) internal pure returns (uint256) { unchecked { // Take care of easy edge cases when a == 0 or a == 1 if (a <= 1) { return a; } // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between // the current value as `ε_n = | x_n - sqrt(a) |`. // // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is // bigger than any uint256. // // By noticing that // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)` // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar // to the msb function. uint256 aa = a; uint256 xn = 1; if (aa >= (1 << 128)) { aa >>= 128; xn <<= 64; } if (aa >= (1 << 64)) { aa >>= 64; xn <<= 32; } if (aa >= (1 << 32)) { aa >>= 32; xn <<= 16; } if (aa >= (1 << 16)) { aa >>= 16; xn <<= 8; } if (aa >= (1 << 8)) { aa >>= 8; xn <<= 4; } if (aa >= (1 << 4)) { aa >>= 4; xn <<= 2; } if (aa >= (1 << 2)) { xn <<= 1; } // We now have x_n such that `x_n = 2**(e-1) ≤ sqrt(a) < 2**e = 2 * x_n`. This implies ε_n ≤ 2**(e-1). // // We can refine our estimation by noticing that the the middle of that interval minimizes the error. // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2). // This is going to be our x_0 (and ε_0) xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2) // From here, Newton's method give us: // x_{n+1} = (x_n + a / x_n) / 2 // // One should note that: // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a // = ((x_n² + a) / (2 * x_n))² - a // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²) // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²) // = (x_n² - a)² / (2 * x_n)² // = ((x_n² - a) / (2 * x_n))² // ≥ 0 // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n // // This gives us the proof of quadratic convergence of the sequence: // ε_{n+1} = | x_{n+1} - sqrt(a) | // = | (x_n + a / x_n) / 2 - sqrt(a) | // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) | // = | (x_n - sqrt(a))² / (2 * x_n) | // = | ε_n² / (2 * x_n) | // = ε_n² / | (2 * x_n) | // // For the first iteration, we have a special case where x_0 is known: // ε_1 = ε_0² / | (2 * x_0) | // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2))) // ≤ 2**(2*e-4) / (3 * 2**(e-1)) // ≤ 2**(e-3) / 3 // ≤ 2**(e-3-log2(3)) // ≤ 2**(e-4.5) // // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n: // ε_{n+1} = ε_n² / | (2 * x_n) | // ≤ (2**(e-k))² / (2 * 2**(e-1)) // ≤ 2**(2*e-2*k) / 2**e // ≤ 2**(e-2*k) xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5 xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9 xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18 xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36 xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72 // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either // sqrt(a) or sqrt(a) + 1. return xn - SafeCast.toUint(xn > a / xn); } } /** * @dev Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a); } } /** * @dev Return the log in base 2 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; uint256 exp; unchecked { exp = 128 * SafeCast.toUint(value > (1 << 128) - 1); value >>= exp; result += exp; exp = 64 * SafeCast.toUint(value > (1 << 64) - 1); value >>= exp; result += exp; exp = 32 * SafeCast.toUint(value > (1 << 32) - 1); value >>= exp; result += exp; exp = 16 * SafeCast.toUint(value > (1 << 16) - 1); value >>= exp; result += exp; exp = 8 * SafeCast.toUint(value > (1 << 8) - 1); value >>= exp; result += exp; exp = 4 * SafeCast.toUint(value > (1 << 4) - 1); value >>= exp; result += exp; exp = 2 * SafeCast.toUint(value > (1 << 2) - 1); value >>= exp; result += exp; result += SafeCast.toUint(value > 1); } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value); } } /** * @dev Return the log in base 10 of a positive value rounded towards zero. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value); } } /** * @dev Return the log in base 256 of a positive value rounded towards zero. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; uint256 isGt; unchecked { isGt = SafeCast.toUint(value > (1 << 128) - 1); value >>= isGt * 128; result += isGt * 16; isGt = SafeCast.toUint(value > (1 << 64) - 1); value >>= isGt * 64; result += isGt * 8; isGt = SafeCast.toUint(value > (1 << 32) - 1); value >>= isGt * 32; result += isGt * 4; isGt = SafeCast.toUint(value > (1 << 16) - 1); value >>= isGt * 16; result += isGt * 2; result += SafeCast.toUint(value > (1 << 8) - 1); } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value); } } /** * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. */ function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { return uint8(rounding) % 2 == 1; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.20; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMath { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // Formula from the "Bit Twiddling Hacks" by Sean Eron Anderson. // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift, // taking advantage of the most significant (or "sign" bit) in two's complement representation. // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result, // the mask will either be `bytes(0)` (if n is positive) or `~bytes32(0)` (if n is negative). int256 mask = n >> 255; // A `bytes(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it. return uint256((n + mask) ^ mask); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /** * @dev Helper library for emitting standardized panic codes. * * ```solidity * contract Example { * using Panic for uint256; * * // Use any of the declared internal constants * function foo() { Panic.GENERIC.panic(); } * * // Alternatively * function foo() { Panic.panic(Panic.GENERIC); } * } * ``` * * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil]. */ // slither-disable-next-line unused-state library Panic { /// @dev generic / unspecified error uint256 internal constant GENERIC = 0x00; /// @dev used by the assert() builtin uint256 internal constant ASSERT = 0x01; /// @dev arithmetic underflow or overflow uint256 internal constant UNDER_OVERFLOW = 0x11; /// @dev division or modulo by zero uint256 internal constant DIVISION_BY_ZERO = 0x12; /// @dev enum conversion error uint256 internal constant ENUM_CONVERSION_ERROR = 0x21; /// @dev invalid encoding in storage uint256 internal constant STORAGE_ENCODING_ERROR = 0x22; /// @dev empty array pop uint256 internal constant EMPTY_ARRAY_POP = 0x31; /// @dev array out of bounds access uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32; /// @dev resource error (too large allocation or too large array) uint256 internal constant RESOURCE_ERROR = 0x41; /// @dev calling invalid internal function uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51; /// @dev Reverts with a panic code. Recommended to use with /// the internal constants with predefined codes. function panic(uint256 code) internal pure { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x4e487b71) mstore(0x20, code) revert(0x1c, 0x24) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol) // This file was procedurally generated from scripts/generate/templates/SafeCast.js. pragma solidity ^0.8.20; /** * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow * checks. * * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can * easily result in undesired exploitation or bugs, since developers usually * assume that overflows raise errors. `SafeCast` restores this intuition by * reverting the transaction when such an operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeCast { /** * @dev Value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); /** * @dev An int value doesn't fit in an uint of `bits` size. */ error SafeCastOverflowedIntToUint(int256 value); /** * @dev Value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); /** * @dev An uint value doesn't fit in an int of `bits` size. */ error SafeCastOverflowedUintToInt(uint256 value); /** * @dev Returns the downcasted uint248 from uint256, reverting on * overflow (when the input is greater than largest uint248). * * Counterpart to Solidity's `uint248` operator. * * Requirements: * * - input must fit into 248 bits */ function toUint248(uint256 value) internal pure returns (uint248) { if (value > type(uint248).max) { revert SafeCastOverflowedUintDowncast(248, value); } return uint248(value); } /** * @dev Returns the downcasted uint240 from uint256, reverting on * overflow (when the input is greater than largest uint240). * * Counterpart to Solidity's `uint240` operator. * * Requirements: * * - input must fit into 240 bits */ function toUint240(uint256 value) internal pure returns (uint240) { if (value > type(uint240).max) { revert SafeCastOverflowedUintDowncast(240, value); } return uint240(value); } /** * @dev Returns the downcasted uint232 from uint256, reverting on * overflow (when the input is greater than largest uint232). * * Counterpart to Solidity's `uint232` operator. * * Requirements: * * - input must fit into 232 bits */ function toUint232(uint256 value) internal pure returns (uint232) { if (value > type(uint232).max) { revert SafeCastOverflowedUintDowncast(232, value); } return uint232(value); } /** * @dev Returns the downcasted uint224 from uint256, reverting on * overflow (when the input is greater than largest uint224). * * Counterpart to Solidity's `uint224` operator. * * Requirements: * * - input must fit into 224 bits */ function toUint224(uint256 value) internal pure returns (uint224) { if (value > type(uint224).max) { revert SafeCastOverflowedUintDowncast(224, value); } return uint224(value); } /** * @dev Returns the downcasted uint216 from uint256, reverting on * overflow (when the input is greater than largest uint216). * * Counterpart to Solidity's `uint216` operator. * * Requirements: * * - input must fit into 216 bits */ function toUint216(uint256 value) internal pure returns (uint216) { if (value > type(uint216).max) { revert SafeCastOverflowedUintDowncast(216, value); } return uint216(value); } /** * @dev Returns the downcasted uint208 from uint256, reverting on * overflow (when the input is greater than largest uint208). * * Counterpart to Solidity's `uint208` operator. * * Requirements: * * - input must fit into 208 bits */ function toUint208(uint256 value) internal pure returns (uint208) { if (value > type(uint208).max) { revert SafeCastOverflowedUintDowncast(208, value); } return uint208(value); } /** * @dev Returns the downcasted uint200 from uint256, reverting on * overflow (when the input is greater than largest uint200). * * Counterpart to Solidity's `uint200` operator. * * Requirements: * * - input must fit into 200 bits */ function toUint200(uint256 value) internal pure returns (uint200) { if (value > type(uint200).max) { revert SafeCastOverflowedUintDowncast(200, value); } return uint200(value); } /** * @dev Returns the downcasted uint192 from uint256, reverting on * overflow (when the input is greater than largest uint192). * * Counterpart to Solidity's `uint192` operator. * * Requirements: * * - input must fit into 192 bits */ function toUint192(uint256 value) internal pure returns (uint192) { if (value > type(uint192).max) { revert SafeCastOverflowedUintDowncast(192, value); } return uint192(value); } /** * @dev Returns the downcasted uint184 from uint256, reverting on * overflow (when the input is greater than largest uint184). * * Counterpart to Solidity's `uint184` operator. * * Requirements: * * - input must fit into 184 bits */ function toUint184(uint256 value) internal pure returns (uint184) { if (value > type(uint184).max) { revert SafeCastOverflowedUintDowncast(184, value); } return uint184(value); } /** * @dev Returns the downcasted uint176 from uint256, reverting on * overflow (when the input is greater than largest uint176). * * Counterpart to Solidity's `uint176` operator. * * Requirements: * * - input must fit into 176 bits */ function toUint176(uint256 value) internal pure returns (uint176) { if (value > type(uint176).max) { revert SafeCastOverflowedUintDowncast(176, value); } return uint176(value); } /** * @dev Returns the downcasted uint168 from uint256, reverting on * overflow (when the input is greater than largest uint168). * * Counterpart to Solidity's `uint168` operator. * * Requirements: * * - input must fit into 168 bits */ function toUint168(uint256 value) internal pure returns (uint168) { if (value > type(uint168).max) { revert SafeCastOverflowedUintDowncast(168, value); } return uint168(value); } /** * @dev Returns the downcasted uint160 from uint256, reverting on * overflow (when the input is greater than largest uint160). * * Counterpart to Solidity's `uint160` operator. * * Requirements: * * - input must fit into 160 bits */ function toUint160(uint256 value) internal pure returns (uint160) { if (value > type(uint160).max) { revert SafeCastOverflowedUintDowncast(160, value); } return uint160(value); } /** * @dev Returns the downcasted uint152 from uint256, reverting on * overflow (when the input is greater than largest uint152). * * Counterpart to Solidity's `uint152` operator. * * Requirements: * * - input must fit into 152 bits */ function toUint152(uint256 value) internal pure returns (uint152) { if (value > type(uint152).max) { revert SafeCastOverflowedUintDowncast(152, value); } return uint152(value); } /** * @dev Returns the downcasted uint144 from uint256, reverting on * overflow (when the input is greater than largest uint144). * * Counterpart to Solidity's `uint144` operator. * * Requirements: * * - input must fit into 144 bits */ function toUint144(uint256 value) internal pure returns (uint144) { if (value > type(uint144).max) { revert SafeCastOverflowedUintDowncast(144, value); } return uint144(value); } /** * @dev Returns the downcasted uint136 from uint256, reverting on * overflow (when the input is greater than largest uint136). * * Counterpart to Solidity's `uint136` operator. * * Requirements: * * - input must fit into 136 bits */ function toUint136(uint256 value) internal pure returns (uint136) { if (value > type(uint136).max) { revert SafeCastOverflowedUintDowncast(136, value); } return uint136(value); } /** * @dev Returns the downcasted uint128 from uint256, reverting on * overflow (when the input is greater than largest uint128). * * Counterpart to Solidity's `uint128` operator. * * Requirements: * * - input must fit into 128 bits */ function toUint128(uint256 value) internal pure returns (uint128) { if (value > type(uint128).max) { revert SafeCastOverflowedUintDowncast(128, value); } return uint128(value); } /** * @dev Returns the downcasted uint120 from uint256, reverting on * overflow (when the input is greater than largest uint120). * * Counterpart to Solidity's `uint120` operator. * * Requirements: * * - input must fit into 120 bits */ function toUint120(uint256 value) internal pure returns (uint120) { if (value > type(uint120).max) { revert SafeCastOverflowedUintDowncast(120, value); } return uint120(value); } /** * @dev Returns the downcasted uint112 from uint256, reverting on * overflow (when the input is greater than largest uint112). * * Counterpart to Solidity's `uint112` operator. * * Requirements: * * - input must fit into 112 bits */ function toUint112(uint256 value) internal pure returns (uint112) { if (value > type(uint112).max) { revert SafeCastOverflowedUintDowncast(112, value); } return uint112(value); } /** * @dev Returns the downcasted uint104 from uint256, reverting on * overflow (when the input is greater than largest uint104). * * Counterpart to Solidity's `uint104` operator. * * Requirements: * * - input must fit into 104 bits */ function toUint104(uint256 value) internal pure returns (uint104) { if (value > type(uint104).max) { revert SafeCastOverflowedUintDowncast(104, value); } return uint104(value); } /** * @dev Returns the downcasted uint96 from uint256, reverting on * overflow (when the input is greater than largest uint96). * * Counterpart to Solidity's `uint96` operator. * * Requirements: * * - input must fit into 96 bits */ function toUint96(uint256 value) internal pure returns (uint96) { if (value > type(uint96).max) { revert SafeCastOverflowedUintDowncast(96, value); } return uint96(value); } /** * @dev Returns the downcasted uint88 from uint256, reverting on * overflow (when the input is greater than largest uint88). * * Counterpart to Solidity's `uint88` operator. * * Requirements: * * - input must fit into 88 bits */ function toUint88(uint256 value) internal pure returns (uint88) { if (value > type(uint88).max) { revert SafeCastOverflowedUintDowncast(88, value); } return uint88(value); } /** * @dev Returns the downcasted uint80 from uint256, reverting on * overflow (when the input is greater than largest uint80). * * Counterpart to Solidity's `uint80` operator. * * Requirements: * * - input must fit into 80 bits */ function toUint80(uint256 value) internal pure returns (uint80) { if (value > type(uint80).max) { revert SafeCastOverflowedUintDowncast(80, value); } return uint80(value); } /** * @dev Returns the downcasted uint72 from uint256, reverting on * overflow (when the input is greater than largest uint72). * * Counterpart to Solidity's `uint72` operator. * * Requirements: * * - input must fit into 72 bits */ function toUint72(uint256 value) internal pure returns (uint72) { if (value > type(uint72).max) { revert SafeCastOverflowedUintDowncast(72, value); } return uint72(value); } /** * @dev Returns the downcasted uint64 from uint256, reverting on * overflow (when the input is greater than largest uint64). * * Counterpart to Solidity's `uint64` operator. * * Requirements: * * - input must fit into 64 bits */ function toUint64(uint256 value) internal pure returns (uint64) { if (value > type(uint64).max) { revert SafeCastOverflowedUintDowncast(64, value); } return uint64(value); } /** * @dev Returns the downcasted uint56 from uint256, reverting on * overflow (when the input is greater than largest uint56). * * Counterpart to Solidity's `uint56` operator. * * Requirements: * * - input must fit into 56 bits */ function toUint56(uint256 value) internal pure returns (uint56) { if (value > type(uint56).max) { revert SafeCastOverflowedUintDowncast(56, value); } return uint56(value); } /** * @dev Returns the downcasted uint48 from uint256, reverting on * overflow (when the input is greater than largest uint48). * * Counterpart to Solidity's `uint48` operator. * * Requirements: * * - input must fit into 48 bits */ function toUint48(uint256 value) internal pure returns (uint48) { if (value > type(uint48).max) { revert SafeCastOverflowedUintDowncast(48, value); } return uint48(value); } /** * @dev Returns the downcasted uint40 from uint256, reverting on * overflow (when the input is greater than largest uint40). * * Counterpart to Solidity's `uint40` operator. * * Requirements: * * - input must fit into 40 bits */ function toUint40(uint256 value) internal pure returns (uint40) { if (value > type(uint40).max) { revert SafeCastOverflowedUintDowncast(40, value); } return uint40(value); } /** * @dev Returns the downcasted uint32 from uint256, reverting on * overflow (when the input is greater than largest uint32). * * Counterpart to Solidity's `uint32` operator. * * Requirements: * * - input must fit into 32 bits */ function toUint32(uint256 value) internal pure returns (uint32) { if (value > type(uint32).max) { revert SafeCastOverflowedUintDowncast(32, value); } return uint32(value); } /** * @dev Returns the downcasted uint24 from uint256, reverting on * overflow (when the input is greater than largest uint24). * * Counterpart to Solidity's `uint24` operator. * * Requirements: * * - input must fit into 24 bits */ function toUint24(uint256 value) internal pure returns (uint24) { if (value > type(uint24).max) { revert SafeCastOverflowedUintDowncast(24, value); } return uint24(value); } /** * @dev Returns the downcasted uint16 from uint256, reverting on * overflow (when the input is greater than largest uint16). * * Counterpart to Solidity's `uint16` operator. * * Requirements: * * - input must fit into 16 bits */ function toUint16(uint256 value) internal pure returns (uint16) { if (value > type(uint16).max) { revert SafeCastOverflowedUintDowncast(16, value); } return uint16(value); } /** * @dev Returns the downcasted uint8 from uint256, reverting on * overflow (when the input is greater than largest uint8). * * Counterpart to Solidity's `uint8` operator. * * Requirements: * * - input must fit into 8 bits */ function toUint8(uint256 value) internal pure returns (uint8) { if (value > type(uint8).max) { revert SafeCastOverflowedUintDowncast(8, value); } return uint8(value); } /** * @dev Converts a signed int256 into an unsigned uint256. * * Requirements: * * - input must be greater than or equal to 0. */ function toUint256(int256 value) internal pure returns (uint256) { if (value < 0) { revert SafeCastOverflowedIntToUint(value); } return uint256(value); } /** * @dev Returns the downcasted int248 from int256, reverting on * overflow (when the input is less than smallest int248 or * greater than largest int248). * * Counterpart to Solidity's `int248` operator. * * Requirements: * * - input must fit into 248 bits */ function toInt248(int256 value) internal pure returns (int248 downcasted) { downcasted = int248(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(248, value); } } /** * @dev Returns the downcasted int240 from int256, reverting on * overflow (when the input is less than smallest int240 or * greater than largest int240). * * Counterpart to Solidity's `int240` operator. * * Requirements: * * - input must fit into 240 bits */ function toInt240(int256 value) internal pure returns (int240 downcasted) { downcasted = int240(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(240, value); } } /** * @dev Returns the downcasted int232 from int256, reverting on * overflow (when the input is less than smallest int232 or * greater than largest int232). * * Counterpart to Solidity's `int232` operator. * * Requirements: * * - input must fit into 232 bits */ function toInt232(int256 value) internal pure returns (int232 downcasted) { downcasted = int232(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(232, value); } } /** * @dev Returns the downcasted int224 from int256, reverting on * overflow (when the input is less than smallest int224 or * greater than largest int224). * * Counterpart to Solidity's `int224` operator. * * Requirements: * * - input must fit into 224 bits */ function toInt224(int256 value) internal pure returns (int224 downcasted) { downcasted = int224(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(224, value); } } /** * @dev Returns the downcasted int216 from int256, reverting on * overflow (when the input is less than smallest int216 or * greater than largest int216). * * Counterpart to Solidity's `int216` operator. * * Requirements: * * - input must fit into 216 bits */ function toInt216(int256 value) internal pure returns (int216 downcasted) { downcasted = int216(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(216, value); } } /** * @dev Returns the downcasted int208 from int256, reverting on * overflow (when the input is less than smallest int208 or * greater than largest int208). * * Counterpart to Solidity's `int208` operator. * * Requirements: * * - input must fit into 208 bits */ function toInt208(int256 value) internal pure returns (int208 downcasted) { downcasted = int208(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(208, value); } } /** * @dev Returns the downcasted int200 from int256, reverting on * overflow (when the input is less than smallest int200 or * greater than largest int200). * * Counterpart to Solidity's `int200` operator. * * Requirements: * * - input must fit into 200 bits */ function toInt200(int256 value) internal pure returns (int200 downcasted) { downcasted = int200(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(200, value); } } /** * @dev Returns the downcasted int192 from int256, reverting on * overflow (when the input is less than smallest int192 or * greater than largest int192). * * Counterpart to Solidity's `int192` operator. * * Requirements: * * - input must fit into 192 bits */ function toInt192(int256 value) internal pure returns (int192 downcasted) { downcasted = int192(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(192, value); } } /** * @dev Returns the downcasted int184 from int256, reverting on * overflow (when the input is less than smallest int184 or * greater than largest int184). * * Counterpart to Solidity's `int184` operator. * * Requirements: * * - input must fit into 184 bits */ function toInt184(int256 value) internal pure returns (int184 downcasted) { downcasted = int184(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(184, value); } } /** * @dev Returns the downcasted int176 from int256, reverting on * overflow (when the input is less than smallest int176 or * greater than largest int176). * * Counterpart to Solidity's `int176` operator. * * Requirements: * * - input must fit into 176 bits */ function toInt176(int256 value) internal pure returns (int176 downcasted) { downcasted = int176(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(176, value); } } /** * @dev Returns the downcasted int168 from int256, reverting on * overflow (when the input is less than smallest int168 or * greater than largest int168). * * Counterpart to Solidity's `int168` operator. * * Requirements: * * - input must fit into 168 bits */ function toInt168(int256 value) internal pure returns (int168 downcasted) { downcasted = int168(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(168, value); } } /** * @dev Returns the downcasted int160 from int256, reverting on * overflow (when the input is less than smallest int160 or * greater than largest int160). * * Counterpart to Solidity's `int160` operator. * * Requirements: * * - input must fit into 160 bits */ function toInt160(int256 value) internal pure returns (int160 downcasted) { downcasted = int160(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(160, value); } } /** * @dev Returns the downcasted int152 from int256, reverting on * overflow (when the input is less than smallest int152 or * greater than largest int152). * * Counterpart to Solidity's `int152` operator. * * Requirements: * * - input must fit into 152 bits */ function toInt152(int256 value) internal pure returns (int152 downcasted) { downcasted = int152(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(152, value); } } /** * @dev Returns the downcasted int144 from int256, reverting on * overflow (when the input is less than smallest int144 or * greater than largest int144). * * Counterpart to Solidity's `int144` operator. * * Requirements: * * - input must fit into 144 bits */ function toInt144(int256 value) internal pure returns (int144 downcasted) { downcasted = int144(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(144, value); } } /** * @dev Returns the downcasted int136 from int256, reverting on * overflow (when the input is less than smallest int136 or * greater than largest int136). * * Counterpart to Solidity's `int136` operator. * * Requirements: * * - input must fit into 136 bits */ function toInt136(int256 value) internal pure returns (int136 downcasted) { downcasted = int136(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(136, value); } } /** * @dev Returns the downcasted int128 from int256, reverting on * overflow (when the input is less than smallest int128 or * greater than largest int128). * * Counterpart to Solidity's `int128` operator. * * Requirements: * * - input must fit into 128 bits */ function toInt128(int256 value) internal pure returns (int128 downcasted) { downcasted = int128(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(128, value); } } /** * @dev Returns the downcasted int120 from int256, reverting on * overflow (when the input is less than smallest int120 or * greater than largest int120). * * Counterpart to Solidity's `int120` operator. * * Requirements: * * - input must fit into 120 bits */ function toInt120(int256 value) internal pure returns (int120 downcasted) { downcasted = int120(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(120, value); } } /** * @dev Returns the downcasted int112 from int256, reverting on * overflow (when the input is less than smallest int112 or * greater than largest int112). * * Counterpart to Solidity's `int112` operator. * * Requirements: * * - input must fit into 112 bits */ function toInt112(int256 value) internal pure returns (int112 downcasted) { downcasted = int112(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(112, value); } } /** * @dev Returns the downcasted int104 from int256, reverting on * overflow (when the input is less than smallest int104 or * greater than largest int104). * * Counterpart to Solidity's `int104` operator. * * Requirements: * * - input must fit into 104 bits */ function toInt104(int256 value) internal pure returns (int104 downcasted) { downcasted = int104(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(104, value); } } /** * @dev Returns the downcasted int96 from int256, reverting on * overflow (when the input is less than smallest int96 or * greater than largest int96). * * Counterpart to Solidity's `int96` operator. * * Requirements: * * - input must fit into 96 bits */ function toInt96(int256 value) internal pure returns (int96 downcasted) { downcasted = int96(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(96, value); } } /** * @dev Returns the downcasted int88 from int256, reverting on * overflow (when the input is less than smallest int88 or * greater than largest int88). * * Counterpart to Solidity's `int88` operator. * * Requirements: * * - input must fit into 88 bits */ function toInt88(int256 value) internal pure returns (int88 downcasted) { downcasted = int88(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(88, value); } } /** * @dev Returns the downcasted int80 from int256, reverting on * overflow (when the input is less than smallest int80 or * greater than largest int80). * * Counterpart to Solidity's `int80` operator. * * Requirements: * * - input must fit into 80 bits */ function toInt80(int256 value) internal pure returns (int80 downcasted) { downcasted = int80(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(80, value); } } /** * @dev Returns the downcasted int72 from int256, reverting on * overflow (when the input is less than smallest int72 or * greater than largest int72). * * Counterpart to Solidity's `int72` operator. * * Requirements: * * - input must fit into 72 bits */ function toInt72(int256 value) internal pure returns (int72 downcasted) { downcasted = int72(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(72, value); } } /** * @dev Returns the downcasted int64 from int256, reverting on * overflow (when the input is less than smallest int64 or * greater than largest int64). * * Counterpart to Solidity's `int64` operator. * * Requirements: * * - input must fit into 64 bits */ function toInt64(int256 value) internal pure returns (int64 downcasted) { downcasted = int64(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(64, value); } } /** * @dev Returns the downcasted int56 from int256, reverting on * overflow (when the input is less than smallest int56 or * greater than largest int56). * * Counterpart to Solidity's `int56` operator. * * Requirements: * * - input must fit into 56 bits */ function toInt56(int256 value) internal pure returns (int56 downcasted) { downcasted = int56(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(56, value); } } /** * @dev Returns the downcasted int48 from int256, reverting on * overflow (when the input is less than smallest int48 or * greater than largest int48). * * Counterpart to Solidity's `int48` operator. * * Requirements: * * - input must fit into 48 bits */ function toInt48(int256 value) internal pure returns (int48 downcasted) { downcasted = int48(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(48, value); } } /** * @dev Returns the downcasted int40 from int256, reverting on * overflow (when the input is less than smallest int40 or * greater than largest int40). * * Counterpart to Solidity's `int40` operator. * * Requirements: * * - input must fit into 40 bits */ function toInt40(int256 value) internal pure returns (int40 downcasted) { downcasted = int40(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(40, value); } } /** * @dev Returns the downcasted int32 from int256, reverting on * overflow (when the input is less than smallest int32 or * greater than largest int32). * * Counterpart to Solidity's `int32` operator. * * Requirements: * * - input must fit into 32 bits */ function toInt32(int256 value) internal pure returns (int32 downcasted) { downcasted = int32(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(32, value); } } /** * @dev Returns the downcasted int24 from int256, reverting on * overflow (when the input is less than smallest int24 or * greater than largest int24). * * Counterpart to Solidity's `int24` operator. * * Requirements: * * - input must fit into 24 bits */ function toInt24(int256 value) internal pure returns (int24 downcasted) { downcasted = int24(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(24, value); } } /** * @dev Returns the downcasted int16 from int256, reverting on * overflow (when the input is less than smallest int16 or * greater than largest int16). * * Counterpart to Solidity's `int16` operator. * * Requirements: * * - input must fit into 16 bits */ function toInt16(int256 value) internal pure returns (int16 downcasted) { downcasted = int16(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(16, value); } } /** * @dev Returns the downcasted int8 from int256, reverting on * overflow (when the input is less than smallest int8 or * greater than largest int8). * * Counterpart to Solidity's `int8` operator. * * Requirements: * * - input must fit into 8 bits */ function toInt8(int256 value) internal pure returns (int8 downcasted) { downcasted = int8(value); if (downcasted != value) { revert SafeCastOverflowedIntDowncast(8, value); } } /** * @dev Converts an unsigned uint256 into a signed int256. * * Requirements: * * - input must be less than or equal to maxInt256. */ function toInt256(uint256 value) internal pure returns (int256) { // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive if (value > uint256(type(int256).max)) { revert SafeCastOverflowedUintToInt(value); } return int256(value); } /** * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump. */ function toUint(bool b) internal pure returns (uint256 u) { /// @solidity memory-safe-assembly assembly { u := iszero(iszero(b)) } } }
{ "remappings": [ "@openzeppelin/=lib/openzeppelin-contracts/contracts/", "@solady/=lib/solady/src/", "@smart-wallet/=lib/smart-wallet/src/", "@webauthn-sol/=lib/webauthn-sol/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "FreshCryptoLib/=lib/webauthn-sol/lib/FreshCryptoLib/solidity/src/", "account-abstraction/=lib/smart-wallet/lib/account-abstraction/contracts/", "ds-test/=lib/smart-wallet/lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "p256-verifier/=lib/smart-wallet/lib/p256-verifier/", "safe-singleton-deployer-sol/=lib/smart-wallet/lib/safe-singleton-deployer-sol/", "smart-wallet/=lib/smart-wallet/", "solady/=lib/solady/src/", "webauthn-sol/=lib/webauthn-sol/src/" ], "optimizer": { "enabled": true, "runs": 500000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": {} }
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_idRegistry","type":"address"},{"internalType":"address","name":"_keyRegistry","type":"address"},{"internalType":"address","name":"_initialOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Input_Length_Mismatch","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"Invalid_Address","type":"error"},{"inputs":[],"name":"Only_Trusted","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"Registratable","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[],"name":"DisableTrustedOnly","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"bool","name":"status","type":"bool"},{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"SetTrustedCaller","type":"event"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"disableTrustedOnly","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"idRegistry","outputs":[{"internalType":"contract IdRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isTrustedCaller","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"keyRegistry","outputs":[{"internalType":"contract KeyRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"bool[]","name":"statuses","type":"bool[]"}],"name":"setTrustedCallers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"trustedOnly","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"recovery","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct IBundler.RegistrationParams","name":"registration","type":"tuple"},{"components":[{"internalType":"uint32","name":"keyType","type":"uint32"},{"internalType":"bytes","name":"key","type":"bytes"},{"internalType":"uint8","name":"metadataType","type":"uint8"},{"internalType":"bytes","name":"metadata","type":"bytes"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"sig","type":"bytes"}],"internalType":"struct IBundler.SignerParams[]","name":"signers","type":"tuple[]"}],"name":"trustedRegister","outputs":[],"stateMutability":"payable","type":"function"}]
Contract Creation Code
60c060405260016003553480156200001657600080fd5b50604051620011093803806200110983398101604081905262000039916200011b565b80806001600160a01b0381166200006a57604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b620000758162000090565b5050506001600160a01b039182166080521660a05262000165565b600180546001600160a01b0319169055620000ab81620000ae565b50565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b03811681146200011657600080fd5b919050565b6000806000606084860312156200013157600080fd5b6200013c84620000fe565b92506200014c60208501620000fe565b91506200015c60408501620000fe565b90509250925092565b60805160a051610f71620001986000396000818160e90152610571015260008181610147015261044d0152610f716000f3fe6080604052600436106100d25760003560e01c8063715018a61161007f578063d3f4ff8511610059578063d3f4ff8514610259578063e30c39781461026c578063f2fde38b14610297578063ffa1ad74146102b757600080fd5b8063715018a61461020457806379ba5097146102195780638da5cb5b1461022e57600080fd5b80636b2ddd4e116100b05780636b2ddd4e146101a95780636be65a94146101cd5780636e9bde49146101ef57600080fd5b8063086b5198146100d75780630aa13b8c146101355780631fbd282214610169575b600080fd5b3480156100e357600080fd5b5061010b7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561014157600080fd5b5061010b7f000000000000000000000000000000000000000000000000000000000000000081565b34801561017557600080fd5b50610199610184366004610a22565b60026020526000908152604090205460ff1681565b604051901515815260200161012c565b3480156101b557600080fd5b506101bf60035481565b60405190815260200161012c565b3480156101d957600080fd5b506101ed6101e8366004610b64565b61030d565b005b3480156101fb57600080fd5b506101ed610323565b34801561021057600080fd5b506101ed61035b565b34801561022557600080fd5b506101ed61036f565b34801561023a57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661010b565b6101ed610267366004610c24565b6103eb565b34801561027857600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff1661010b565b3480156102a357600080fd5b506101ed6102b2366004610a22565b610657565b3480156102c357600080fd5b506103006040518060400160405280600a81526020017f323032342e30372e31310000000000000000000000000000000000000000000081525081565b60405161012c9190610cc6565b610315610707565b61031f828261075a565b5050565b61032b610707565b600060038190556040517f03732e5295a5bd18e6ef95b03b41aa8bcadae292a7ef40468144c7a727dfa8b59190a1565b610363610707565b61036d6000610958565b565b600154339073ffffffffffffffffffffffffffffffffffffffff1681146103df576040517f118cdaa700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b6103e881610958565b50565b3360009081526002602052604090205460ff16610434576040517ff35a1b0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016637a52679261047f6020870187610a22565b61048f6040880160208901610a22565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9283166004820152911660248201526044016020604051808303816000875af1158015610501573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105259190610d33565b90508160005b8181101561064f573685858381811061054657610546610d4c565b90506020028101906105589190610d7b565b905073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663ce16c00d6105a360208a018a610a22565b6105b06020850185610db9565b6105bd6020860186610ddf565b6105cd6060880160408901610e4b565b6105da6060890189610ddf565b60808a01356105ec60a08c018c610ddf565b6040518b63ffffffff1660e01b81526004016106119a99989796959493929190610eb7565b600060405180830381600087803b15801561062b57600080fd5b505af115801561063f573d6000803e3d6000fd5b505050508160010191505061052b565b505050505050565b61065f610707565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000090911681179091556106c260005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60005473ffffffffffffffffffffffffffffffffffffffff16331461036d576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016103d6565b80518251339114610797576040517fa755bb2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b835181101561095257600073ffffffffffffffffffffffffffffffffffffffff168482815181106107cd576107cd610d4c565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603610822576040517fc765f93200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82818151811061083457610834610d4c565b60200260200101516002600086848151811061085257610852610d4c565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508281815181106108bd576108bd610d4c565b602002602001015115158482815181106108d9576108d9610d4c565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167ffecaf0e2aeb8c6a6fe2e3c626631ed42b3ce22afdec93d7ffb95a093a3a30c2d84604051610942919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405180910390a360010161079a565b50505050565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556103e8816000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610a1d57600080fd5b919050565b600060208284031215610a3457600080fd5b610a3d826109f9565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610aba57610aba610a44565b604052919050565b600067ffffffffffffffff821115610adc57610adc610a44565b5060051b60200190565b600082601f830112610af757600080fd5b81356020610b0c610b0783610ac2565b610a73565b8083825260208201915060208460051b870101935086841115610b2e57600080fd5b602086015b84811015610b595780358015158114610b4c5760008081fd5b8352918301918301610b33565b509695505050505050565b60008060408385031215610b7757600080fd5b823567ffffffffffffffff80821115610b8f57600080fd5b818501915085601f830112610ba357600080fd5b81356020610bb3610b0783610ac2565b82815260059290921b84018101918181019089841115610bd257600080fd5b948201945b83861015610bf757610be8866109f9565b82529482019490820190610bd7565b96505086013592505080821115610c0d57600080fd5b50610c1a85828601610ae6565b9150509250929050565b600080600060408486031215610c3957600080fd5b833567ffffffffffffffff80821115610c5157600080fd5b9085019060808288031215610c6557600080fd5b90935060208501359080821115610c7b57600080fd5b818601915086601f830112610c8f57600080fd5b813581811115610c9e57600080fd5b8760208260051b8501011115610cb357600080fd5b6020830194508093505050509250925092565b60006020808352835180602085015260005b81811015610cf457858101830151858201604001528201610cd8565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b600060208284031215610d4557600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff41833603018112610daf57600080fd5b9190910192915050565b600060208284031215610dcb57600080fd5b813563ffffffff81168114610a3d57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610e1457600080fd5b83018035915067ffffffffffffffff821115610e2f57600080fd5b602001915036819003821315610e4457600080fd5b9250929050565b600060208284031215610e5d57600080fd5b813560ff81168114610a3d57600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff8b16815263ffffffff8a16602082015260e060408201526000610ef360e083018a8c610e6e565b60ff891660608401528281036080840152610f0f81888a610e6e565b90508560a084015282810360c0840152610f2a818587610e6e565b9d9c5050505050505050505050505056fea26469706673582212209848aac97aafd708c575ccd0ac26541acaedb35a6231314a46e8aa22f930aff864736f6c634300081700330000000000000000000000002601197940e714ca54c22832177f3cbda128248d000000000000000000000000bc7e9a9a2b1ff7fbb4700a2d48c51d700ac5ca850000000000000000000000002167dcea5210a0744a4718ea4c56c042a2f84269
Deployed Bytecode
0x6080604052600436106100d25760003560e01c8063715018a61161007f578063d3f4ff8511610059578063d3f4ff8514610259578063e30c39781461026c578063f2fde38b14610297578063ffa1ad74146102b757600080fd5b8063715018a61461020457806379ba5097146102195780638da5cb5b1461022e57600080fd5b80636b2ddd4e116100b05780636b2ddd4e146101a95780636be65a94146101cd5780636e9bde49146101ef57600080fd5b8063086b5198146100d75780630aa13b8c146101355780631fbd282214610169575b600080fd5b3480156100e357600080fd5b5061010b7f000000000000000000000000bc7e9a9a2b1ff7fbb4700a2d48c51d700ac5ca8581565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561014157600080fd5b5061010b7f0000000000000000000000002601197940e714ca54c22832177f3cbda128248d81565b34801561017557600080fd5b50610199610184366004610a22565b60026020526000908152604090205460ff1681565b604051901515815260200161012c565b3480156101b557600080fd5b506101bf60035481565b60405190815260200161012c565b3480156101d957600080fd5b506101ed6101e8366004610b64565b61030d565b005b3480156101fb57600080fd5b506101ed610323565b34801561021057600080fd5b506101ed61035b565b34801561022557600080fd5b506101ed61036f565b34801561023a57600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff1661010b565b6101ed610267366004610c24565b6103eb565b34801561027857600080fd5b5060015473ffffffffffffffffffffffffffffffffffffffff1661010b565b3480156102a357600080fd5b506101ed6102b2366004610a22565b610657565b3480156102c357600080fd5b506103006040518060400160405280600a81526020017f323032342e30372e31310000000000000000000000000000000000000000000081525081565b60405161012c9190610cc6565b610315610707565b61031f828261075a565b5050565b61032b610707565b600060038190556040517f03732e5295a5bd18e6ef95b03b41aa8bcadae292a7ef40468144c7a727dfa8b59190a1565b610363610707565b61036d6000610958565b565b600154339073ffffffffffffffffffffffffffffffffffffffff1681146103df576040517f118cdaa700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201526024015b60405180910390fd5b6103e881610958565b50565b3360009081526002602052604090205460ff16610434576040517ff35a1b0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002601197940e714ca54c22832177f3cbda128248d16637a52679261047f6020870187610a22565b61048f6040880160208901610a22565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9283166004820152911660248201526044016020604051808303816000875af1158015610501573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105259190610d33565b90508160005b8181101561064f573685858381811061054657610546610d4c565b90506020028101906105589190610d7b565b905073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000bc7e9a9a2b1ff7fbb4700a2d48c51d700ac5ca851663ce16c00d6105a360208a018a610a22565b6105b06020850185610db9565b6105bd6020860186610ddf565b6105cd6060880160408901610e4b565b6105da6060890189610ddf565b60808a01356105ec60a08c018c610ddf565b6040518b63ffffffff1660e01b81526004016106119a99989796959493929190610eb7565b600060405180830381600087803b15801561062b57600080fd5b505af115801561063f573d6000803e3d6000fd5b505050508160010191505061052b565b505050505050565b61065f610707565b6001805473ffffffffffffffffffffffffffffffffffffffff83167fffffffffffffffffffffffff000000000000000000000000000000000000000090911681179091556106c260005473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60005473ffffffffffffffffffffffffffffffffffffffff16331461036d576040517f118cdaa70000000000000000000000000000000000000000000000000000000081523360048201526024016103d6565b80518251339114610797576040517fa755bb2e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b835181101561095257600073ffffffffffffffffffffffffffffffffffffffff168482815181106107cd576107cd610d4c565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1603610822576040517fc765f93200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82818151811061083457610834610d4c565b60200260200101516002600086848151811061085257610852610d4c565b602002602001015173ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055508281815181106108bd576108bd610d4c565b602002602001015115158482815181106108d9576108d9610d4c565b602002602001015173ffffffffffffffffffffffffffffffffffffffff167ffecaf0e2aeb8c6a6fe2e3c626631ed42b3ce22afdec93d7ffb95a093a3a30c2d84604051610942919073ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b60405180910390a360010161079a565b50505050565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001690556103e8816000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610a1d57600080fd5b919050565b600060208284031215610a3457600080fd5b610a3d826109f9565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610aba57610aba610a44565b604052919050565b600067ffffffffffffffff821115610adc57610adc610a44565b5060051b60200190565b600082601f830112610af757600080fd5b81356020610b0c610b0783610ac2565b610a73565b8083825260208201915060208460051b870101935086841115610b2e57600080fd5b602086015b84811015610b595780358015158114610b4c5760008081fd5b8352918301918301610b33565b509695505050505050565b60008060408385031215610b7757600080fd5b823567ffffffffffffffff80821115610b8f57600080fd5b818501915085601f830112610ba357600080fd5b81356020610bb3610b0783610ac2565b82815260059290921b84018101918181019089841115610bd257600080fd5b948201945b83861015610bf757610be8866109f9565b82529482019490820190610bd7565b96505086013592505080821115610c0d57600080fd5b50610c1a85828601610ae6565b9150509250929050565b600080600060408486031215610c3957600080fd5b833567ffffffffffffffff80821115610c5157600080fd5b9085019060808288031215610c6557600080fd5b90935060208501359080821115610c7b57600080fd5b818601915086601f830112610c8f57600080fd5b813581811115610c9e57600080fd5b8760208260051b8501011115610cb357600080fd5b6020830194508093505050509250925092565b60006020808352835180602085015260005b81811015610cf457858101830151858201604001528201610cd8565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b600060208284031215610d4557600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff41833603018112610daf57600080fd5b9190910192915050565b600060208284031215610dcb57600080fd5b813563ffffffff81168114610a3d57600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610e1457600080fd5b83018035915067ffffffffffffffff821115610e2f57600080fd5b602001915036819003821315610e4457600080fd5b9250929050565b600060208284031215610e5d57600080fd5b813560ff81168114610a3d57600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b73ffffffffffffffffffffffffffffffffffffffff8b16815263ffffffff8a16602082015260e060408201526000610ef360e083018a8c610e6e565b60ff891660608401528281036080840152610f0f81888a610e6e565b90508560a084015282810360c0840152610f2a818587610e6e565b9d9c5050505050505050505050505056fea26469706673582212209848aac97aafd708c575ccd0ac26541acaedb35a6231314a46e8aa22f930aff864736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002601197940e714ca54c22832177f3cbda128248d000000000000000000000000bc7e9a9a2b1ff7fbb4700a2d48c51d700ac5ca850000000000000000000000002167dcea5210a0744a4718ea4c56c042a2f84269
-----Decoded View---------------
Arg [0] : _idRegistry (address): 0x2601197940E714CA54C22832177f3CBda128248d
Arg [1] : _keyRegistry (address): 0xbc7e9A9a2b1Ff7fbB4700a2D48C51D700aC5cA85
Arg [2] : _initialOwner (address): 0x2167dcea5210A0744A4718Ea4C56c042a2f84269
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000002601197940e714ca54c22832177f3cbda128248d
Arg [1] : 000000000000000000000000bc7e9a9a2b1ff7fbb4700a2d48c51d700ac5ca85
Arg [2] : 0000000000000000000000002167dcea5210a0744a4718ea4c56c042a2f84269
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.