-
Notifications
You must be signed in to change notification settings - Fork 3
/
etherscan.json
1 lines (1 loc) · 73.1 KB
/
etherscan.json
1
{"language":"Solidity","sources":{"src/Dagon.sol":{"content":"// ᗪᗩGOᑎ 𒀭 𒀭 𒀭 𒀭 𒀭 𒀭 𒀭 𒀭 𒀭 𒀭 𒀭\n// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity 0.8.26;\n\nimport {ERC6909} from \"@solady/src/tokens/ERC6909.sol\";\nimport {SignatureCheckerLib} from \"@solady/src/utils/SignatureCheckerLib.sol\";\n\n/// @notice Simple ownership singleton for smart accounts. Version 1x.\ncontract Dagon is ERC6909 {\n /// ======================= CUSTOM ERRORS ======================= ///\n\n /// @dev Inputs are invalid for an ownership setting.\n error InvalidSetting();\n\n /// =========================== EVENTS =========================== ///\n\n /// @dev Logs new metadata for an account ID.\n event URI(string uri, uint256 indexed id);\n\n /// @dev Logs new authority contract for an account.\n event AuthSet(address indexed account, IAuth auth);\n\n /// @dev Logs new ownership threshold for an account.\n event ThresholdSet(address indexed account, uint88 threshold);\n\n /// @dev Logs new token ownership standard for an account.\n event TokenSet(address indexed account, address token, Standard standard);\n\n /// ========================== STRUCTS ========================== ///\n\n /// @dev The account token metadata struct.\n struct Metadata {\n string name;\n string symbol;\n string tokenURI;\n IAuth authority;\n uint96 totalSupply;\n }\n\n /// @dev The account ownership shares struct.\n struct Ownership {\n address owner;\n uint96 shares;\n }\n\n /// @dev The signature struct.\n struct Signature {\n address owner;\n bytes sigData;\n }\n\n /// @dev The account ownership settings struct.\n struct Settings {\n address token;\n uint88 threshold;\n Standard standard;\n }\n\n /// @dev The packed ERC4337 user operation (userOp) struct.\n struct PackedUserOperation {\n address sender;\n uint256 nonce;\n bytes initCode;\n bytes callData;\n bytes32 accountGasLimits;\n uint256 preVerificationGas;\n bytes32 gasFees;\n bytes paymasterAndData;\n bytes signature;\n }\n\n /// =========================== ENUMS =========================== ///\n\n /// @dev The token standard interface enum.\n enum Standard {\n DAGON,\n ERC20,\n ERC721,\n ERC1155,\n ERC6909\n }\n\n /// ========================== STORAGE ========================== ///\n\n /// @dev Stores mapping of metadata settings to account token IDs.\n /// note: IDs are unique to addresses (`uint256(uint160(account))`).\n mapping(uint256 id => Metadata) internal _metadata;\n\n /// @dev Stores mapping of ownership settings to accounts.\n mapping(address account => Settings) internal _settings;\n\n /// @dev Stores mapping of voting tallies to account operation hashes.\n mapping(address account => mapping(bytes32 hash => uint256)) public votingTally;\n\n /// @dev Stores mapping of account owner shares cast on account operation hashes.\n mapping(address account => mapping(address owner => mapping(bytes32 hash => uint256 shares)))\n public voted;\n\n /// ================= ERC6909 METADATA & SUPPLY ================= ///\n\n /// @dev Returns the name for token `id` using this contract.\n function name(uint256 id) public view virtual override(ERC6909) returns (string memory) {\n return _metadata[id].name;\n }\n\n /// @dev Returns the symbol for token `id` using this contract.\n function symbol(uint256 id) public view virtual override(ERC6909) returns (string memory) {\n return _metadata[id].symbol;\n }\n\n /// @dev Returns the URI for token `id` using this contract.\n function tokenURI(uint256 id) public view virtual override(ERC6909) returns (string memory) {\n return _metadata[id].tokenURI;\n }\n\n /// @dev Returns the total supply for token `id` using this contract.\n function totalSupply(uint256 id) public view virtual returns (uint256) {\n return _metadata[id].totalSupply;\n }\n\n /// ======================== CONSTRUCTOR ======================== ///\n\n /// @dev Constructs\n /// this implementation.\n constructor() payable {}\n\n /// =================== VALIDATION OPERATIONS =================== ///\n\n /// @dev Validates ERC1271 signature with additional auth logic flow among owners.\n /// note: This implementation is designed to be the ERC-173-owner-of-4337-accounts.\n function isValidSignature(bytes32 hash, bytes calldata signature)\n public\n view\n virtual\n returns (bytes4)\n {\n Settings memory setting = _settings[msg.sender];\n if (signature.length != 0) {\n unchecked {\n Signature[] memory signatures = abi.decode(signature, (Signature[]));\n address prev;\n address owner;\n uint256 tally;\n for (uint256 i; i != signatures.length; ++i) {\n if (\n SignatureCheckerLib.isValidSignatureNow(\n owner = signatures[i].owner, hash, signatures[i].sigData\n ) && prev < owner // Check double voting.\n ) {\n prev = owner;\n tally += setting.standard == Standard.DAGON\n ? balanceOf(owner, uint256(uint160(msg.sender)))\n : setting.standard == Standard.ERC20 || setting.standard == Standard.ERC721\n ? _balanceOf(setting.token, owner)\n : _balanceOf(setting.token, owner, uint256(uint160(msg.sender)));\n } else {\n return 0xffffffff; // Failure code.\n }\n }\n return _validateReturn(tally >= setting.threshold);\n }\n }\n return _validateReturn(votingTally[msg.sender][hash] >= setting.threshold);\n }\n\n /// @dev Validates packed userOp with additional auth logic flow among owners.\n /// note: This is expected to be called in a validator plugin-like userOp flow.\n function validateUserOp(\n PackedUserOperation calldata userOp,\n bytes32 userOpHash,\n uint256 /*missingAccountFunds*/\n ) public virtual returns (uint256 validationData) {\n IAuth auth = _metadata[uint256(uint160(msg.sender))].authority;\n if (auth != IAuth(address(0))) {\n (address target, uint256 value, bytes memory data) =\n abi.decode(userOp.callData[4:], (address, uint256, bytes));\n auth.validateCall(msg.sender, target, value, data);\n }\n if (isValidSignature(userOpHash, userOp.signature) != this.isValidSignature.selector) {\n validationData = 0x01; // Failure code.\n }\n }\n\n /// @dev Returns validated signature result within the conventional ERC1271 syntax.\n function _validateReturn(bool success) internal pure virtual returns (bytes4 result) {\n assembly (\"memory-safe\") {\n // `success ? bytes4(keccak256(\"isValidSignature(bytes32,bytes)\")) : 0xffffffff`.\n result := shl(224, or(0x1626ba7e, sub(0, iszero(success))))\n }\n }\n\n /// ===================== VOTING OPERATIONS ===================== ///\n\n /// @dev Casts account owners' voting shares on a given operation hash.\n function vote(address account, bytes32 hash, bytes calldata signature)\n public\n virtual\n returns (uint256)\n {\n Signature[] memory signatures = abi.decode(signature, (Signature[]));\n Settings memory setting = _settings[account];\n unchecked {\n address owner;\n uint256 tally;\n for (uint256 i; i != signatures.length; ++i) {\n if (\n SignatureCheckerLib.isValidSignatureNow(\n owner = signatures[i].owner, hash, signatures[i].sigData\n ) && voted[account][owner][hash] == 0 // Check double voting.\n ) {\n tally += voted[account][owner][hash] = setting.standard == Standard.DAGON\n ? balanceOf(owner, uint256(uint160(account)))\n : setting.standard == Standard.ERC20 || setting.standard == Standard.ERC721\n ? _balanceOf(setting.token, owner)\n : _balanceOf(setting.token, owner, uint256(uint160(account)));\n }\n }\n return votingTally[account][hash] += tally; // Return latest total tally.\n }\n }\n\n /// @dev Casts caller voting shares on a given operation hash and returns tally.\n function vote(address account, bytes32 hash) public virtual returns (uint256) {\n if (voted[account][msg.sender][hash] != 0) revert InsufficientPermission();\n Settings storage setting = _settings[account];\n unchecked {\n return votingTally[account][hash] += voted[account][msg.sender][hash] = setting.standard\n == Standard.DAGON\n ? balanceOf(msg.sender, uint256(uint160(account)))\n : setting.standard == Standard.ERC20 || setting.standard == Standard.ERC721\n ? _balanceOf(setting.token, msg.sender)\n : _balanceOf(setting.token, msg.sender, uint256(uint160(account)));\n }\n }\n\n /// ======================== INSTALLATION ======================== ///\n\n /// @dev Initializes ownership settings for the caller account.\n /// note: Finalizes with transfer request in two-step pattern.\n /// See, e.g., Ownable.sol:\n /// https://github.com/Vectorized/solady/blob/main/src/auth/Ownable.sol\n function install(Ownership[] calldata owners, Settings calldata setting, Metadata calldata meta)\n public\n virtual\n {\n uint256 id = uint256(uint160(msg.sender));\n if (owners.length != 0) {\n uint96 supply;\n for (uint256 i; i != owners.length; ++i) {\n supply += owners[i].shares;\n _mint(owners[i].owner, id, owners[i].shares);\n }\n _metadata[id].totalSupply += supply;\n }\n setToken(setting.token, setting.standard);\n setThreshold(setting.threshold);\n if (bytes(meta.name).length != 0) {\n _metadata[id].name = meta.name;\n _metadata[id].symbol = meta.symbol;\n }\n if (bytes(meta.tokenURI).length != 0) setURI(meta.tokenURI);\n if (meta.authority != IAuth(address(0))) setAuth(meta.authority);\n try IOwnable(msg.sender).requestOwnershipHandover() {} catch {} // Avoid revert.\n }\n\n /// ===================== OWNERSHIP SETTINGS ===================== ///\n\n /// @dev Returns the account settings.\n function getSettings(address account) public view virtual returns (address, uint88, Standard) {\n Settings storage set = _settings[account];\n return (set.token, set.threshold, set.standard);\n }\n\n /// @dev Sets new authority contract for the caller account.\n function setAuth(IAuth auth) public virtual {\n emit AuthSet(msg.sender, (_metadata[uint256(uint160(msg.sender))].authority = auth));\n }\n\n /// @dev Sets new token ownership interface standard for the caller account.\n function setToken(address token, Standard standard) public virtual {\n emit TokenSet(\n msg.sender,\n _settings[msg.sender].token = token,\n _settings[msg.sender].standard = standard\n );\n }\n\n /// @dev Sets new ownership threshold for the caller account.\n function setThreshold(uint88 threshold) public virtual {\n Settings storage set = _settings[msg.sender];\n if (\n threshold\n > (\n set.standard == Standard.DAGON\n ? totalSupply(uint256(uint160(msg.sender)))\n : set.standard == Standard.ERC20 || set.standard == Standard.ERC721\n ? _totalSupply(set.token)\n : _totalSupply(set.token, uint256(uint160(msg.sender)))\n ) || threshold == 0\n ) revert InvalidSetting();\n emit ThresholdSet(msg.sender, (set.threshold = threshold));\n }\n\n /// ====================== TOKEN OPERATIONS ====================== ///\n\n /// @dev Returns the account metadata.\n function getMetadata(address account)\n public\n view\n virtual\n returns (string memory, string memory, string memory, IAuth)\n {\n Metadata storage meta = _metadata[uint256(uint160(account))];\n return (meta.name, meta.symbol, meta.tokenURI, meta.authority);\n }\n\n /// @dev Mints shares for an owner of the caller account.\n function mint(address owner, uint96 shares) public virtual {\n uint256 id = uint256(uint160(msg.sender));\n _metadata[id].totalSupply += shares;\n _mint(owner, id, shares);\n }\n\n /// @dev Burns shares from an owner of the caller account.\n function burn(address owner, uint96 shares) public virtual {\n uint256 id = uint256(uint160(msg.sender));\n unchecked {\n if (_settings[msg.sender].threshold > (_metadata[id].totalSupply -= shares)) {\n revert InvalidSetting();\n }\n }\n _burn(owner, id, shares);\n }\n\n /// @dev Sets new token URI metadata for the caller account.\n function setURI(string calldata uri) public virtual {\n uint256 id = uint256(uint160(msg.sender));\n emit URI((_metadata[id].tokenURI = uri), id);\n }\n\n /// =================== EXTERNAL TOKEN HELPERS =================== ///\n\n /// @dev Returns the amount of ERC20/721 `token` owned by `account`.\n function _balanceOf(address token, address account)\n internal\n view\n virtual\n returns (uint256 amount)\n {\n assembly (\"memory-safe\") {\n mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.\n mstore(0x14, account) // Store the `account` argument.\n pop(staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20))\n amount := mload(0x20)\n }\n }\n\n /// @dev Returns the amount of ERC1155/6909 `token` `id` owned by `account`.\n function _balanceOf(address token, address account, uint256 id)\n internal\n view\n virtual\n returns (uint256 amount)\n {\n assembly (\"memory-safe\") {\n mstore(0x00, 0x00fdd58e000000000000000000000000) // `balanceOf(address,uint256)`.\n mstore(0x14, account) // Store the `account` argument.\n mstore(0x34, id) // Store the `id` argument.\n pop(staticcall(gas(), token, 0x10, 0x44, 0x20, 0x20))\n amount := mload(0x20)\n mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.\n }\n }\n\n /// @dev Returns the total supply of ERC20/721 `token`.\n function _totalSupply(address token) internal view virtual returns (uint256 supply) {\n assembly (\"memory-safe\") {\n mstore(0x00, 0x18160ddd) // `totalSupply()`.\n pop(staticcall(gas(), token, 0x1c, 0x04, 0x20, 0x20))\n supply := mload(0x20)\n }\n }\n\n /// @dev Returns the total supply of ERC1155/6909 `token` `id`.\n function _totalSupply(address token, uint256 id)\n internal\n view\n virtual\n returns (uint256 supply)\n {\n assembly (\"memory-safe\") {\n mstore(0x00, 0xbd85b039) // `totalSupply(uint256)`.\n mstore(0x20, id) // Store the `id` argument.\n pop(staticcall(gas(), token, 0x1c, 0x24, 0x20, 0x20))\n supply := mload(0x20)\n }\n }\n\n /// ========================= OVERRIDES ========================= ///\n\n /// @dev Hook that is called before any transfer of tokens.\n /// This includes minting and burning. Also requests authority for token transfers.\n function _beforeTokenTransfer(address from, address to, uint256 id, uint256 amount)\n internal\n virtual\n override(ERC6909)\n {\n IAuth auth = _metadata[id].authority;\n if (auth != IAuth(address(0))) auth.validateTransfer(from, to, id, amount);\n }\n}\n\n/// @notice Simple authority interface for contracts.\ninterface IAuth {\n function validateTransfer(address, address, uint256, uint256)\n external\n payable\n returns (uint256);\n function validateCall(address, address, uint256, bytes calldata)\n external\n payable\n returns (uint256);\n}\n\n/// @notice Simple ownership interface for handover requests.\ninterface IOwnable {\n function requestOwnershipHandover() external payable;\n}\n"},"lib/solady/src/tokens/ERC6909.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Simple EIP-6909 implementation.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC6909.sol)\n///\n/// @dev Note:\n/// The ERC6909 standard allows minting and transferring to and from the zero address,\n/// minting and transferring zero tokens, as well as self-approvals.\n/// For performance, this implementation WILL NOT revert for such actions.\n/// Please add any checks with overrides if desired.\n///\n/// If you are overriding:\n/// - Make sure all variables written to storage are properly cleaned\n// (e.g. the bool value for `isOperator` MUST be either 1 or 0 under the hood).\n/// - Check that the overridden function is actually used in the function you want to\n/// change the behavior of. Much of the code has been manually inlined for performance.\nabstract contract ERC6909 {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* CUSTOM ERRORS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Insufficient balance.\n error InsufficientBalance();\n\n /// @dev Insufficient permission to perform the action.\n error InsufficientPermission();\n\n /// @dev The balance has overflowed.\n error BalanceOverflow();\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* EVENTS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Emitted when `by` transfers `amount` of token `id` from `from` to `to`.\n event Transfer(\n address by, address indexed from, address indexed to, uint256 indexed id, uint256 amount\n );\n\n /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens.\n event OperatorSet(address indexed owner, address indexed operator, bool approved);\n\n /// @dev Emitted when `owner` approves `spender` to use `amount` of `id` token.\n event Approval(\n address indexed owner, address indexed spender, uint256 indexed id, uint256 amount\n );\n\n /// @dev `keccak256(bytes(\"Transfer(address,address,address,uint256,uint256)\"))`.\n uint256 private constant _TRANSFER_EVENT_SIGNATURE =\n 0x1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac728859;\n\n /// @dev `keccak256(bytes(\"OperatorSet(address,address,bool)\"))`.\n uint256 private constant _OPERATOR_SET_EVENT_SIGNATURE =\n 0xceb576d9f15e4e200fdb5096d64d5dfd667e16def20c1eefd14256d8e3faa267;\n\n /// @dev `keccak256(bytes(\"Approval(address,address,uint256,uint256)\"))`.\n uint256 private constant _APPROVAL_EVENT_SIGNATURE =\n 0xb3fd5071835887567a0671151121894ddccc2842f1d10bedad13e0d17cace9a7;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* STORAGE */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev The `ownerSlotSeed` of a given owner is given by.\n /// ```\n /// let ownerSlotSeed := or(_ERC6909_MASTER_SLOT_SEED, shl(96, owner))\n /// ```\n ///\n /// The balance slot of `owner` is given by.\n /// ```\n /// mstore(0x20, ownerSlotSeed)\n /// mstore(0x00, id)\n /// let balanceSlot := keccak256(0x00, 0x40)\n /// ```\n ///\n /// The operator approval slot of `owner` is given by.\n /// ```\n /// mstore(0x20, ownerSlotSeed)\n /// mstore(0x00, operator)\n /// let operatorApprovalSlot := keccak256(0x0c, 0x34)\n /// ```\n ///\n /// The allowance slot of (`owner`, `spender`, `id`) is given by:\n /// ```\n /// mstore(0x34, ownerSlotSeed)\n /// mstore(0x14, spender)\n /// mstore(0x00, id)\n /// let allowanceSlot := keccak256(0x00, 0x54)\n /// ```\n uint256 private constant _ERC6909_MASTER_SLOT_SEED = 0xedcaa89a82293940;\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* ERC6909 METADATA */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the name for token `id`.\n function name(uint256 id) public view virtual returns (string memory);\n\n /// @dev Returns the symbol for token `id`.\n function symbol(uint256 id) public view virtual returns (string memory);\n\n /// @dev Returns the number of decimals for token `id`.\n /// Returns 18 by default.\n /// Please override this function if you need to return a custom value.\n function decimals(uint256 id) public view virtual returns (uint8) {\n id = id; // Silence compiler warning.\n return 18;\n }\n\n /// @dev Returns the Uniform Resource Identifier (URI) for token `id`.\n function tokenURI(uint256 id) public view virtual returns (string memory);\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* ERC6909 */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns the amount of token `id` owned by `owner`.\n function balanceOf(address owner, uint256 id) public view virtual returns (uint256 amount) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x20, _ERC6909_MASTER_SLOT_SEED)\n mstore(0x14, owner)\n mstore(0x00, id)\n amount := sload(keccak256(0x00, 0x40))\n }\n }\n\n /// @dev Returns the amount of token `id` that `spender` can spend on behalf of `owner`.\n function allowance(address owner, address spender, uint256 id)\n public\n view\n virtual\n returns (uint256 amount)\n {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x34, _ERC6909_MASTER_SLOT_SEED)\n mstore(0x28, owner)\n mstore(0x14, spender)\n mstore(0x00, id)\n amount := sload(keccak256(0x00, 0x54))\n // Restore the part of the free memory pointer that has been overwritten.\n mstore(0x34, 0x00)\n }\n }\n\n /// @dev Checks if a `spender` is approved by `owner` to manage all of their tokens.\n function isOperator(address owner, address spender) public view virtual returns (bool status) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x20, _ERC6909_MASTER_SLOT_SEED)\n mstore(0x14, owner)\n mstore(0x00, spender)\n status := sload(keccak256(0x0c, 0x34))\n }\n }\n\n /// @dev Transfers `amount` of token `id` from the caller to `to`.\n ///\n /// Requirements:\n /// - caller must at least have `amount`.\n ///\n /// Emits a {Transfer} event.\n function transfer(address to, uint256 id, uint256 amount)\n public\n payable\n virtual\n returns (bool)\n {\n _beforeTokenTransfer(msg.sender, to, id, amount);\n /// @solidity memory-safe-assembly\n assembly {\n /// Compute the balance slot and load its value.\n mstore(0x20, _ERC6909_MASTER_SLOT_SEED)\n mstore(0x14, caller())\n mstore(0x00, id)\n let fromBalanceSlot := keccak256(0x00, 0x40)\n let fromBalance := sload(fromBalanceSlot)\n // Revert if insufficient balance.\n if gt(amount, fromBalance) {\n mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.\n revert(0x1c, 0x04)\n }\n // Subtract and store the updated balance.\n sstore(fromBalanceSlot, sub(fromBalance, amount))\n // Compute the balance slot of `to`.\n mstore(0x14, to)\n mstore(0x00, id)\n let toBalanceSlot := keccak256(0x00, 0x40)\n let toBalanceBefore := sload(toBalanceSlot)\n let toBalanceAfter := add(toBalanceBefore, amount)\n // Revert if the balance overflows.\n if lt(toBalanceAfter, toBalanceBefore) {\n mstore(0x00, 0x89560ca1) // `BalanceOverflow()`.\n revert(0x1c, 0x04)\n }\n // Store the updated balance of `to`.\n sstore(toBalanceSlot, toBalanceAfter)\n // Emit the {Transfer} event.\n mstore(0x00, caller())\n mstore(0x20, amount)\n log4(0x00, 0x40, _TRANSFER_EVENT_SIGNATURE, caller(), shr(96, shl(96, to)), id)\n }\n _afterTokenTransfer(msg.sender, to, id, amount);\n return true;\n }\n\n /// @dev Transfers `amount` of token `id` from `from` to `to`.\n ///\n /// Note: Does not update the allowance if it is the maximum uint256 value.\n ///\n /// Requirements:\n /// - `from` must at least have `amount` of token `id`.\n /// - The caller must have at least `amount` of allowance to transfer the\n /// tokens of `from` or approved as an operator.\n ///\n /// Emits a {Transfer} event.\n function transferFrom(address from, address to, uint256 id, uint256 amount)\n public\n payable\n virtual\n returns (bool)\n {\n _beforeTokenTransfer(from, to, id, amount);\n /// @solidity memory-safe-assembly\n assembly {\n // Compute the operator slot and load its value.\n mstore(0x34, _ERC6909_MASTER_SLOT_SEED)\n mstore(0x28, from)\n mstore(0x14, caller())\n // Check if the caller is an operator.\n if iszero(sload(keccak256(0x20, 0x34))) {\n // Compute the allowance slot and load its value.\n mstore(0x00, id)\n let allowanceSlot := keccak256(0x00, 0x54)\n let allowance_ := sload(allowanceSlot)\n // If the allowance is not the maximum uint256 value.\n if add(allowance_, 1) {\n // Revert if the amount to be transferred exceeds the allowance.\n if gt(amount, allowance_) {\n mstore(0x00, 0xdeda9030) // `InsufficientPermission()`.\n revert(0x1c, 0x04)\n }\n // Subtract and store the updated allowance.\n sstore(allowanceSlot, sub(allowance_, amount))\n }\n }\n // Compute the balance slot and load its value.\n mstore(0x14, id)\n let fromBalanceSlot := keccak256(0x14, 0x40)\n let fromBalance := sload(fromBalanceSlot)\n // Revert if insufficient balance.\n if gt(amount, fromBalance) {\n mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.\n revert(0x1c, 0x04)\n }\n // Subtract and store the updated balance.\n sstore(fromBalanceSlot, sub(fromBalance, amount))\n // Compute the balance slot of `to`.\n mstore(0x28, to)\n mstore(0x14, id)\n let toBalanceSlot := keccak256(0x14, 0x40)\n let toBalanceBefore := sload(toBalanceSlot)\n let toBalanceAfter := add(toBalanceBefore, amount)\n // Revert if the balance overflows.\n if lt(toBalanceAfter, toBalanceBefore) {\n mstore(0x00, 0x89560ca1) // `BalanceOverflow()`.\n revert(0x1c, 0x04)\n }\n // Store the updated balance of `to`.\n sstore(toBalanceSlot, toBalanceAfter)\n // Emit the {Transfer} event.\n mstore(0x00, caller())\n mstore(0x20, amount)\n // forgefmt: disable-next-line\n log4(0x00, 0x40, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), shr(96, shl(96, to)), id)\n // Restore the part of the free memory pointer that has been overwritten.\n mstore(0x34, 0x00)\n }\n _afterTokenTransfer(from, to, id, amount);\n return true;\n }\n\n /// @dev Sets `amount` as the allowance of `spender` for the caller for token `id`.\n ///\n /// Emits a {Approval} event.\n function approve(address spender, uint256 id, uint256 amount)\n public\n payable\n virtual\n returns (bool)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // Compute the allowance slot and store the amount.\n mstore(0x34, _ERC6909_MASTER_SLOT_SEED)\n mstore(0x28, caller())\n mstore(0x14, spender)\n mstore(0x00, id)\n sstore(keccak256(0x00, 0x54), amount)\n // Emit the {Approval} event.\n mstore(0x00, amount)\n log4(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x20)), id)\n // Restore the part of the free memory pointer that has been overwritten.\n mstore(0x34, 0x00)\n }\n return true;\n }\n\n /// @dev Sets whether `operator` is approved to manage the tokens of the caller.\n ///\n /// Emits {OperatorSet} event.\n function setOperator(address operator, bool approved) public payable virtual returns (bool) {\n /// @solidity memory-safe-assembly\n assembly {\n // Convert `approved` to `0` or `1`.\n let approvedCleaned := iszero(iszero(approved))\n // Compute the operator slot and store the approved.\n mstore(0x20, _ERC6909_MASTER_SLOT_SEED)\n mstore(0x14, caller())\n mstore(0x00, operator)\n sstore(keccak256(0x0c, 0x34), approvedCleaned)\n // Emit the {OperatorSet} event.\n mstore(0x20, approvedCleaned)\n log3(0x20, 0x20, _OPERATOR_SET_EVENT_SIGNATURE, caller(), shr(96, mload(0x0c)))\n }\n return true;\n }\n\n /// @dev Returns true if this contract implements the interface defined by `interfaceId`.\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {\n /// @solidity memory-safe-assembly\n assembly {\n let s := shr(224, interfaceId)\n // ERC165: 0x01ffc9a7, ERC6909: 0x0f632fb3.\n result := or(eq(s, 0x01ffc9a7), eq(s, 0x0f632fb3))\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* INTERNAL FUNCTIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Mints `amount` of token `id` to `to`.\n ///\n /// Emits a {Transfer} event.\n function _mint(address to, uint256 id, uint256 amount) internal virtual {\n _beforeTokenTransfer(address(0), to, id, amount);\n /// @solidity memory-safe-assembly\n assembly {\n // Compute the balance slot.\n mstore(0x20, _ERC6909_MASTER_SLOT_SEED)\n mstore(0x14, to)\n mstore(0x00, id)\n let toBalanceSlot := keccak256(0x00, 0x40)\n // Add and store the updated balance\n let toBalanceBefore := sload(toBalanceSlot)\n let toBalanceAfter := add(toBalanceBefore, amount)\n // Revert if the balance overflows.\n if lt(toBalanceAfter, toBalanceBefore) {\n mstore(0x00, 0x89560ca1) // `BalanceOverflow()`.\n revert(0x1c, 0x04)\n }\n sstore(toBalanceSlot, toBalanceAfter)\n // Emit the {Transfer} event.\n mstore(0x00, caller())\n mstore(0x20, amount)\n log4(0x00, 0x40, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, shl(96, to)), id)\n }\n _afterTokenTransfer(address(0), to, id, amount);\n }\n\n /// @dev Burns `amount` token `id` from `from`.\n ///\n /// Emits a {Transfer} event.\n function _burn(address from, uint256 id, uint256 amount) internal virtual {\n _beforeTokenTransfer(from, address(0), id, amount);\n /// @solidity memory-safe-assembly\n assembly {\n // Compute the balance slot.\n mstore(0x20, _ERC6909_MASTER_SLOT_SEED)\n mstore(0x14, from)\n mstore(0x00, id)\n let fromBalanceSlot := keccak256(0x00, 0x40)\n let fromBalance := sload(fromBalanceSlot)\n // Revert if insufficient balance.\n if gt(amount, fromBalance) {\n mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.\n revert(0x1c, 0x04)\n }\n // Subtract and store the updated balance.\n sstore(fromBalanceSlot, sub(fromBalance, amount))\n // Emit the {Transfer} event.\n mstore(0x00, caller())\n mstore(0x20, amount)\n log4(0x00, 0x40, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0, id)\n }\n _afterTokenTransfer(from, address(0), id, amount);\n }\n\n /// @dev Transfers `amount` of token `id` from `from` to `to`.\n ///\n /// Note: Does not update the allowance if it is the maximum uint256 value.\n ///\n /// Requirements:\n /// - `from` must at least have `amount` of token `id`.\n /// - If `by` is not the zero address,\n /// it must have at least `amount` of allowance to transfer the\n /// tokens of `from` or approved as an operator.\n ///\n /// Emits a {Transfer} event.\n function _transfer(address by, address from, address to, uint256 id, uint256 amount)\n internal\n virtual\n {\n _beforeTokenTransfer(from, to, id, amount);\n /// @solidity memory-safe-assembly\n assembly {\n let bitmaskAddress := 0xffffffffffffffffffffffffffffffffffffffff\n // Compute the operator slot and load its value.\n mstore(0x34, _ERC6909_MASTER_SLOT_SEED)\n mstore(0x28, from)\n // If `by` is not the zero address.\n if and(bitmaskAddress, by) {\n mstore(0x14, by)\n // Check if the `by` is an operator.\n if iszero(sload(keccak256(0x20, 0x34))) {\n // Compute the allowance slot and load its value.\n mstore(0x00, id)\n let allowanceSlot := keccak256(0x00, 0x54)\n let allowance_ := sload(allowanceSlot)\n // If the allowance is not the maximum uint256 value.\n if add(allowance_, 1) {\n // Revert if the amount to be transferred exceeds the allowance.\n if gt(amount, allowance_) {\n mstore(0x00, 0xdeda9030) // `InsufficientPermission()`.\n revert(0x1c, 0x04)\n }\n // Subtract and store the updated allowance.\n sstore(allowanceSlot, sub(allowance_, amount))\n }\n }\n }\n // Compute the balance slot and load its value.\n mstore(0x14, id)\n let fromBalanceSlot := keccak256(0x14, 0x40)\n let fromBalance := sload(fromBalanceSlot)\n // Revert if insufficient balance.\n if gt(amount, fromBalance) {\n mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.\n revert(0x1c, 0x04)\n }\n // Subtract and store the updated balance.\n sstore(fromBalanceSlot, sub(fromBalance, amount))\n // Compute the balance slot of `to`.\n mstore(0x28, to)\n mstore(0x14, id)\n let toBalanceSlot := keccak256(0x14, 0x40)\n let toBalanceBefore := sload(toBalanceSlot)\n let toBalanceAfter := add(toBalanceBefore, amount)\n // Revert if the balance overflows.\n if lt(toBalanceAfter, toBalanceBefore) {\n mstore(0x00, 0x89560ca1) // `BalanceOverflow()`.\n revert(0x1c, 0x04)\n }\n // Store the updated balance of `to`.\n sstore(toBalanceSlot, toBalanceAfter)\n // Emit the {Transfer} event.\n mstore(0x00, and(bitmaskAddress, by))\n mstore(0x20, amount)\n // forgefmt: disable-next-line\n log4(0x00, 0x40, _TRANSFER_EVENT_SIGNATURE, and(bitmaskAddress, from), and(bitmaskAddress, to), id)\n // Restore the part of the free memory pointer that has been overwritten.\n mstore(0x34, 0x00)\n }\n _afterTokenTransfer(from, to, id, amount);\n }\n\n /// @dev Sets `amount` as the allowance of `spender` for `owner` for token `id`.\n ///\n /// Emits a {Approval} event.\n function _approve(address owner, address spender, uint256 id, uint256 amount)\n internal\n virtual\n {\n /// @solidity memory-safe-assembly\n assembly {\n // Compute the allowance slot and store the amount.\n mstore(0x34, _ERC6909_MASTER_SLOT_SEED)\n mstore(0x28, owner)\n mstore(0x14, spender)\n mstore(0x00, id)\n sstore(keccak256(0x00, 0x54), amount)\n // Emit the {Approval} event.\n mstore(0x00, amount)\n // forgefmt: disable-next-line\n log4(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, mload(0x34)), shr(96, mload(0x20)), id)\n // Restore the part of the free memory pointer that has been overwritten.\n mstore(0x34, 0x00)\n }\n }\n\n /// @dev Sets whether `operator` is approved to manage the tokens of `owner`.\n ///\n /// Emits {OperatorSet} event.\n function _setOperator(address owner, address operator, bool approved) internal virtual {\n /// @solidity memory-safe-assembly\n assembly {\n // Convert `approved` to `0` or `1`.\n let approvedCleaned := iszero(iszero(approved))\n // Compute the operator slot and store the approved.\n mstore(0x20, _ERC6909_MASTER_SLOT_SEED)\n mstore(0x14, owner)\n mstore(0x00, operator)\n sstore(keccak256(0x0c, 0x34), approvedCleaned)\n // Emit the {OperatorSet} event.\n mstore(0x20, approvedCleaned)\n // forgefmt: disable-next-line\n log3(0x20, 0x20, _OPERATOR_SET_EVENT_SIGNATURE, shr(96, shl(96, owner)), shr(96, mload(0x0c)))\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* HOOKS TO OVERRIDE */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Hook that is called before any transfer of tokens.\n /// This includes minting and burning.\n function _beforeTokenTransfer(address from, address to, uint256 id, uint256 amount)\n internal\n virtual\n {}\n\n /// @dev Hook that is called after any transfer of tokens.\n /// This includes minting and burning.\n function _afterTokenTransfer(address from, address to, uint256 id, uint256 amount)\n internal\n virtual\n {}\n}\n"},"lib/solady/src/utils/SignatureCheckerLib.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.4;\n\n/// @notice Signature verification helper that supports both ECDSA signatures from EOAs\n/// and ERC1271 signatures from smart contract wallets like Argent and Gnosis safe.\n/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SignatureCheckerLib.sol)\n/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol)\n///\n/// @dev Note:\n/// - The signature checking functions use the ecrecover precompile (0x1).\n/// - The `bytes memory signature` variants use the identity precompile (0x4)\n/// to copy memory internally.\n/// - Unlike ECDSA signatures, contract signatures are revocable.\n/// - As of Solady version 0.0.134, all `bytes signature` variants accept both\n/// regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures.\n/// See: https://eips.ethereum.org/EIPS/eip-2098\n/// This is for calldata efficiency on smart accounts prevalent on L2s.\n///\n/// WARNING! Do NOT use signatures as unique identifiers:\n/// - Use a nonce in the digest to prevent replay attacks on the same contract.\n/// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts.\n/// EIP-712 also enables readable signing of typed data for better user safety.\n/// This implementation does NOT check if a signature is non-malleable.\nlibrary SignatureCheckerLib {\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* SIGNATURE CHECKING OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns whether `signature` is valid for `signer` and `hash`.\n /// If `signer` is a smart contract, the signature is validated with ERC1271.\n /// Otherwise, the signature is validated with `ECDSA.recover`.\n function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature)\n internal\n view\n returns (bool isValid)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // Clean the upper 96 bits of `signer` in case they are dirty.\n for { signer := shr(96, shl(96, signer)) } signer {} {\n let m := mload(0x40)\n mstore(0x00, hash)\n mstore(0x40, mload(add(signature, 0x20))) // `r`.\n if eq(mload(signature), 64) {\n let vs := mload(add(signature, 0x40))\n mstore(0x20, add(shr(255, vs), 27)) // `v`.\n mstore(0x60, shr(1, shl(1, vs))) // `s`.\n let t :=\n staticcall(\n gas(), // Amount of gas left for the transaction.\n 1, // Address of `ecrecover`.\n 0x00, // Start of input.\n 0x80, // Size of input.\n 0x01, // Start of output.\n 0x20 // Size of output.\n )\n // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.\n if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {\n isValid := 1\n mstore(0x60, 0) // Restore the zero slot.\n mstore(0x40, m) // Restore the free memory pointer.\n break\n }\n }\n if eq(mload(signature), 65) {\n mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.\n mstore(0x60, mload(add(signature, 0x40))) // `s`.\n let t :=\n staticcall(\n gas(), // Amount of gas left for the transaction.\n 1, // Address of `ecrecover`.\n 0x00, // Start of input.\n 0x80, // Size of input.\n 0x01, // Start of output.\n 0x20 // Size of output.\n )\n // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.\n if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {\n isValid := 1\n mstore(0x60, 0) // Restore the zero slot.\n mstore(0x40, m) // Restore the free memory pointer.\n break\n }\n }\n mstore(0x60, 0) // Restore the zero slot.\n mstore(0x40, m) // Restore the free memory pointer.\n\n let f := shl(224, 0x1626ba7e)\n mstore(m, f) // `bytes4(keccak256(\"isValidSignature(bytes32,bytes)\"))`.\n mstore(add(m, 0x04), hash)\n let d := add(m, 0x24)\n mstore(d, 0x40) // The offset of the `signature` in the calldata.\n // Copy the `signature` over.\n let n := add(0x20, mload(signature))\n pop(staticcall(gas(), 4, signature, n, add(m, 0x44), n))\n // forgefmt: disable-next-item\n isValid := and(\n // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).\n eq(mload(d), f),\n // Whether the staticcall does not revert.\n // This must be placed at the end of the `and` clause,\n // as the arguments are evaluated from right to left.\n staticcall(\n gas(), // Remaining gas.\n signer, // The `signer` address.\n m, // Offset of calldata in memory.\n add(returndatasize(), 0x44), // Length of calldata in memory.\n d, // Offset of returndata.\n 0x20 // Length of returndata to write.\n )\n )\n break\n }\n }\n }\n\n /// @dev Returns whether `signature` is valid for `signer` and `hash`.\n /// If `signer` is a smart contract, the signature is validated with ERC1271.\n /// Otherwise, the signature is validated with `ECDSA.recover`.\n function isValidSignatureNowCalldata(address signer, bytes32 hash, bytes calldata signature)\n internal\n view\n returns (bool isValid)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // Clean the upper 96 bits of `signer` in case they are dirty.\n for { signer := shr(96, shl(96, signer)) } signer {} {\n let m := mload(0x40)\n mstore(0x00, hash)\n if eq(signature.length, 64) {\n let vs := calldataload(add(signature.offset, 0x20))\n mstore(0x20, add(shr(255, vs), 27)) // `v`.\n mstore(0x40, calldataload(signature.offset)) // `r`.\n mstore(0x60, shr(1, shl(1, vs))) // `s`.\n let t :=\n staticcall(\n gas(), // Amount of gas left for the transaction.\n 1, // Address of `ecrecover`.\n 0x00, // Start of input.\n 0x80, // Size of input.\n 0x01, // Start of output.\n 0x20 // Size of output.\n )\n // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.\n if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {\n isValid := 1\n mstore(0x60, 0) // Restore the zero slot.\n mstore(0x40, m) // Restore the free memory pointer.\n break\n }\n }\n if eq(signature.length, 65) {\n mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.\n calldatacopy(0x40, signature.offset, 0x40) // `r`, `s`.\n let t :=\n staticcall(\n gas(), // Amount of gas left for the transaction.\n 1, // Address of `ecrecover`.\n 0x00, // Start of input.\n 0x80, // Size of input.\n 0x01, // Start of output.\n 0x20 // Size of output.\n )\n // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.\n if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {\n isValid := 1\n mstore(0x60, 0) // Restore the zero slot.\n mstore(0x40, m) // Restore the free memory pointer.\n break\n }\n }\n mstore(0x60, 0) // Restore the zero slot.\n mstore(0x40, m) // Restore the free memory pointer.\n\n let f := shl(224, 0x1626ba7e)\n mstore(m, f) // `bytes4(keccak256(\"isValidSignature(bytes32,bytes)\"))`.\n mstore(add(m, 0x04), hash)\n let d := add(m, 0x24)\n mstore(d, 0x40) // The offset of the `signature` in the calldata.\n mstore(add(m, 0x44), signature.length)\n // Copy the `signature` over.\n calldatacopy(add(m, 0x64), signature.offset, signature.length)\n // forgefmt: disable-next-item\n isValid := and(\n // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).\n eq(mload(d), f),\n // Whether the staticcall does not revert.\n // This must be placed at the end of the `and` clause,\n // as the arguments are evaluated from right to left.\n staticcall(\n gas(), // Remaining gas.\n signer, // The `signer` address.\n m, // Offset of calldata in memory.\n add(signature.length, 0x64), // Length of calldata in memory.\n d, // Offset of returndata.\n 0x20 // Length of returndata to write.\n )\n )\n break\n }\n }\n }\n\n /// @dev Returns whether the signature (`r`, `vs`) is valid for `signer` and `hash`.\n /// If `signer` is a smart contract, the signature is validated with ERC1271.\n /// Otherwise, the signature is validated with `ECDSA.recover`.\n function isValidSignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs)\n internal\n view\n returns (bool isValid)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // Clean the upper 96 bits of `signer` in case they are dirty.\n for { signer := shr(96, shl(96, signer)) } signer {} {\n let m := mload(0x40)\n mstore(0x00, hash)\n mstore(0x20, add(shr(255, vs), 27)) // `v`.\n mstore(0x40, r) // `r`.\n mstore(0x60, shr(1, shl(1, vs))) // `s`.\n let t :=\n staticcall(\n gas(), // Amount of gas left for the transaction.\n 1, // Address of `ecrecover`.\n 0x00, // Start of input.\n 0x80, // Size of input.\n 0x01, // Start of output.\n 0x20 // Size of output.\n )\n // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.\n if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {\n isValid := 1\n mstore(0x60, 0) // Restore the zero slot.\n mstore(0x40, m) // Restore the free memory pointer.\n break\n }\n\n let f := shl(224, 0x1626ba7e)\n mstore(m, f) // `bytes4(keccak256(\"isValidSignature(bytes32,bytes)\"))`.\n mstore(add(m, 0x04), hash)\n let d := add(m, 0x24)\n mstore(d, 0x40) // The offset of the `signature` in the calldata.\n mstore(add(m, 0x44), 65) // Length of the signature.\n mstore(add(m, 0x64), r) // `r`.\n mstore(add(m, 0x84), mload(0x60)) // `s`.\n mstore8(add(m, 0xa4), mload(0x20)) // `v`.\n // forgefmt: disable-next-item\n isValid := and(\n // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).\n eq(mload(d), f),\n // Whether the staticcall does not revert.\n // This must be placed at the end of the `and` clause,\n // as the arguments are evaluated from right to left.\n staticcall(\n gas(), // Remaining gas.\n signer, // The `signer` address.\n m, // Offset of calldata in memory.\n 0xa5, // Length of calldata in memory.\n d, // Offset of returndata.\n 0x20 // Length of returndata to write.\n )\n )\n mstore(0x60, 0) // Restore the zero slot.\n mstore(0x40, m) // Restore the free memory pointer.\n break\n }\n }\n }\n\n /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `signer` and `hash`.\n /// If `signer` is a smart contract, the signature is validated with ERC1271.\n /// Otherwise, the signature is validated with `ECDSA.recover`.\n function isValidSignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s)\n internal\n view\n returns (bool isValid)\n {\n /// @solidity memory-safe-assembly\n assembly {\n // Clean the upper 96 bits of `signer` in case they are dirty.\n for { signer := shr(96, shl(96, signer)) } signer {} {\n let m := mload(0x40)\n mstore(0x00, hash)\n mstore(0x20, and(v, 0xff)) // `v`.\n mstore(0x40, r) // `r`.\n mstore(0x60, s) // `s`.\n let t :=\n staticcall(\n gas(), // Amount of gas left for the transaction.\n 1, // Address of `ecrecover`.\n 0x00, // Start of input.\n 0x80, // Size of input.\n 0x01, // Start of output.\n 0x20 // Size of output.\n )\n // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise.\n if iszero(or(iszero(returndatasize()), xor(signer, mload(t)))) {\n isValid := 1\n mstore(0x60, 0) // Restore the zero slot.\n mstore(0x40, m) // Restore the free memory pointer.\n break\n }\n\n let f := shl(224, 0x1626ba7e)\n mstore(m, f) // `bytes4(keccak256(\"isValidSignature(bytes32,bytes)\"))`.\n mstore(add(m, 0x04), hash)\n let d := add(m, 0x24)\n mstore(d, 0x40) // The offset of the `signature` in the calldata.\n mstore(add(m, 0x44), 65) // Length of the signature.\n mstore(add(m, 0x64), r) // `r`.\n mstore(add(m, 0x84), s) // `s`.\n mstore8(add(m, 0xa4), v) // `v`.\n // forgefmt: disable-next-item\n isValid := and(\n // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).\n eq(mload(d), f),\n // Whether the staticcall does not revert.\n // This must be placed at the end of the `and` clause,\n // as the arguments are evaluated from right to left.\n staticcall(\n gas(), // Remaining gas.\n signer, // The `signer` address.\n m, // Offset of calldata in memory.\n 0xa5, // Length of calldata in memory.\n d, // Offset of returndata.\n 0x20 // Length of returndata to write.\n )\n )\n mstore(0x60, 0) // Restore the zero slot.\n mstore(0x40, m) // Restore the free memory pointer.\n break\n }\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* ERC1271 OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // Note: These ERC1271 operations do NOT have an ECDSA fallback.\n // These functions are intended to be used with the regular `isValidSignatureNow` functions\n // or other signature verification functions (e.g. P256).\n\n /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.\n function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes memory signature)\n internal\n view\n returns (bool isValid)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let m := mload(0x40)\n let f := shl(224, 0x1626ba7e)\n mstore(m, f) // `bytes4(keccak256(\"isValidSignature(bytes32,bytes)\"))`.\n mstore(add(m, 0x04), hash)\n let d := add(m, 0x24)\n mstore(d, 0x40) // The offset of the `signature` in the calldata.\n // Copy the `signature` over.\n let n := add(0x20, mload(signature))\n pop(staticcall(gas(), 4, signature, n, add(m, 0x44), n))\n // forgefmt: disable-next-item\n isValid := and(\n // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).\n eq(mload(d), f),\n // Whether the staticcall does not revert.\n // This must be placed at the end of the `and` clause,\n // as the arguments are evaluated from right to left.\n staticcall(\n gas(), // Remaining gas.\n signer, // The `signer` address.\n m, // Offset of calldata in memory.\n add(returndatasize(), 0x44), // Length of calldata in memory.\n d, // Offset of returndata.\n 0x20 // Length of returndata to write.\n )\n )\n }\n }\n\n /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.\n function isValidERC1271SignatureNowCalldata(\n address signer,\n bytes32 hash,\n bytes calldata signature\n ) internal view returns (bool isValid) {\n /// @solidity memory-safe-assembly\n assembly {\n let m := mload(0x40)\n let f := shl(224, 0x1626ba7e)\n mstore(m, f) // `bytes4(keccak256(\"isValidSignature(bytes32,bytes)\"))`.\n mstore(add(m, 0x04), hash)\n let d := add(m, 0x24)\n mstore(d, 0x40) // The offset of the `signature` in the calldata.\n mstore(add(m, 0x44), signature.length)\n // Copy the `signature` over.\n calldatacopy(add(m, 0x64), signature.offset, signature.length)\n // forgefmt: disable-next-item\n isValid := and(\n // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).\n eq(mload(d), f),\n // Whether the staticcall does not revert.\n // This must be placed at the end of the `and` clause,\n // as the arguments are evaluated from right to left.\n staticcall(\n gas(), // Remaining gas.\n signer, // The `signer` address.\n m, // Offset of calldata in memory.\n add(signature.length, 0x64), // Length of calldata in memory.\n d, // Offset of returndata.\n 0x20 // Length of returndata to write.\n )\n )\n }\n }\n\n /// @dev Returns whether the signature (`r`, `vs`) is valid for `hash`\n /// for an ERC1271 `signer` contract.\n function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs)\n internal\n view\n returns (bool isValid)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let m := mload(0x40)\n let f := shl(224, 0x1626ba7e)\n mstore(m, f) // `bytes4(keccak256(\"isValidSignature(bytes32,bytes)\"))`.\n mstore(add(m, 0x04), hash)\n let d := add(m, 0x24)\n mstore(d, 0x40) // The offset of the `signature` in the calldata.\n mstore(add(m, 0x44), 65) // Length of the signature.\n mstore(add(m, 0x64), r) // `r`.\n mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`.\n mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`.\n // forgefmt: disable-next-item\n isValid := and(\n // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).\n eq(mload(d), f),\n // Whether the staticcall does not revert.\n // This must be placed at the end of the `and` clause,\n // as the arguments are evaluated from right to left.\n staticcall(\n gas(), // Remaining gas.\n signer, // The `signer` address.\n m, // Offset of calldata in memory.\n 0xa5, // Length of calldata in memory.\n d, // Offset of returndata.\n 0x20 // Length of returndata to write.\n )\n )\n }\n }\n\n /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `hash`\n /// for an ERC1271 `signer` contract.\n function isValidERC1271SignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s)\n internal\n view\n returns (bool isValid)\n {\n /// @solidity memory-safe-assembly\n assembly {\n let m := mload(0x40)\n let f := shl(224, 0x1626ba7e)\n mstore(m, f) // `bytes4(keccak256(\"isValidSignature(bytes32,bytes)\"))`.\n mstore(add(m, 0x04), hash)\n let d := add(m, 0x24)\n mstore(d, 0x40) // The offset of the `signature` in the calldata.\n mstore(add(m, 0x44), 65) // Length of the signature.\n mstore(add(m, 0x64), r) // `r`.\n mstore(add(m, 0x84), s) // `s`.\n mstore8(add(m, 0xa4), v) // `v`.\n // forgefmt: disable-next-item\n isValid := and(\n // Whether the returndata is the magic value `0x1626ba7e` (left-aligned).\n eq(mload(d), f),\n // Whether the staticcall does not revert.\n // This must be placed at the end of the `and` clause,\n // as the arguments are evaluated from right to left.\n staticcall(\n gas(), // Remaining gas.\n signer, // The `signer` address.\n m, // Offset of calldata in memory.\n 0xa5, // Length of calldata in memory.\n d, // Offset of returndata.\n 0x20 // Length of returndata to write.\n )\n )\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* ERC6492 OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n // Note: These ERC6492 operations do NOT have an ECDSA fallback.\n // These functions are intended to be used with the regular `isValidSignatureNow` functions\n // or other signature verification functions (e.g. P256).\n // The calldata variants are excluded for brevity.\n\n /// @dev Returns whether `signature` is valid for `hash`.\n /// If the signature is postfixed with the ERC6492 magic number, it will attempt to\n /// deploy / prepare the `signer` smart account before doing a regular ERC1271 check.\n /// Note: This function is NOT reentrancy safe.\n function isValidERC6492SignatureNowAllowSideEffects(\n address signer,\n bytes32 hash,\n bytes memory signature\n ) internal returns (bool isValid) {\n /// @solidity memory-safe-assembly\n assembly {\n function callIsValidSignature(signer_, hash_, signature_) -> _isValid {\n let m_ := mload(0x40)\n let f_ := shl(224, 0x1626ba7e)\n mstore(m_, f_) // `bytes4(keccak256(\"isValidSignature(bytes32,bytes)\"))`.\n mstore(add(m_, 0x04), hash_)\n let d_ := add(m_, 0x24)\n mstore(d_, 0x40) // The offset of the `signature` in the calldata.\n let n_ := add(0x20, mload(signature_))\n pop(staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_))\n _isValid :=\n and(\n eq(mload(d_), f_),\n staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20)\n )\n }\n for { let n := mload(signature) } 1 {} {\n if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) {\n isValid := callIsValidSignature(signer, hash, signature)\n break\n }\n let o := add(signature, 0x20) // Signature bytes.\n let d := add(o, mload(add(o, 0x20))) // Factory calldata.\n if iszero(extcodesize(signer)) {\n if iszero(call(gas(), mload(o), 0, add(d, 0x20), mload(d), codesize(), 0x00)) {\n break\n }\n }\n let s := add(o, mload(add(o, 0x40))) // Inner signature.\n isValid := callIsValidSignature(signer, hash, s)\n if iszero(isValid) {\n if call(gas(), mload(o), 0, add(d, 0x20), mload(d), codesize(), 0x00) {\n isValid := callIsValidSignature(signer, hash, s)\n }\n }\n break\n }\n }\n }\n\n /// @dev Returns whether `signature` is valid for `hash`.\n /// If the signature is postfixed with the ERC6492 magic number, it will attempt\n /// to use a reverting verifier to deploy / prepare the `signer` smart account\n /// and do a `isValidSignature` check via the reverting verifier.\n /// Note: This function is reentrancy safe.\n /// The reverting verifier must be deployed.\n /// Otherwise, the function will return false if `signer` is not yet deployed / prepared.\n /// See: https://gist.github.com/Vectorized/846a474c855eee9e441506676800a9ad\n function isValidERC6492SignatureNow(address signer, bytes32 hash, bytes memory signature)\n internal\n returns (bool isValid)\n {\n /// @solidity memory-safe-assembly\n assembly {\n function callIsValidSignature(signer_, hash_, signature_) -> _isValid {\n let m_ := mload(0x40)\n let f_ := shl(224, 0x1626ba7e)\n mstore(m_, f_) // `bytes4(keccak256(\"isValidSignature(bytes32,bytes)\"))`.\n mstore(add(m_, 0x04), hash_)\n let d_ := add(m_, 0x24)\n mstore(d_, 0x40) // The offset of the `signature` in the calldata.\n let n_ := add(0x20, mload(signature_))\n pop(staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_))\n _isValid :=\n and(\n eq(mload(d_), f_),\n staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20)\n )\n }\n for { let n := mload(signature) } 1 {} {\n if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) {\n isValid := callIsValidSignature(signer, hash, signature)\n break\n }\n if extcodesize(signer) {\n let o := add(signature, 0x20) // Signature bytes.\n isValid := callIsValidSignature(signer, hash, add(o, mload(add(o, 0x40))))\n if isValid { break }\n }\n let m := mload(0x40)\n mstore(m, signer)\n mstore(add(m, 0x20), hash)\n let willBeZeroIfRevertingVerifierExists :=\n call(\n gas(), // Remaining gas.\n 0x00007bd799e4A591FeA53f8A8a3E9f931626Ba7e, // Reverting verifier.\n 0, // Send zero ETH.\n m, // Start of memory.\n add(returndatasize(), 0x40), // Length of calldata in memory.\n staticcall(gas(), 4, add(signature, 0x20), n, add(m, 0x40), n), // 1.\n 0x00 // Length of returndata to write.\n )\n isValid := gt(returndatasize(), willBeZeroIfRevertingVerifierExists)\n break\n }\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* HASHING OPERATIONS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns an Ethereum Signed Message, created from a `hash`.\n /// This produces a hash corresponding to the one signed with the\n /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)\n /// JSON-RPC method as part of EIP-191.\n function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n mstore(0x20, hash) // Store into scratch space for keccak256.\n mstore(0x00, \"\\x00\\x00\\x00\\x00\\x19Ethereum Signed Message:\\n32\") // 28 bytes.\n result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.\n }\n }\n\n /// @dev Returns an Ethereum Signed Message, created from `s`.\n /// This produces a hash corresponding to the one signed with the\n /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)\n /// JSON-RPC method as part of EIP-191.\n /// Note: Supports lengths of `s` up to 999999 bytes.\n function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {\n /// @solidity memory-safe-assembly\n assembly {\n let sLength := mload(s)\n let o := 0x20\n mstore(o, \"\\x19Ethereum Signed Message:\\n\") // 26 bytes, zero-right-padded.\n mstore(0x00, 0x00)\n // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.\n for { let temp := sLength } 1 {} {\n o := sub(o, 1)\n mstore8(o, add(48, mod(temp, 10)))\n temp := div(temp, 10)\n if iszero(temp) { break }\n }\n let n := sub(0x3a, o) // Header length: `26 + 32 - o`.\n // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.\n returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))\n mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.\n result := keccak256(add(s, sub(0x20, n)), add(n, sLength))\n mstore(s, sLength) // Restore the length.\n }\n }\n\n /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/\n /* EMPTY CALLDATA HELPERS */\n /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/\n\n /// @dev Returns an empty calldata bytes.\n function emptySignature() internal pure returns (bytes calldata signature) {\n /// @solidity memory-safe-assembly\n assembly {\n signature.length := 0\n }\n }\n}\n"}},"settings":{"remappings":["@solady/=lib/solady/","@forge/=lib/forge-std/src/","forge-std/=lib/forge-std/src/","solady/=lib/solady/src/"],"optimizer":{"enabled":true,"runs":9999999},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"]}},"evmVersion":"cancun","viaIR":false,"libraries":{}}}