From f11a85974c6d3925311290fa392ea66d40dd2f24 Mon Sep 17 00:00:00 2001 From: Rishabh Singh Date: Wed, 1 Jul 2026 06:31:09 +0530 Subject: [PATCH 1/5] fix: remove duplicate FACTORY_ADDRESS_AMOY in .env.example --- .env.example | 1 - 1 file changed, 1 deletion(-) diff --git a/.env.example b/.env.example index 6e832bf..2e2ba52 100644 --- a/.env.example +++ b/.env.example @@ -68,4 +68,3 @@ TDOC_IMPLEMENTATION_AMOY=0x_tdoc_implementation_on_amoy # Filled in after running gasless scripts with NETWORK=amoy REGISTRY_ADDRESS_AMOY=0x_filled_after_deployRegistry TITLE_ESCROW_ADDRESS_AMOY=0x_filled_after_mintDocument -FACTORY_ADDRESS_AMOY=0x_filled_after_deployFactory From 0edc40f2bf639508acc58a20c9309f4bbba7acdb Mon Sep 17 00:00:00 2001 From: Rishabh Singh Date: Wed, 12 Aug 2026 10:54:07 +0530 Subject: [PATCH 2/5] fix: role access to minter --- contracts/Factory.sol | 30 +++++- contracts/PlatformPaymaster.sol | 11 ++- contracts/mocks/MockRegistry.sol | 23 ++++- test/PlatformPaymaster.ts | 30 ++++++ upload.json | 159 +++++++++++++++++++++++++++++-- 5 files changed, 236 insertions(+), 17 deletions(-) diff --git a/contracts/Factory.sol b/contracts/Factory.sol index 4a4fdb5..2d47870 100644 --- a/contracts/Factory.sol +++ b/contracts/Factory.sol @@ -8,8 +8,12 @@ import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; contract PlatformAccountFactory is Ownable { address public tdocDeployer; address public paymasterImplementation; + mapping(address => address) public attachedPaymaster; - event PlatformOnboarded(address indexed platformAddress, address indexed paymaster); + event PlatformOnboarded( + address indexed platformAddress, + address indexed paymaster + ); event TdocDeployerUpdated(address indexed newDeployer); event ImplementationUpdated(address indexed newImplementation); @@ -21,6 +25,13 @@ contract PlatformAccountFactory is Ownable { paymasterImplementation = _paymasterImplementation; } + function setAttachedPaymaster( + address platformAddress + ) external view returns (address) { + address paymaster = attachedPaymaster[platformAddress]; + return paymaster; + } + function updateTdocDeployer(address _tdocDeployer) external onlyOwner { require(_tdocDeployer != address(0), "Zero address"); tdocDeployer = _tdocDeployer; @@ -39,12 +50,23 @@ contract PlatformAccountFactory is Ownable { bytes32 salt ) external returns (address paymaster) { paymaster = Clones.cloneDeterministic(paymasterImplementation, salt); - PlatformPaymaster(payable(paymaster)).initialize(platformAddress, dailyLimit, tdocDeployer); + PlatformPaymaster(payable(paymaster)).initialize( + platformAddress, + dailyLimit, + tdocDeployer + ); emit PlatformOnboarded(platformAddress, paymaster); } // Address is determined solely by implementation + salt (not by constructor args). - function computePaymasterAddress(bytes32 salt) external view returns (address) { - return Clones.predictDeterministicAddress(paymasterImplementation, salt, address(this)); + function computePaymasterAddress( + bytes32 salt + ) external view returns (address) { + return + Clones.predictDeterministicAddress( + paymasterImplementation, + salt, + address(this) + ); } } diff --git a/contracts/PlatformPaymaster.sol b/contracts/PlatformPaymaster.sol index 2be365b..7b10829 100644 --- a/contracts/PlatformPaymaster.sol +++ b/contracts/PlatformPaymaster.sol @@ -49,6 +49,9 @@ contract PlatformPaymaster is BasePaymaster { ); bytes32 private constant DEFAULT_ADMIN_ROLE = bytes32(0); + bytes32 private constant RESTORER_ROLE = keccak256("RESTORER_ROLE"); + bytes32 private constant ACCEPTER_ROLE = keccak256("ACCEPTER_ROLE"); + bytes32 private constant MINTER_ROLE = keccak256("MINTER_ROLE"); ITDocDeployer public tdocDeployer; @@ -141,13 +144,11 @@ contract PlatformPaymaster is BasePaymaster { bytes memory params = abi.encode(name, symbol, address(this)); deployed = tdocDeployer.deploy(implementation, params); - // Hand admin to the calling EOA IAccessControl(deployed).grantRole(DEFAULT_ADMIN_ROLE, msg.sender); + IAccessControl(deployed).grantRole(RESTORER_ROLE, msg.sender); + IAccessControl(deployed).grantRole(ACCEPTER_ROLE, msg.sender); + IAccessControl(deployed).grantRole(MINTER_ROLE, msg.sender); - // Paymaster keeps only the operational roles it needs - // (MINTER_ROLE, RESTORER_ROLE, ACCEPTER_ROLE were granted to address(this) via initialize) - - // Relinquish admin — EOA is now sole admin IAccessControl(deployed).renounceRole( DEFAULT_ADMIN_ROLE, address(this) diff --git a/contracts/mocks/MockRegistry.sol b/contracts/mocks/MockRegistry.sol index e79ab56..5542a59 100644 --- a/contracts/mocks/MockRegistry.sol +++ b/contracts/mocks/MockRegistry.sol @@ -7,19 +7,38 @@ contract MockTitleEscrow {} contract MockRegistry { bytes32 public constant DEFAULT_ADMIN_ROLE = bytes32(0); + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant RESTORER_ROLE = keccak256("RESTORER_ROLE"); + bytes32 public constant ACCEPTER_ROLE = keccak256("ACCEPTER_ROLE"); + mapping(bytes32 => mapping(address => bool)) private _roles; address public lastTitleEscrow; + error AccessControlUnauthorizedAccount(address account, bytes32 role); + error AccessControlBadConfirmation(); + + // Mirrors RegistryAccess.__RegistryAccess_init: the real registry grants + // all four roles to the single admin address passed at deploy time. constructor(address initialAdmin) { _roles[DEFAULT_ADMIN_ROLE][initialAdmin] = true; + _roles[MINTER_ROLE][initialAdmin] = true; + _roles[RESTORER_ROLE][initialAdmin] = true; + _roles[ACCEPTER_ROLE][initialAdmin] = true; } - // IAccessControl + // IAccessControl — mirrors OZ's default: granting any role requires + // DEFAULT_ADMIN_ROLE, since the real registry never overrides role admins. function grantRole(bytes32 role, address account) external { + if (!_roles[DEFAULT_ADMIN_ROLE][msg.sender]) { + revert AccessControlUnauthorizedAccount(msg.sender, DEFAULT_ADMIN_ROLE); + } _roles[role][account] = true; } - function renounceRole(bytes32 role, address) external { + function renounceRole(bytes32 role, address callerConfirmation) external { + if (callerConfirmation != msg.sender) { + revert AccessControlBadConfirmation(); + } _roles[role][msg.sender] = false; } diff --git a/test/PlatformPaymaster.ts b/test/PlatformPaymaster.ts index 6457abb..5a4ae19 100644 --- a/test/PlatformPaymaster.ts +++ b/test/PlatformPaymaster.ts @@ -278,6 +278,36 @@ describe("PlatformPaymaster", function () { paymasterAsOther.write.deployRegistry([impl.address, "TT", "TT"]), ).to.be.rejectedWith("No deployment credits"); }); + + it("hands admin + all operational roles to msg.sender; paymaster keeps minter/restorer/accepter but not admin", async function () { + const { paymaster, paymasterAsOther, other, impl, publicClient } = + await loadFixture(deployFixture); + await paymaster.write.setUserWhitelist([other.account.address, 1n]); + + const hash = await paymasterAsOther.write.deployRegistry([impl.address, "TT", "TT"]); + await publicClient.waitForTransactionReceipt({ hash }); + + const events = await paymaster.getEvents.RegistryDeployed(); + const deployedAddr = events[0].args.deployed as `0x${string}`; + const registry = await hre.viem.getContractAt("MockRegistry", deployedAddr); + + const DEFAULT_ADMIN_ROLE = await registry.read.DEFAULT_ADMIN_ROLE(); + const MINTER_ROLE = await registry.read.MINTER_ROLE(); + const RESTORER_ROLE = await registry.read.RESTORER_ROLE(); + const ACCEPTER_ROLE = await registry.read.ACCEPTER_ROLE(); + + // msg.sender (the deploying EOA) ends up holding all four roles + expect(await registry.read.hasRole([DEFAULT_ADMIN_ROLE, other.account.address])).to.be.true; + expect(await registry.read.hasRole([RESTORER_ROLE, other.account.address])).to.be.true; + expect(await registry.read.hasRole([ACCEPTER_ROLE, other.account.address])).to.be.true; + expect(await registry.read.hasRole([MINTER_ROLE, other.account.address])).to.be.true; + + // paymaster relinquishes admin but keeps the operational roles + expect(await registry.read.hasRole([DEFAULT_ADMIN_ROLE, paymaster.address])).to.be.false; + expect(await registry.read.hasRole([RESTORER_ROLE, paymaster.address])).to.be.true; + expect(await registry.read.hasRole([ACCEPTER_ROLE, paymaster.address])).to.be.true; + expect(await registry.read.hasRole([MINTER_ROLE, paymaster.address])).to.be.true; + }); }); // ─── mintDocument ───────────────────────────────────────────────────────── diff --git a/upload.json b/upload.json index ec17cf0..9e4908d 100644 --- a/upload.json +++ b/upload.json @@ -4,12 +4,33 @@ "@account-abstraction/contracts/core/BasePaymaster.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n/* solhint-disable reason-string */\n\nimport \"@openzeppelin/contracts/access/Ownable2Step.sol\";\nimport \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport \"../interfaces/IPaymaster.sol\";\nimport \"../interfaces/IEntryPoint.sol\";\nimport \"./UserOperationLib.sol\";\n/**\n * Helper class for creating a paymaster.\n * provides helper methods for staking.\n * Validates that the postOp is called only by the entryPoint.\n */\nabstract contract BasePaymaster is IPaymaster, Ownable2Step {\n IEntryPoint public immutable entryPoint;\n\n uint256 internal constant PAYMASTER_VALIDATION_GAS_OFFSET = UserOperationLib.PAYMASTER_VALIDATION_GAS_OFFSET;\n uint256 internal constant PAYMASTER_POSTOP_GAS_OFFSET = UserOperationLib.PAYMASTER_POSTOP_GAS_OFFSET;\n uint256 internal constant PAYMASTER_DATA_OFFSET = UserOperationLib.PAYMASTER_DATA_OFFSET;\n\n constructor(IEntryPoint _entryPoint) Ownable(msg.sender) {\n _validateEntryPointInterface(_entryPoint);\n entryPoint = _entryPoint;\n }\n\n // Sanity check: make sure this EntryPoint was compiled against the same\n // IEntryPoint of this paymaster\n function _validateEntryPointInterface(IEntryPoint _entryPoint) internal virtual {\n require(IERC165(address(_entryPoint)).supportsInterface(type(IEntryPoint).interfaceId), \"IEntryPoint interface mismatch\");\n }\n\n /// @inheritdoc IPaymaster\n function validatePaymasterUserOp(\n PackedUserOperation calldata userOp,\n bytes32 userOpHash,\n uint256 maxCost\n ) external override returns (bytes memory context, uint256 validationData) {\n _requireFromEntryPoint();\n return _validatePaymasterUserOp(userOp, userOpHash, maxCost);\n }\n\n /**\n * Validate a user operation.\n * @param userOp - The user operation.\n * @param userOpHash - The hash of the user operation.\n * @param maxCost - The maximum cost of the user operation.\n */\n function _validatePaymasterUserOp(\n PackedUserOperation calldata userOp,\n bytes32 userOpHash,\n uint256 maxCost\n ) internal virtual returns (bytes memory context, uint256 validationData);\n\n /// @inheritdoc IPaymaster\n function postOp(\n PostOpMode mode,\n bytes calldata context,\n uint256 actualGasCost,\n uint256 actualUserOpFeePerGas\n ) external override {\n _requireFromEntryPoint();\n _postOp(mode, context, actualGasCost, actualUserOpFeePerGas);\n }\n\n /**\n * Post-operation handler.\n * (verified to be called only through the entryPoint)\n * @dev If subclass returns a non-empty context from validatePaymasterUserOp,\n * it must also implement this method.\n * @param mode - Enum with the following options:\n * opSucceeded - User operation succeeded.\n * opReverted - User op reverted. The paymaster still has to pay for gas.\n * postOpReverted - never passed in a call to postOp().\n * @param context - The context value returned by validatePaymasterUserOp\n * @param actualGasCost - Actual cost of gas used so far (without this postOp call).\n * @param actualUserOpFeePerGas - the gas price this UserOp pays. This value is based on the UserOp's maxFeePerGas\n * and maxPriorityFee (and basefee)\n * It is not the same as tx.gasprice, which is what the bundler pays.\n */\n function _postOp(\n PostOpMode mode,\n bytes calldata context,\n uint256 actualGasCost,\n uint256 actualUserOpFeePerGas\n ) internal virtual {\n (mode, context, actualGasCost, actualUserOpFeePerGas); // unused params\n // subclass must override this method if validatePaymasterUserOp returns a context\n revert(\"must override\");\n }\n\n /**\n * Add a deposit for this paymaster, used for paying for transaction fees.\n */\n function deposit() public payable {\n entryPoint.depositTo{value: msg.value}(address(this));\n }\n\n /**\n * Withdraw value from the deposit.\n * @param withdrawAddress - Target to send to.\n * @param amount - Amount to withdraw.\n */\n function withdrawTo(\n address payable withdrawAddress,\n uint256 amount\n ) public onlyOwner {\n entryPoint.withdrawTo(withdrawAddress, amount);\n }\n\n /**\n * Add stake for this paymaster.\n * This method can also carry eth value to add to the current stake.\n * @param unstakeDelaySec - The unstake delay for this paymaster. Can only be increased.\n */\n function addStake(uint32 unstakeDelaySec) external payable onlyOwner {\n entryPoint.addStake{value: msg.value}(unstakeDelaySec);\n }\n\n /**\n * Return current paymaster's deposit on the entryPoint.\n */\n function getDeposit() public view returns (uint256) {\n return entryPoint.balanceOf(address(this));\n }\n\n /**\n * Unlock the stake, in order to withdraw it.\n * The paymaster can't serve requests once unlocked, until it calls addStake again\n */\n function unlockStake() external onlyOwner {\n entryPoint.unlockStake();\n }\n\n /**\n * Withdraw the entire paymaster's stake.\n * stake must be unlocked first (and then wait for the unstakeDelay to be over)\n * @param withdrawAddress - The address to send withdrawn value.\n */\n function withdrawStake(address payable withdrawAddress) external onlyOwner {\n entryPoint.withdrawStake(withdrawAddress);\n }\n\n /**\n * Validate the call is made from a valid entrypoint\n */\n function _requireFromEntryPoint() internal virtual {\n require(msg.sender == address(entryPoint), \"Sender not EntryPoint\");\n }\n}\n" }, + "@account-abstraction/contracts/core/Eip7702Support.sol": { + "content": "pragma solidity ^0.8.28;\n// SPDX-License-Identifier: MIT\n// solhint-disable no-inline-assembly\n\nimport \"../interfaces/PackedUserOperation.sol\";\nimport \"../core/UserOperationLib.sol\";\n\nlibrary Eip7702Support {\n\n // EIP-7702 code prefix before delegate address.\n bytes3 internal constant EIP7702_PREFIX = 0xef0100;\n\n // EIP-7702 initCode marker, to specify this account is EIP-7702.\n bytes2 internal constant INITCODE_EIP7702_MARKER = 0x7702;\n\n using UserOperationLib for PackedUserOperation;\n\n /**\n * Get the alternative 'InitCodeHash' value for the UserOp hash calculation when using EIP-7702.\n *\n * @param userOp - the UserOperation to for the 'InitCodeHash' calculation.\n * @return the 'InitCodeHash' value.\n */\n function _getEip7702InitCodeHashOverride(PackedUserOperation calldata userOp) internal view returns (bytes32) {\n bytes calldata initCode = userOp.initCode;\n if (!_isEip7702InitCode(initCode)) {\n return 0;\n }\n address delegate = _getEip7702Delegate(userOp.sender);\n if (initCode.length <= 20)\n return keccak256(abi.encodePacked(delegate));\n else\n return keccak256(abi.encodePacked(delegate, initCode[20 :]));\n }\n\n /**\n * Check if this 'initCode' is actually an EIP-7702 authorization.\n * This is indicated by 'initCode' that starts with INITCODE_EIP7702_MARKER.\n *\n * @param initCode - the 'initCode' to check.\n * @return true if the 'initCode' is EIP-7702 authorization, false otherwise.\n */\n function _isEip7702InitCode(bytes calldata initCode) internal pure returns (bool) {\n\n if (initCode.length < 2) {\n return false;\n }\n bytes20 initCodeStart;\n // non-empty calldata bytes are always zero-padded to 32-bytes, so can be safely casted to \"bytes20\"\n assembly (\"memory-safe\") {\n initCodeStart := calldataload(initCode.offset)\n }\n // make sure first 20 bytes of initCode are \"0x7702\" (padded with zeros)\n return initCodeStart == bytes20(INITCODE_EIP7702_MARKER);\n }\n\n /**\n * Get the EIP-7702 delegate from contract code.\n * Must only be used if _isEip7702InitCode(initCode) is true.\n *\n * @param sender - the EIP-7702 'sender' account to get the delegated contract code address.\n * @return the address of the EIP-7702 authorized contract.\n */\n function _getEip7702Delegate(address sender) internal view returns (address) {\n\n bytes32 senderCode;\n\n assembly (\"memory-safe\") {\n extcodecopy(sender, 0, 0, 23)\n senderCode := mload(0)\n }\n // To be a valid EIP-7702 delegate, the first 3 bytes are EIP7702_PREFIX\n // followed by the delegate address\n if (bytes3(senderCode) != EIP7702_PREFIX) {\n // instead of just \"not an EIP-7702 delegate\", if some info.\n require(sender.code.length > 0, \"sender has no code\");\n revert(\"not an EIP-7702 delegate\");\n }\n return address(bytes20(senderCode << 24));\n }\n}\n" + }, + "@account-abstraction/contracts/core/EntryPoint.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.28;\n/* solhint-disable avoid-low-level-calls */\n/* solhint-disable no-inline-assembly */\n\nimport \"../interfaces/IAccount.sol\";\nimport \"../interfaces/IAccountExecute.sol\";\nimport \"../interfaces/IEntryPoint.sol\";\nimport \"../interfaces/IPaymaster.sol\";\n\nimport \"./UserOperationLib.sol\";\nimport \"./StakeManager.sol\";\nimport \"./NonceManager.sol\";\nimport \"./Helpers.sol\";\nimport \"./SenderCreator.sol\";\nimport \"./Eip7702Support.sol\";\nimport \"../utils/Exec.sol\";\n\nimport \"@openzeppelin/contracts/utils/ReentrancyGuardTransient.sol\";\nimport \"@openzeppelin/contracts/utils/introspection/ERC165.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/EIP712.sol\";\n\n/**\n * Account-Abstraction (EIP-4337) singleton EntryPoint v0.8 implementation.\n * Only one instance required on each chain.\n * @custom:security-contact https://bounty.ethereum.org\n */\ncontract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuardTransient, ERC165, EIP712 {\n\n using UserOperationLib for PackedUserOperation;\n\n /**\n * internal-use constants\n */\n\n // allow some slack for future gas price changes.\n uint256 private constant INNER_GAS_OVERHEAD = 10000;\n\n // Marker for inner call revert on out of gas\n bytes32 private constant INNER_OUT_OF_GAS = hex\"deaddead\";\n bytes32 private constant INNER_REVERT_LOW_PREFUND = hex\"deadaa51\";\n\n uint256 private constant REVERT_REASON_MAX_LEN = 2048;\n // Penalty charged for either unused execution gas or postOp gas\n uint256 private constant UNUSED_GAS_PENALTY_PERCENT = 10;\n // Threshold below which no penalty would be charged\n uint256 private constant PENALTY_GAS_THRESHOLD = 40000;\n\n SenderCreator private immutable _senderCreator = new SenderCreator();\n\n string constant internal DOMAIN_NAME = \"ERC4337\";\n string constant internal DOMAIN_VERSION = \"1\";\n\n constructor() EIP712(DOMAIN_NAME, DOMAIN_VERSION) {\n }\n\n /// @inheritdoc IEntryPoint\n function handleOps(\n PackedUserOperation[] calldata ops,\n address payable beneficiary\n ) external nonReentrant {\n uint256 opslen = ops.length;\n UserOpInfo[] memory opInfos = new UserOpInfo[](opslen);\n unchecked {\n _iterateValidationPhase(ops, opInfos, address(0), 0);\n\n uint256 collected = 0;\n emit BeforeExecution();\n\n for (uint256 i = 0; i < opslen; i++) {\n collected += _executeUserOp(i, ops[i], opInfos[i]);\n }\n\n _compensate(beneficiary, collected);\n }\n }\n\n /// @inheritdoc IEntryPoint\n function handleAggregatedOps(\n UserOpsPerAggregator[] calldata opsPerAggregator,\n address payable beneficiary\n ) external nonReentrant {\n\n unchecked {\n uint256 opasLen = opsPerAggregator.length;\n uint256 totalOps = 0;\n for (uint256 i = 0; i < opasLen; i++) {\n UserOpsPerAggregator calldata opa = opsPerAggregator[i];\n PackedUserOperation[] calldata ops = opa.userOps;\n IAggregator aggregator = opa.aggregator;\n\n // address(1) is special marker of \"signature error\"\n require(\n address(aggregator) != address(1),\n SignatureValidationFailed(address(aggregator))\n );\n\n if (address(aggregator) != address(0)) {\n // solhint-disable-next-line no-empty-blocks\n try aggregator.validateSignatures(ops, opa.signature) {} catch {\n revert SignatureValidationFailed(address(aggregator));\n }\n }\n\n totalOps += ops.length;\n }\n\n UserOpInfo[] memory opInfos = new UserOpInfo[](totalOps);\n\n uint256 opIndex = 0;\n for (uint256 a = 0; a < opasLen; a++) {\n UserOpsPerAggregator calldata opa = opsPerAggregator[a];\n PackedUserOperation[] calldata ops = opa.userOps;\n IAggregator aggregator = opa.aggregator;\n\n opIndex += _iterateValidationPhase(ops, opInfos, address(aggregator), opIndex);\n }\n\n emit BeforeExecution();\n\n uint256 collected = 0;\n opIndex = 0;\n for (uint256 a = 0; a < opasLen; a++) {\n UserOpsPerAggregator calldata opa = opsPerAggregator[a];\n emit SignatureAggregatorChanged(address(opa.aggregator));\n PackedUserOperation[] calldata ops = opa.userOps;\n uint256 opslen = ops.length;\n\n for (uint256 i = 0; i < opslen; i++) {\n collected += _executeUserOp(opIndex, ops[i], opInfos[opIndex]);\n opIndex++;\n }\n }\n\n _compensate(beneficiary, collected);\n }\n }\n\n /// @inheritdoc IEntryPoint\n function getUserOpHash(\n PackedUserOperation calldata userOp\n ) public view returns (bytes32) {\n bytes32 overrideInitCodeHash = Eip7702Support._getEip7702InitCodeHashOverride(userOp);\n return\n MessageHashUtils.toTypedDataHash(getDomainSeparatorV4(), userOp.hash(overrideInitCodeHash));\n }\n\n /// @inheritdoc IEntryPoint\n function getSenderAddress(bytes calldata initCode) external {\n address sender = senderCreator().createSender(initCode);\n revert SenderAddressResult(sender);\n }\n\n /// @inheritdoc IEntryPoint\n function senderCreator() public view virtual returns (ISenderCreator) {\n return _senderCreator;\n }\n\n /// @inheritdoc IEntryPoint\n function delegateAndRevert(address target, bytes calldata data) external {\n (bool success, bytes memory ret) = target.delegatecall(data);\n revert DelegateAndRevert(success, ret);\n }\n\n function getPackedUserOpTypeHash() external pure returns (bytes32) {\n return UserOperationLib.PACKED_USEROP_TYPEHASH;\n }\n\n function getDomainSeparatorV4() public virtual view returns (bytes32) {\n return _domainSeparatorV4();\n }\n\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n // note: solidity \"type(IEntryPoint).interfaceId\" is without inherited methods but we want to check everything\n return interfaceId == (type(IEntryPoint).interfaceId ^ type(IStakeManager).interfaceId ^ type(INonceManager).interfaceId) ||\n interfaceId == type(IEntryPoint).interfaceId ||\n interfaceId == type(IStakeManager).interfaceId ||\n interfaceId == type(INonceManager).interfaceId ||\n super.supportsInterface(interfaceId);\n }\n\n /**\n * Compensate the caller's beneficiary address with the collected fees of all UserOperations.\n * @param beneficiary - The address to receive the fees.\n * @param amount - Amount to transfer.\n */\n function _compensate(address payable beneficiary, uint256 amount) internal virtual {\n require(beneficiary != address(0), \"AA90 invalid beneficiary\");\n (bool success,) = beneficiary.call{value: amount}(\"\");\n require(success, \"AA91 failed send to beneficiary\");\n }\n\n /**\n * Execute a user operation.\n * @param opIndex - Index into the opInfo array.\n * @param userOp - The userOp to execute.\n * @param opInfo - The opInfo filled by validatePrepayment for this userOp.\n * @return collected - The total amount this userOp paid.\n */\n function _executeUserOp(\n uint256 opIndex,\n PackedUserOperation calldata userOp,\n UserOpInfo memory opInfo\n )\n internal virtual\n returns (uint256 collected) {\n uint256 preGas = gasleft();\n bytes memory context = _getMemoryBytesFromOffset(opInfo.contextOffset);\n bool success;\n {\n uint256 saveFreePtr = _getFreePtr();\n bytes calldata callData = userOp.callData;\n bytes memory innerCall;\n bytes4 methodSig;\n assembly (\"memory-safe\") {\n let len := callData.length\n if gt(len, 3) {\n methodSig := calldataload(callData.offset)\n }\n }\n if (methodSig == IAccountExecute.executeUserOp.selector) {\n bytes memory executeUserOp = abi.encodeCall(IAccountExecute.executeUserOp, (userOp, opInfo.userOpHash));\n innerCall = abi.encodeCall(this.innerHandleOp, (executeUserOp, opInfo, context));\n } else\n {\n innerCall = abi.encodeCall(this.innerHandleOp, (callData, opInfo, context));\n }\n assembly (\"memory-safe\") {\n success := call(gas(), address(), 0, add(innerCall, 0x20), mload(innerCall), 0, 32)\n collected := mload(0)\n }\n _restoreFreePtr(saveFreePtr);\n }\n if (!success) {\n bytes32 innerRevertCode;\n assembly (\"memory-safe\") {\n let len := returndatasize()\n if eq(32, len) {\n returndatacopy(0, 0, 32)\n innerRevertCode := mload(0)\n }\n }\n if (innerRevertCode == INNER_OUT_OF_GAS) {\n // handleOps was called with gas limit too low. abort entire bundle.\n // can only be caused by bundler (leaving not enough gas for inner call)\n revert FailedOp(opIndex, \"AA95 out of gas\");\n } else if (innerRevertCode == INNER_REVERT_LOW_PREFUND) {\n // innerCall reverted on prefund too low. treat entire prefund as \"gas cost\"\n uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;\n uint256 actualGasCost = opInfo.prefund;\n _emitPrefundTooLow(opInfo);\n _emitUserOperationEvent(opInfo, false, actualGasCost, actualGas);\n collected = actualGasCost;\n } else {\n uint256 freePtr = _getFreePtr();\n emit PostOpRevertReason(\n opInfo.userOpHash,\n opInfo.mUserOp.sender,\n opInfo.mUserOp.nonce,\n Exec.getReturnData(REVERT_REASON_MAX_LEN)\n );\n _restoreFreePtr(freePtr);\n\n uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;\n collected = _postExecution(\n IPaymaster.PostOpMode.postOpReverted,\n opInfo,\n context,\n actualGas\n );\n }\n }\n }\n\n /**\n * Emit the UserOperationEvent for the given UserOperation.\n *\n * @param opInfo - The details of the current UserOperation.\n * @param success - Whether the execution of the UserOperation has succeeded or not.\n * @param actualGasCost - The actual cost of the consumed gas charged from the sender or the paymaster.\n * @param actualGas - The actual amount of gas used.\n */\n function _emitUserOperationEvent(UserOpInfo memory opInfo, bool success, uint256 actualGasCost, uint256 actualGas) internal virtual {\n emit UserOperationEvent(\n opInfo.userOpHash,\n opInfo.mUserOp.sender,\n opInfo.mUserOp.paymaster,\n opInfo.mUserOp.nonce,\n success,\n actualGasCost,\n actualGas\n );\n }\n\n /**\n * Emit the UserOperationPrefundTooLow event for the given UserOperation.\n *\n * @param opInfo - The details of the current UserOperation.\n */\n function _emitPrefundTooLow(UserOpInfo memory opInfo) internal virtual {\n emit UserOperationPrefundTooLow(\n opInfo.userOpHash,\n opInfo.mUserOp.sender,\n opInfo.mUserOp.nonce\n );\n }\n\n /**\n * Iterate over calldata PackedUserOperation array and perform account and paymaster validation.\n * @notice UserOpInfo is a global array of all UserOps while PackedUserOperation is grouped per aggregator.\n *\n * @param ops - an array of UserOps to be validated\n * @param opInfos - an array of UserOp metadata being read and filled in during this function's execution\n * @param expectedAggregator - an address of the aggregator specified for a given UserOp if any, or address(0)\n * @param opIndexOffset - an offset for the index between 'ops' and 'opInfos' arrays, see the notice.\n * @return opsLen - processed UserOps (length of \"ops\" array)\n */\n function _iterateValidationPhase(\n PackedUserOperation[] calldata ops,\n UserOpInfo[] memory opInfos,\n address expectedAggregator,\n uint256 opIndexOffset\n ) internal returns (uint256 opsLen){\n unchecked {\n opsLen = ops.length;\n for (uint256 i = 0; i < opsLen; i++) {\n UserOpInfo memory opInfo = opInfos[opIndexOffset + i];\n (\n uint256 validationData,\n uint256 pmValidationData\n ) = _validatePrepayment(opIndexOffset + i, ops[i], opInfo);\n _validateAccountAndPaymasterValidationData(\n opIndexOffset + i,\n validationData,\n pmValidationData,\n expectedAggregator\n );\n }\n }\n }\n\n /**\n * A memory copy of UserOp static fields only.\n * Excluding: callData, initCode and signature. Replacing paymasterAndData with paymaster.\n */\n struct MemoryUserOp {\n address sender;\n uint256 nonce;\n uint256 verificationGasLimit;\n uint256 callGasLimit;\n uint256 paymasterVerificationGasLimit;\n uint256 paymasterPostOpGasLimit;\n uint256 preVerificationGas;\n address paymaster;\n uint256 maxFeePerGas;\n uint256 maxPriorityFeePerGas;\n }\n\n struct UserOpInfo {\n MemoryUserOp mUserOp;\n bytes32 userOpHash;\n uint256 prefund;\n uint256 contextOffset;\n uint256 preOpGas;\n }\n\n /**\n * Inner function to handle a UserOperation.\n * Must be declared \"external\" to open a call context, but it can only be called by handleOps.\n * @param callData - The callData to execute.\n * @param opInfo - The UserOpInfo struct.\n * @param context - The context bytes.\n * @return actualGasCost - the actual cost in eth this UserOperation paid for gas\n */\n function innerHandleOp(\n bytes memory callData,\n UserOpInfo memory opInfo,\n bytes calldata context\n ) external returns (uint256 actualGasCost) {\n uint256 preGas = gasleft();\n require(msg.sender == address(this), \"AA92 internal call only\");\n MemoryUserOp memory mUserOp = opInfo.mUserOp;\n\n uint256 callGasLimit = mUserOp.callGasLimit;\n unchecked {\n // handleOps was called with gas limit too low. abort entire bundle.\n if (\n gasleft() * 63 / 64 <\n callGasLimit +\n mUserOp.paymasterPostOpGasLimit +\n INNER_GAS_OVERHEAD\n ) {\n assembly (\"memory-safe\") {\n mstore(0, INNER_OUT_OF_GAS)\n revert(0, 32)\n }\n }\n }\n\n IPaymaster.PostOpMode mode = IPaymaster.PostOpMode.opSucceeded;\n if (callData.length > 0) {\n bool success = Exec.call(mUserOp.sender, 0, callData, callGasLimit);\n if (!success) {\n uint256 freePtr = _getFreePtr();\n bytes memory result = Exec.getReturnData(REVERT_REASON_MAX_LEN);\n if (result.length > 0) {\n emit UserOperationRevertReason(\n opInfo.userOpHash,\n mUserOp.sender,\n mUserOp.nonce,\n result\n );\n }\n _restoreFreePtr(freePtr);\n mode = IPaymaster.PostOpMode.opReverted;\n }\n }\n\n unchecked {\n uint256 actualGas = preGas - gasleft() + opInfo.preOpGas;\n return _postExecution(mode, opInfo, context, actualGas);\n }\n }\n\n /**\n * Copy general fields from userOp into the memory opInfo structure.\n * @param userOp - The user operation.\n * @param mUserOp - The memory user operation.\n */\n function _copyUserOpToMemory(\n PackedUserOperation calldata userOp,\n MemoryUserOp memory mUserOp\n ) internal virtual pure {\n mUserOp.sender = userOp.sender;\n mUserOp.nonce = userOp.nonce;\n (mUserOp.verificationGasLimit, mUserOp.callGasLimit) = UserOperationLib.unpackUints(userOp.accountGasLimits);\n mUserOp.preVerificationGas = userOp.preVerificationGas;\n (mUserOp.maxPriorityFeePerGas, mUserOp.maxFeePerGas) = UserOperationLib.unpackUints(userOp.gasFees);\n bytes calldata paymasterAndData = userOp.paymasterAndData;\n if (paymasterAndData.length > 0) {\n require(\n paymasterAndData.length >= UserOperationLib.PAYMASTER_DATA_OFFSET,\n \"AA93 invalid paymasterAndData\"\n );\n address paymaster;\n (paymaster, mUserOp.paymasterVerificationGasLimit, mUserOp.paymasterPostOpGasLimit) = UserOperationLib.unpackPaymasterStaticFields(paymasterAndData);\n require(paymaster != address(0), \"AA98 invalid paymaster\");\n mUserOp.paymaster = paymaster;\n }\n }\n\n /**\n * Get the required prefunded gas fee amount for an operation.\n *\n * @param mUserOp - The user operation in memory.\n * @return requiredPrefund - the required amount.\n */\n function _getRequiredPrefund(\n MemoryUserOp memory mUserOp\n ) internal virtual pure returns (uint256 requiredPrefund) {\n unchecked {\n uint256 requiredGas = mUserOp.verificationGasLimit +\n mUserOp.callGasLimit +\n mUserOp.paymasterVerificationGasLimit +\n mUserOp.paymasterPostOpGasLimit +\n mUserOp.preVerificationGas;\n\n requiredPrefund = requiredGas * mUserOp.maxFeePerGas;\n }\n }\n\n /**\n * Create sender smart contract account if init code is provided.\n * @param opIndex - The operation index.\n * @param opInfo - The operation info.\n * @param initCode - The init code for the smart contract account.\n */\n function _createSenderIfNeeded(\n uint256 opIndex,\n UserOpInfo memory opInfo,\n bytes calldata initCode\n ) internal virtual {\n if (initCode.length != 0) {\n address sender = opInfo.mUserOp.sender;\n if (Eip7702Support._isEip7702InitCode(initCode)) {\n if (initCode.length > 20) {\n // Already validated it is an EIP-7702 delegate (and hence, already has code) - see getUserOpHash()\n // Note: Can be called multiple times as long as an appropriate initCode is supplied\n senderCreator().initEip7702Sender{\n gas: opInfo.mUserOp.verificationGasLimit\n }(sender, initCode[20 :]);\n }\n return;\n }\n if (sender.code.length != 0)\n revert FailedOp(opIndex, \"AA10 sender already constructed\");\n if (initCode.length < 20) {\n revert FailedOp(opIndex, \"AA99 initCode too small\");\n }\n address sender1 = senderCreator().createSender{\n gas: opInfo.mUserOp.verificationGasLimit\n }(initCode);\n if (sender1 == address(0))\n revert FailedOp(opIndex, \"AA13 initCode failed or OOG\");\n if (sender1 != sender)\n revert FailedOp(opIndex, \"AA14 initCode must return sender\");\n if (sender1.code.length == 0)\n revert FailedOp(opIndex, \"AA15 initCode must create sender\");\n address factory = address(bytes20(initCode[0 : 20]));\n emit AccountDeployed(\n opInfo.userOpHash,\n sender,\n factory,\n opInfo.mUserOp.paymaster\n );\n }\n }\n\n /**\n * Call account.validateUserOp.\n * Revert (with FailedOp) in case validateUserOp reverts, or account didn't send required prefund.\n * Decrement account's deposit if needed.\n * @param opIndex - The operation index.\n * @param op - The user operation.\n * @param opInfo - The operation info.\n * @param requiredPrefund - The required prefund amount.\n * @return validationData - The account's validationData.\n */\n function _validateAccountPrepayment(\n uint256 opIndex,\n PackedUserOperation calldata op,\n UserOpInfo memory opInfo,\n uint256 requiredPrefund\n )\n internal virtual\n returns (\n uint256 validationData\n )\n {\n unchecked {\n MemoryUserOp memory mUserOp = opInfo.mUserOp;\n address sender = mUserOp.sender;\n _createSenderIfNeeded(opIndex, opInfo, op.initCode);\n address paymaster = mUserOp.paymaster;\n uint256 missingAccountFunds = 0;\n if (paymaster == address(0)) {\n uint256 bal = balanceOf(sender);\n missingAccountFunds = bal > requiredPrefund\n ? 0\n : requiredPrefund - bal;\n }\n validationData = _callValidateUserOp(opIndex, op, opInfo, missingAccountFunds);\n if (paymaster == address(0)) {\n if (!_tryDecrementDeposit(sender, requiredPrefund)) {\n revert FailedOp(opIndex, \"AA21 didn't pay prefund\");\n }\n }\n }\n }\n\n /**\n * Make a call to the sender.validateUserOp() function.\n * Handle wrong output size by reverting with a FailedOp error.\n *\n * @param opIndex - index of the UserOperation in the bundle.\n * @param op - the packed UserOperation object.\n * @param opInfo - the in-memory UserOperation information.\n * @param missingAccountFunds - the amount of deposit the account has to make to cover the UserOperation gas.\n */\n function _callValidateUserOp(\n uint256 opIndex,\n PackedUserOperation calldata op,\n UserOpInfo memory opInfo,\n uint256 missingAccountFunds\n )\n internal virtual returns (uint256 validationData) {\n uint256 gasLimit = opInfo.mUserOp.verificationGasLimit;\n address sender = opInfo.mUserOp.sender;\n bool success;\n {\n uint256 saveFreePtr = _getFreePtr();\n bytes memory callData = abi.encodeCall(IAccount.validateUserOp, (op, opInfo.userOpHash, missingAccountFunds));\n assembly (\"memory-safe\"){\n success := call(gasLimit, sender, 0, add(callData, 0x20), mload(callData), 0, 32)\n validationData := mload(0)\n // any return data size other than 32 is considered failure\n if iszero(eq(returndatasize(), 32)) {\n success := 0\n }\n }\n _restoreFreePtr(saveFreePtr);\n }\n if (!success) {\n if (sender.code.length == 0) {\n revert FailedOp(opIndex, \"AA20 account not deployed\");\n } else {\n revert FailedOpWithRevert(opIndex, \"AA23 reverted\", Exec.getReturnData(REVERT_REASON_MAX_LEN));\n }\n }\n }\n\n /**\n * In case the request has a paymaster:\n * - Validate paymaster has enough deposit.\n * - Call paymaster.validatePaymasterUserOp.\n * - Revert with proper FailedOp in case paymaster reverts.\n * - Decrement paymaster's deposit.\n * @param opIndex - The operation index.\n * @param op - The user operation.\n * @param opInfo - The operation info.\n * @return context - The Paymaster-provided value to be passed to the 'postOp' function later\n * @return validationData - The Paymaster's validationData.\n */\n function _validatePaymasterPrepayment(\n uint256 opIndex,\n PackedUserOperation calldata op,\n UserOpInfo memory opInfo\n ) internal virtual returns (bytes memory context, uint256 validationData) {\n unchecked {\n uint256 preGas = gasleft();\n MemoryUserOp memory mUserOp = opInfo.mUserOp;\n address paymaster = mUserOp.paymaster;\n uint256 requiredPreFund = opInfo.prefund;\n if (!_tryDecrementDeposit(paymaster, requiredPreFund)) {\n revert FailedOp(opIndex, \"AA31 paymaster deposit too low\");\n }\n uint256 pmVerificationGasLimit = mUserOp.paymasterVerificationGasLimit;\n (context, validationData) = _callValidatePaymasterUserOp(opIndex, op, opInfo);\n if (preGas - gasleft() > pmVerificationGasLimit) {\n revert FailedOp(opIndex, \"AA36 over paymasterVerificationGasLimit\");\n }\n }\n }\n\n function _callValidatePaymasterUserOp(\n uint256 opIndex,\n PackedUserOperation calldata op,\n UserOpInfo memory opInfo\n ) internal returns (bytes memory context, uint256 validationData) {\n uint256 freePtr = _getFreePtr();\n bytes memory validatePaymasterCall = abi.encodeCall(\n IPaymaster.validatePaymasterUserOp,\n (op, opInfo.userOpHash, opInfo.prefund)\n );\n address paymaster = opInfo.mUserOp.paymaster;\n uint256 paymasterVerificationGasLimit = opInfo.mUserOp.paymasterVerificationGasLimit;\n bool success;\n uint256 contextLength;\n uint256 contextOffset;\n uint256 maxContextLength;\n uint256 len;\n assembly (\"memory-safe\") {\n success := call(paymasterVerificationGasLimit, paymaster, 0, add(validatePaymasterCall, 0x20), mload(validatePaymasterCall), 0, 0)\n len := returndatasize()\n // return data from validatePaymasterUserOp is (bytes context, validationData)\n // encoded as:\n // 32 bytes offset of context (always 64)\n // 32 bytes of validationData\n // 32 bytes of context length\n // context data (rounded up, to 32 bytes boundary)\n // so entire buffer size is (at least) 96+content.length.\n //\n // we use freePtr, fetched before calling encodeCall, as return data pointer.\n // this way we reuse that memory without unnecessary memory expansion\n returndatacopy(freePtr, 0, len)\n validationData := mload(add(freePtr, 32))\n contextOffset := mload(freePtr)\n maxContextLength := sub(len, 96)\n context := add(freePtr, 64)\n contextLength := mload(context)\n }\n\n unchecked {\n if (!success || contextOffset != 64 || contextLength + 31 < maxContextLength) {\n revert FailedOpWithRevert(opIndex, \"AA33 reverted\", Exec.getReturnData(REVERT_REASON_MAX_LEN));\n }\n }\n finalizeAllocation(freePtr, len);\n }\n\n /**\n * Revert if either account validationData or paymaster validationData is expired.\n * @param opIndex - The operation index.\n * @param validationData - The account validationData.\n * @param paymasterValidationData - The paymaster validationData.\n * @param expectedAggregator - The expected aggregator.\n */\n function _validateAccountAndPaymasterValidationData(\n uint256 opIndex,\n uint256 validationData,\n uint256 paymasterValidationData,\n address expectedAggregator\n ) internal virtual view {\n (address aggregator, bool outOfTimeRange) = _getValidationData(\n validationData\n );\n if (expectedAggregator != aggregator) {\n revert FailedOp(opIndex, \"AA24 signature error\");\n }\n if (outOfTimeRange) {\n revert FailedOp(opIndex, \"AA22 expired or not due\");\n }\n // pmAggregator is not a real signature aggregator: we don't have logic to handle it as address.\n // Non-zero address means that the paymaster fails due to some signature check (which is ok only during estimation).\n address pmAggregator;\n (pmAggregator, outOfTimeRange) = _getValidationData(\n paymasterValidationData\n );\n if (pmAggregator != address(0)) {\n revert FailedOp(opIndex, \"AA34 signature error\");\n }\n if (outOfTimeRange) {\n revert FailedOp(opIndex, \"AA32 paymaster expired or not due\");\n }\n }\n\n /**\n * Parse validationData into its components.\n * @param validationData - The packed validation data (sigFailed, validAfter, validUntil).\n * @return aggregator the aggregator of the validationData\n * @return outOfTimeRange true if current time is outside the time range of this validationData.\n */\n function _getValidationData(\n uint256 validationData\n ) internal virtual view returns (address aggregator, bool outOfTimeRange) {\n if (validationData == 0) {\n return (address(0), false);\n }\n ValidationData memory data = _parseValidationData(validationData);\n // solhint-disable-next-line not-rely-on-time\n outOfTimeRange = block.timestamp > data.validUntil || block.timestamp <= data.validAfter;\n aggregator = data.aggregator;\n }\n\n /**\n * Validate account and paymaster (if defined) and\n * also make sure total validation doesn't exceed verificationGasLimit.\n * This method is called off-chain (simulateValidation()) and on-chain (from handleOps)\n * @param opIndex - The index of this userOp into the \"opInfos\" array.\n * @param userOp - The packed calldata UserOperation structure to validate.\n * @param outOpInfo - The empty unpacked in-memory UserOperation structure that will be filled in here.\n *\n * @return validationData - The account's validationData.\n * @return paymasterValidationData - The paymaster's validationData.\n */\n function _validatePrepayment(\n uint256 opIndex,\n PackedUserOperation calldata userOp,\n UserOpInfo memory outOpInfo\n )\n internal virtual\n returns (uint256 validationData, uint256 paymasterValidationData)\n {\n uint256 preGas = gasleft();\n MemoryUserOp memory mUserOp = outOpInfo.mUserOp;\n _copyUserOpToMemory(userOp, mUserOp);\n\n // getUserOpHash uses temporary allocations, no required after it returns\n uint256 freePtr = _getFreePtr();\n outOpInfo.userOpHash = getUserOpHash(userOp);\n _restoreFreePtr(freePtr);\n\n // Validate all numeric values in userOp are well below 128 bit, so they can safely be added\n // and multiplied without causing overflow.\n uint256 verificationGasLimit = mUserOp.verificationGasLimit;\n uint256 maxGasValues = mUserOp.preVerificationGas |\n verificationGasLimit |\n mUserOp.callGasLimit |\n mUserOp.paymasterVerificationGasLimit |\n mUserOp.paymasterPostOpGasLimit |\n mUserOp.maxFeePerGas |\n mUserOp.maxPriorityFeePerGas;\n require(maxGasValues <= type(uint120).max, FailedOp(opIndex, \"AA94 gas values overflow\"));\n\n uint256 requiredPreFund = _getRequiredPrefund(mUserOp);\n outOpInfo.prefund = requiredPreFund;\n validationData = _validateAccountPrepayment(\n opIndex,\n userOp,\n outOpInfo,\n requiredPreFund\n );\n\n require(\n _validateAndUpdateNonce(mUserOp.sender, mUserOp.nonce),\n FailedOp(opIndex, \"AA25 invalid account nonce\")\n );\n\n unchecked {\n if (preGas - gasleft() > verificationGasLimit) {\n revert FailedOp(opIndex, \"AA26 over verificationGasLimit\");\n }\n }\n\n bytes memory context;\n if (mUserOp.paymaster != address(0)) {\n (context, paymasterValidationData) = _validatePaymasterPrepayment(\n opIndex,\n userOp,\n outOpInfo\n );\n }\n unchecked {\n outOpInfo.contextOffset = _getOffsetOfMemoryBytes(context);\n outOpInfo.preOpGas = preGas - gasleft() + userOp.preVerificationGas;\n }\n }\n\n /**\n * Process post-operation, called just after the callData is executed.\n * If a paymaster is defined and its validation returned a non-empty context, its postOp is called.\n * The excess amount is refunded to the account (or paymaster - if it was used in the request).\n * @param mode - Whether is called from innerHandleOp, or outside (postOpReverted).\n * @param opInfo - UserOp fields and info collected during validation.\n * @param context - The context returned in validatePaymasterUserOp.\n * @param actualGas - The gas used so far by this user operation.\n *\n * @return actualGasCost - the actual cost in eth this UserOperation paid for gas\n */\n function _postExecution(\n IPaymaster.PostOpMode mode,\n UserOpInfo memory opInfo,\n bytes memory context,\n uint256 actualGas\n ) internal virtual returns (uint256 actualGasCost) {\n uint256 preGas = gasleft();\n unchecked {\n address refundAddress;\n MemoryUserOp memory mUserOp = opInfo.mUserOp;\n uint256 gasPrice = _getUserOpGasPrice(mUserOp);\n\n address paymaster = mUserOp.paymaster;\n // Calculating a penalty for unused execution gas\n {\n uint256 executionGasUsed = actualGas - opInfo.preOpGas;\n // this check is required for the gas used within EntryPoint and not covered by explicit gas limits\n actualGas += _getUnusedGasPenalty(executionGasUsed, mUserOp.callGasLimit);\n }\n uint256 postOpUnusedGasPenalty;\n if (paymaster == address(0)) {\n refundAddress = mUserOp.sender;\n } else {\n refundAddress = paymaster;\n if (context.length > 0) {\n actualGasCost = actualGas * gasPrice;\n uint256 postOpPreGas = gasleft();\n if (mode != IPaymaster.PostOpMode.postOpReverted) {\n try IPaymaster(paymaster).postOp{\n gas: mUserOp.paymasterPostOpGasLimit\n }(mode, context, actualGasCost, gasPrice)\n // solhint-disable-next-line no-empty-blocks\n {} catch {\n bytes memory reason = Exec.getReturnData(REVERT_REASON_MAX_LEN);\n revert PostOpReverted(reason);\n }\n }\n // Calculating a penalty for unused postOp gas\n // note that if postOp is reverted, the maximum penalty (10% of postOpGasLimit) is charged.\n uint256 postOpGasUsed = postOpPreGas - gasleft();\n postOpUnusedGasPenalty = _getUnusedGasPenalty(postOpGasUsed, mUserOp.paymasterPostOpGasLimit);\n }\n }\n actualGas += preGas - gasleft() + postOpUnusedGasPenalty;\n actualGasCost = actualGas * gasPrice;\n uint256 prefund = opInfo.prefund;\n if (prefund < actualGasCost) {\n if (mode == IPaymaster.PostOpMode.postOpReverted) {\n actualGasCost = prefund;\n _emitPrefundTooLow(opInfo);\n _emitUserOperationEvent(opInfo, false, actualGasCost, actualGas);\n } else {\n assembly (\"memory-safe\") {\n mstore(0, INNER_REVERT_LOW_PREFUND)\n revert(0, 32)\n }\n }\n } else {\n uint256 refund = prefund - actualGasCost;\n _incrementDeposit(refundAddress, refund);\n bool success = mode == IPaymaster.PostOpMode.opSucceeded;\n _emitUserOperationEvent(opInfo, success, actualGasCost, actualGas);\n }\n } // unchecked\n }\n\n /**\n * The gas price this UserOp agrees to pay.\n * Relayer/block builder might submit the TX with higher priorityFee, but the user should not be affected.\n * @param mUserOp - The userOp to get the gas price from.\n */\n function _getUserOpGasPrice(\n MemoryUserOp memory mUserOp\n ) internal view returns (uint256) {\n unchecked {\n uint256 maxFeePerGas = mUserOp.maxFeePerGas;\n uint256 maxPriorityFeePerGas = mUserOp.maxPriorityFeePerGas;\n return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);\n }\n }\n\n /**\n * The offset of the given bytes in memory.\n * @param data - The bytes to get the offset of.\n */\n function _getOffsetOfMemoryBytes(\n bytes memory data\n ) internal pure returns (uint256 offset) {\n assembly (\"memory-safe\") {\n offset := data\n }\n }\n\n /**\n * The bytes in memory at the given offset.\n * @param offset - The offset to get the bytes from.\n */\n function _getMemoryBytesFromOffset(\n uint256 offset\n ) internal pure returns (bytes memory data) {\n assembly (\"memory-safe\") {\n data := offset\n }\n }\n\n /**\n * save free memory pointer.\n * save \"free memory\" pointer, so that it can be restored later using restoreFreePtr.\n * This reduce unneeded memory expansion, and reduce memory expansion cost.\n * NOTE: all dynamic allocations between saveFreePtr and restoreFreePtr MUST NOT be used after restoreFreePtr is called.\n */\n function _getFreePtr() internal pure returns (uint256 ptr) {\n assembly (\"memory-safe\") {\n ptr := mload(0x40)\n }\n }\n\n /**\n * restore free memory pointer.\n * any allocated memory since saveFreePtr is cleared, and MUST NOT be accessed later.\n */\n function _restoreFreePtr(uint256 ptr) internal pure {\n assembly (\"memory-safe\") {\n mstore(0x40, ptr)\n }\n }\n\n function _getUnusedGasPenalty(uint256 gasUsed, uint256 gasLimit) internal pure returns (uint256) {\n unchecked {\n if (gasLimit <= gasUsed + PENALTY_GAS_THRESHOLD) {\n return 0;\n }\n uint256 unusedGas = gasLimit - gasUsed;\n uint256 unusedGasPenalty = (unusedGas * UNUSED_GAS_PENALTY_PERCENT) / 100;\n return unusedGasPenalty;\n }\n }\n}\n" + }, "@account-abstraction/contracts/core/Helpers.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n/* solhint-disable no-inline-assembly */\n\n\n /*\n * For simulation purposes, validateUserOp (and validatePaymasterUserOp)\n * must return this value in case of signature failure, instead of revert.\n */\nuint256 constant SIG_VALIDATION_FAILED = 1;\n\n\n/*\n * For simulation purposes, validateUserOp (and validatePaymasterUserOp)\n * return this value on success.\n */\nuint256 constant SIG_VALIDATION_SUCCESS = 0;\n\n\n/**\n * Returned data from validateUserOp.\n * validateUserOp returns a uint256, which is created by `_packedValidationData` and\n * parsed by `_parseValidationData`.\n * @param aggregator - address(0) - The account validated the signature by itself.\n * address(1) - The account failed to validate the signature.\n * otherwise - This is an address of a signature aggregator that must\n * be used to validate the signature.\n * @param validAfter - This UserOp is valid only after this timestamp.\n * @param validUntil - Last timestamp this operation is valid at, or 0 for \"indefinitely\".\n */\nstruct ValidationData {\n address aggregator;\n uint48 validAfter;\n uint48 validUntil;\n}\n\n/**\n * Extract aggregator/sigFailed, validAfter, validUntil.\n * Also convert zero validUntil to type(uint48).max.\n * @param validationData - The packed validation data.\n * @return data - The unpacked in-memory validation data.\n */\nfunction _parseValidationData(\n uint256 validationData\n) pure returns (ValidationData memory data) {\n address aggregator = address(uint160(validationData));\n uint48 validUntil = uint48(validationData >> 160);\n if (validUntil == 0) {\n validUntil = type(uint48).max;\n }\n uint48 validAfter = uint48(validationData >> (48 + 160));\n return ValidationData(aggregator, validAfter, validUntil);\n}\n\n/**\n * Helper to pack the return value for validateUserOp.\n * @param data - The ValidationData to pack.\n * @return the packed validation data.\n */\nfunction _packValidationData(\n ValidationData memory data\n) pure returns (uint256) {\n return\n uint160(data.aggregator) |\n (uint256(data.validUntil) << 160) |\n (uint256(data.validAfter) << (160 + 48));\n}\n\n/**\n * Helper to pack the return value for validateUserOp, when not using an aggregator.\n * @param sigFailed - True for signature failure, false for success.\n * @param validUntil - Last timestamp this operation is valid at, or 0 for \"indefinitely\".\n * @param validAfter - First timestamp this UserOperation is valid.\n * @return the packed validation data.\n */\nfunction _packValidationData(\n bool sigFailed,\n uint48 validUntil,\n uint48 validAfter\n) pure returns (uint256) {\n return\n (sigFailed ? SIG_VALIDATION_FAILED : SIG_VALIDATION_SUCCESS) |\n (uint256(validUntil) << 160) |\n (uint256(validAfter) << (160 + 48));\n}\n\n/**\n * keccak function over calldata.\n * @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it.\n *\n * @param data - the calldata bytes array to perform keccak on.\n * @return ret - the keccak hash of the 'data' array.\n */\n function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) {\n assembly (\"memory-safe\") {\n let mem := mload(0x40)\n let len := data.length\n calldatacopy(mem, data.offset, len)\n ret := keccak256(mem, len)\n }\n }\n\n\n/**\n * The minimum of two numbers.\n * @param a - First number.\n * @param b - Second number.\n * @return - the minimum value.\n */\n function min(uint256 a, uint256 b) pure returns (uint256) {\n return a < b ? a : b;\n }\n\n/**\n * standard solidity memory allocation finalization.\n * copied from solidity generated code\n * @param memPointer - The current memory pointer\n * @param allocationSize - Bytes allocated from memPointer.\n */\n function finalizeAllocation(uint256 memPointer, uint256 allocationSize) pure {\n\n assembly (\"memory-safe\"){\n finalize_allocation(memPointer, allocationSize)\n\n function finalize_allocation(memPtr, size) {\n let newFreePtr := add(memPtr, round_up_to_mul_of_32(size))\n mstore(64, newFreePtr)\n }\n\n function round_up_to_mul_of_32(value) -> result {\n result := and(add(value, 31), not(31))\n }\n }\n }\n" }, + "@account-abstraction/contracts/core/NonceManager.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.28;\n\nimport \"../interfaces/INonceManager.sol\";\n\n/**\n * nonce management functionality\n */\nabstract contract NonceManager is INonceManager {\n\n /**\n * The next valid sequence number for a given nonce key.\n */\n mapping(address => mapping(uint192 => uint256)) public nonceSequenceNumber;\n\n /// @inheritdoc INonceManager\n function getNonce(address sender, uint192 key)\n public view override returns (uint256 nonce) {\n return nonceSequenceNumber[sender][key] | (uint256(key) << 64);\n }\n\n /// @inheritdoc INonceManager\n function incrementNonce(uint192 key) external override {\n nonceSequenceNumber[msg.sender][key]++;\n }\n\n /**\n * validate nonce uniqueness for this account.\n * called just after validateUserOp()\n * @return true if the nonce was incremented successfully.\n * false if the current nonce doesn't match the given one.\n */\n function _validateAndUpdateNonce(address sender, uint256 nonce) internal returns (bool) {\n\n uint192 key = uint192(nonce >> 64);\n uint64 seq = uint64(nonce);\n return nonceSequenceNumber[sender][key]++ == seq;\n }\n\n}\n" + }, + "@account-abstraction/contracts/core/SenderCreator.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.28;\n/* solhint-disable avoid-low-level-calls */\n/* solhint-disable no-inline-assembly */\n\nimport \"../interfaces/ISenderCreator.sol\";\nimport \"../interfaces/IEntryPoint.sol\";\nimport \"../utils/Exec.sol\";\n\n/**\n * Helper contract for EntryPoint, to call userOp.initCode from a \"neutral\" address,\n * which is explicitly not the entryPoint itself.\n */\ncontract SenderCreator is ISenderCreator {\n address public immutable entryPoint;\n\n constructor(){\n entryPoint = msg.sender;\n }\n\n uint256 private constant REVERT_REASON_MAX_LEN = 2048;\n\n /**\n * Call the \"initCode\" factory to create and return the sender account address.\n * @param initCode - The initCode value from a UserOp. contains 20 bytes of factory address,\n * followed by calldata.\n * @return sender - The returned address of the created account, or zero address on failure.\n */\n function createSender(\n bytes calldata initCode\n ) external returns (address sender) {\n require(msg.sender == entryPoint, \"AA97 should call from EntryPoint\");\n address factory = address(bytes20(initCode[0 : 20]));\n\n bytes memory initCallData = initCode[20 :];\n bool success;\n assembly (\"memory-safe\") {\n success := call(\n gas(),\n factory,\n 0,\n add(initCallData, 0x20),\n mload(initCallData),\n 0,\n 32\n )\n if success {\n sender := mload(0)\n }\n }\n }\n\n /// @inheritdoc ISenderCreator\n function initEip7702Sender(\n address sender,\n bytes memory initCallData\n ) external {\n require(msg.sender == entryPoint, \"AA97 should call from EntryPoint\");\n bool success;\n assembly (\"memory-safe\") {\n success := call(\n gas(),\n sender,\n 0,\n add(initCallData, 0x20),\n mload(initCallData),\n 0,\n 0\n )\n }\n if (!success) {\n bytes memory result = Exec.getReturnData(REVERT_REASON_MAX_LEN);\n revert IEntryPoint.FailedOpWithRevert(0, \"AA13 EIP7702 sender init failed\", result);\n }\n }\n}\n" + }, + "@account-abstraction/contracts/core/StakeManager.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.28;\n\nimport \"../interfaces/IStakeManager.sol\";\n\n/* solhint-disable avoid-low-level-calls */\n/* solhint-disable not-rely-on-time */\n\n/**\n * Manage deposits and stakes.\n * Deposit is just a balance used to pay for UserOperations (either by a paymaster or an account).\n * Stake is value locked for at least \"unstakeDelay\" by a paymaster.\n */\nabstract contract StakeManager is IStakeManager {\n /// maps paymaster to their deposits and stakes\n mapping(address => DepositInfo) private deposits;\n\n /// @inheritdoc IStakeManager\n function getDepositInfo(\n address account\n ) external view returns (DepositInfo memory info) {\n return deposits[account];\n }\n\n /**\n * Internal method to return just the stake info.\n * @param addr - The account to query.\n */\n function _getStakeInfo(\n address addr\n ) internal view returns (StakeInfo memory info) {\n DepositInfo storage depositInfo = deposits[addr];\n info.stake = depositInfo.stake;\n info.unstakeDelaySec = depositInfo.unstakeDelaySec;\n }\n\n /// @inheritdoc IStakeManager\n function balanceOf(address account) public view returns (uint256) {\n return deposits[account].deposit;\n }\n\n receive() external payable {\n depositTo(msg.sender);\n }\n\n\n /**\n * Increments an account's deposit.\n * @param account - The account to increment.\n * @param amount - The amount to increment by.\n * @return the updated deposit of this account\n */\n function _incrementDeposit(address account, uint256 amount) internal returns (uint256) {\n unchecked {\n DepositInfo storage info = deposits[account];\n uint256 newAmount = info.deposit + amount;\n info.deposit = newAmount;\n return newAmount;\n }\n }\n\n /**\n * Try to decrement the account's deposit.\n * @param account - The account to decrement.\n * @param amount - The amount to decrement by.\n * @return true if the decrement succeeded (that is, previous balance was at least that amount)\n */\n function _tryDecrementDeposit(address account, uint256 amount) internal returns(bool) {\n unchecked {\n DepositInfo storage info = deposits[account];\n uint256 currentDeposit = info.deposit;\n if (currentDeposit < amount) {\n return false;\n }\n info.deposit = currentDeposit - amount;\n return true;\n }\n }\n\n /// @inheritdoc IStakeManager\n function depositTo(address account) public virtual payable {\n uint256 newDeposit = _incrementDeposit(account, msg.value);\n emit Deposited(account, newDeposit);\n }\n\n /// @inheritdoc IStakeManager\n function addStake(uint32 unstakeDelaySec) external payable {\n DepositInfo storage info = deposits[msg.sender];\n require(unstakeDelaySec > 0, \"must specify unstake delay\");\n require(\n unstakeDelaySec >= info.unstakeDelaySec,\n \"cannot decrease unstake time\"\n );\n uint256 stake = info.stake + msg.value;\n require(stake > 0, \"no stake specified\");\n require(stake <= type(uint112).max, \"stake overflow\");\n deposits[msg.sender] = DepositInfo(\n info.deposit,\n true,\n uint112(stake),\n unstakeDelaySec,\n 0\n );\n emit StakeLocked(msg.sender, stake, unstakeDelaySec);\n }\n\n /// @inheritdoc IStakeManager\n function unlockStake() external {\n DepositInfo storage info = deposits[msg.sender];\n require(info.unstakeDelaySec != 0, \"not staked\");\n require(info.staked, \"already unstaking\");\n uint48 withdrawTime = uint48(block.timestamp) + info.unstakeDelaySec;\n info.withdrawTime = withdrawTime;\n info.staked = false;\n emit StakeUnlocked(msg.sender, withdrawTime);\n }\n\n /// @inheritdoc IStakeManager\n function withdrawStake(address payable withdrawAddress) external {\n DepositInfo storage info = deposits[msg.sender];\n uint256 stake = info.stake;\n require(stake > 0, \"No stake to withdraw\");\n require(info.withdrawTime > 0, \"must call unlockStake() first\");\n require(\n info.withdrawTime <= block.timestamp,\n \"Stake withdrawal is not due\"\n );\n info.unstakeDelaySec = 0;\n info.withdrawTime = 0;\n info.stake = 0;\n emit StakeWithdrawn(msg.sender, withdrawAddress, stake);\n (bool success,) = withdrawAddress.call{value: stake}(\"\");\n require(success, \"failed to withdraw stake\");\n }\n\n /// @inheritdoc IStakeManager\n function withdrawTo(\n address payable withdrawAddress,\n uint256 withdrawAmount\n ) external {\n DepositInfo storage info = deposits[msg.sender];\n uint256 currentDeposit = info.deposit;\n require(withdrawAmount <= currentDeposit, \"Withdraw amount too large\");\n info.deposit = currentDeposit - withdrawAmount;\n emit Withdrawn(msg.sender, withdrawAddress, withdrawAmount);\n (bool success,) = withdrawAddress.call{value: withdrawAmount}(\"\");\n require(success, \"failed to withdraw\");\n }\n}\n" + }, "@account-abstraction/contracts/core/UserOperationLib.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n/* solhint-disable no-inline-assembly */\n\nimport \"../interfaces/PackedUserOperation.sol\";\nimport {calldataKeccak, min} from \"./Helpers.sol\";\n\n/**\n * Utility functions helpful when working with UserOperation structs.\n */\nlibrary UserOperationLib {\n\n uint256 public constant PAYMASTER_VALIDATION_GAS_OFFSET = 20;\n uint256 public constant PAYMASTER_POSTOP_GAS_OFFSET = 36;\n uint256 public constant PAYMASTER_DATA_OFFSET = 52;\n\n /**\n * Relayer/block builder might submit the TX with higher priorityFee,\n * but the user should not pay above what he signed for.\n * @param userOp - The user operation data.\n */\n function gasPrice(\n PackedUserOperation calldata userOp\n ) internal view returns (uint256) {\n unchecked {\n (uint256 maxPriorityFeePerGas, uint256 maxFeePerGas) = unpackUints(userOp.gasFees);\n return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);\n }\n }\n\n bytes32 internal constant PACKED_USEROP_TYPEHASH =\n keccak256(\n \"PackedUserOperation(address sender,uint256 nonce,bytes initCode,bytes callData,bytes32 accountGasLimits,uint256 preVerificationGas,bytes32 gasFees,bytes paymasterAndData)\"\n );\n\n /**\n * Pack the user operation data into bytes for hashing.\n * @param userOp - The user operation data.\n * @param overrideInitCodeHash - If set, encode this instead of the initCode field in the userOp.\n */\n function encode(\n PackedUserOperation calldata userOp,\n bytes32 overrideInitCodeHash\n ) internal pure returns (bytes memory ret) {\n address sender = userOp.sender;\n uint256 nonce = userOp.nonce;\n bytes32 hashInitCode = overrideInitCodeHash != 0 ? overrideInitCodeHash : calldataKeccak(userOp.initCode);\n bytes32 hashCallData = calldataKeccak(userOp.callData);\n bytes32 accountGasLimits = userOp.accountGasLimits;\n uint256 preVerificationGas = userOp.preVerificationGas;\n bytes32 gasFees = userOp.gasFees;\n bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData);\n\n return abi.encode(\n UserOperationLib.PACKED_USEROP_TYPEHASH,\n sender, nonce,\n hashInitCode, hashCallData,\n accountGasLimits, preVerificationGas, gasFees,\n hashPaymasterAndData\n );\n }\n\n function unpackUints(\n bytes32 packed\n ) internal pure returns (uint256 high128, uint256 low128) {\n return (unpackHigh128(packed), unpackLow128(packed));\n }\n\n // Unpack just the high 128-bits from a packed value\n function unpackHigh128(bytes32 packed) internal pure returns (uint256) {\n return uint256(packed) >> 128;\n }\n\n // Unpack just the low 128-bits from a packed value\n function unpackLow128(bytes32 packed) internal pure returns (uint256) {\n return uint128(uint256(packed));\n }\n\n function unpackMaxPriorityFeePerGas(PackedUserOperation calldata userOp)\n internal pure returns (uint256) {\n return unpackHigh128(userOp.gasFees);\n }\n\n function unpackMaxFeePerGas(PackedUserOperation calldata userOp)\n internal pure returns (uint256) {\n return unpackLow128(userOp.gasFees);\n }\n\n function unpackVerificationGasLimit(PackedUserOperation calldata userOp)\n internal pure returns (uint256) {\n return unpackHigh128(userOp.accountGasLimits);\n }\n\n function unpackCallGasLimit(PackedUserOperation calldata userOp)\n internal pure returns (uint256) {\n return unpackLow128(userOp.accountGasLimits);\n }\n\n function unpackPaymasterVerificationGasLimit(PackedUserOperation calldata userOp)\n internal pure returns (uint256) {\n return uint128(bytes16(userOp.paymasterAndData[PAYMASTER_VALIDATION_GAS_OFFSET : PAYMASTER_POSTOP_GAS_OFFSET]));\n }\n\n function unpackPostOpGasLimit(PackedUserOperation calldata userOp)\n internal pure returns (uint256) {\n return uint128(bytes16(userOp.paymasterAndData[PAYMASTER_POSTOP_GAS_OFFSET : PAYMASTER_DATA_OFFSET]));\n }\n\n function unpackPaymasterStaticFields(\n bytes calldata paymasterAndData\n ) internal pure returns (address paymaster, uint256 validationGasLimit, uint256 postOpGasLimit) {\n return (\n address(bytes20(paymasterAndData[: PAYMASTER_VALIDATION_GAS_OFFSET])),\n uint128(bytes16(paymasterAndData[PAYMASTER_VALIDATION_GAS_OFFSET : PAYMASTER_POSTOP_GAS_OFFSET])),\n uint128(bytes16(paymasterAndData[PAYMASTER_POSTOP_GAS_OFFSET : PAYMASTER_DATA_OFFSET]))\n );\n }\n\n /**\n * Hash the user operation data.\n * @param userOp - The user operation data.\n * @param overrideInitCodeHash - If set, the initCode hash will be replaced with this value just for UserOp hashing.\n */\n function hash(\n PackedUserOperation calldata userOp,\n bytes32 overrideInitCodeHash\n ) internal pure returns (bytes32) {\n return keccak256(encode(userOp, overrideInitCodeHash));\n }\n}\n" }, + "@account-abstraction/contracts/interfaces/IAccount.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport \"./PackedUserOperation.sol\";\n\ninterface IAccount {\n /**\n * Validate user's signature and nonce\n * the entryPoint will make the call to the recipient only if this validation call returns successfully.\n * signature failure should be reported by returning SIG_VALIDATION_FAILED (1).\n * This allows making a \"simulation call\" without a valid signature\n * Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to signal failure.\n *\n * @dev Must validate caller is the entryPoint.\n * Must validate the signature and nonce\n * @param userOp - The operation that is about to be executed.\n * @param userOpHash - Hash of the user's request data. can be used as the basis for signature.\n * @param missingAccountFunds - Missing funds on the account's deposit in the entrypoint.\n * This is the minimum amount to transfer to the sender(entryPoint) to be\n * able to make the call. The excess is left as a deposit in the entrypoint\n * for future calls. Can be withdrawn anytime using \"entryPoint.withdrawTo()\".\n * In case there is a paymaster in the request (or the current deposit is high\n * enough), this value will be zero.\n * @return validationData - Packaged ValidationData structure. use `_packValidationData` and\n * `_unpackValidationData` to encode and decode.\n * <20-byte> aggregatorOrSigFail - 0 for valid signature, 1 to mark signature failure,\n * otherwise, an address of an \"aggregator\" contract.\n * <6-byte> validUntil - Last timestamp this operation is valid at, or 0 for \"indefinitely\"\n * <6-byte> validAfter - First timestamp this operation is valid\n * If an account doesn't use time-range, it is enough to\n * return SIG_VALIDATION_FAILED value (1) for signature failure.\n * Note that the validation code cannot use block.timestamp (or block.number) directly.\n */\n function validateUserOp(\n PackedUserOperation calldata userOp,\n bytes32 userOpHash,\n uint256 missingAccountFunds\n ) external returns (uint256 validationData);\n}\n" + }, + "@account-abstraction/contracts/interfaces/IAccountExecute.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport \"./PackedUserOperation.sol\";\n\ninterface IAccountExecute {\n /**\n * Account may implement this execute method.\n * passing this methodSig at the beginning of callData will cause the entryPoint to pass the full UserOp (and hash)\n * to the account.\n * The account should skip the methodSig, and use the callData (and optionally, other UserOp fields)\n *\n * @param userOp - The operation that was just validated.\n * @param userOpHash - Hash of the user's request data.\n */\n function executeUserOp(\n PackedUserOperation calldata userOp,\n bytes32 userOpHash\n ) external;\n}\n" + }, "@account-abstraction/contracts/interfaces/IAggregator.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport \"./PackedUserOperation.sol\";\n\n/**\n * Aggregated Signatures validator.\n */\ninterface IAggregator {\n /**\n * Validate an aggregated signature.\n * Reverts if the aggregated signature does not match the given list of operations.\n * @param userOps - An array of UserOperations to validate the signature for.\n * @param signature - The aggregated signature.\n */\n function validateSignatures(\n PackedUserOperation[] calldata userOps,\n bytes calldata signature\n ) external;\n\n /**\n * Validate the signature of a single userOp.\n * This method should be called by bundler after EntryPointSimulation.simulateValidation() returns\n * the aggregator this account uses.\n * First it validates the signature over the userOp. Then it returns data to be used when creating the handleOps.\n * @param userOp - The userOperation received from the user.\n * @return sigForUserOp - The value to put into the signature field of the userOp when calling handleOps.\n * (usually empty, unless account and aggregator support some kind of \"multisig\".\n */\n function validateUserOpSignature(\n PackedUserOperation calldata userOp\n ) external view returns (bytes memory sigForUserOp);\n\n /**\n * Aggregate multiple signatures into a single value.\n * This method is called off-chain to calculate the signature to pass with handleOps()\n * bundler MAY use optimized custom code to perform this aggregation.\n * @param userOps - An array of UserOperations to collect the signatures from.\n * @return aggregatedSignature - The aggregated signature.\n */\n function aggregateSignatures(\n PackedUserOperation[] calldata userOps\n ) external view returns (bytes memory aggregatedSignature);\n}\n" }, @@ -31,35 +52,161 @@ "@account-abstraction/contracts/interfaces/PackedUserOperation.sol": { "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n/**\n * User Operation struct\n * @param sender - The sender account of this request.\n * @param nonce - Unique value the sender uses to verify it is not a replay.\n * @param initCode - If set, the account contract will be created by this constructor\n * @param callData - The method call to execute on this account.\n * @param accountGasLimits - Packed gas limits for validateUserOp and gas limit passed to the callData method call.\n * @param preVerificationGas - Gas not calculated by the handleOps method, but added to the gas paid.\n * Covers batch overhead.\n * @param gasFees - packed gas fields maxPriorityFeePerGas and maxFeePerGas - Same as EIP-1559 gas parameters.\n * @param paymasterAndData - If set, this field holds the paymaster address, verification gas limit, postOp gas limit and paymaster-specific extra data\n * The paymaster will pay for the transaction instead of the sender.\n * @param signature - Sender-verified signature over the entire request, the EntryPoint address and the chain ID.\n */\nstruct 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" }, + "@account-abstraction/contracts/utils/Exec.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n// solhint-disable no-inline-assembly\n\n/**\n * Utility functions helpful when making different kinds of contract calls in Solidity.\n */\nlibrary Exec {\n\n function call(\n address to,\n uint256 value,\n bytes memory data,\n uint256 txGas\n ) internal returns (bool success) {\n assembly (\"memory-safe\") {\n success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0)\n }\n }\n\n function staticcall(\n address to,\n bytes memory data,\n uint256 txGas\n ) internal view returns (bool success) {\n assembly (\"memory-safe\") {\n success := staticcall(txGas, to, add(data, 0x20), mload(data), 0, 0)\n }\n }\n\n function delegateCall(\n address to,\n bytes memory data,\n uint256 txGas\n ) internal returns (bool success) {\n assembly (\"memory-safe\") {\n success := delegatecall(txGas, to, add(data, 0x20), mload(data), 0, 0)\n }\n }\n\n // get returned data from last call or delegateCall\n // maxLen - maximum length of data to return, or zero, for the full length\n function getReturnData(uint256 maxLen) internal pure returns (bytes memory returnData) {\n assembly (\"memory-safe\") {\n let len := returndatasize()\n if gt(maxLen,0) {\n if gt(len, maxLen) {\n len := maxLen\n }\n }\n let ptr := mload(0x40)\n mstore(0x40, add(ptr, add(len, 0x20)))\n mstore(ptr, len)\n returndatacopy(add(ptr, 0x20), 0, len)\n returnData := ptr\n }\n }\n\n // revert with explicit byte array (probably reverted info from call)\n function revertWithData(bytes memory returnData) internal pure {\n assembly (\"memory-safe\") {\n revert(add(returnData, 32), mload(returnData))\n }\n }\n\n // Propagate revert data from last call\n function revertWithReturnData() internal pure {\n revertWithData(getReturnData(0));\n }\n}\n" + }, "@openzeppelin/contracts/access/Ownable.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)\n\npragma solidity ^0.8.20;\n\nimport {Context} from \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * The initial owner is set to the address provided by the deployer. This can\n * later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n /**\n * @dev The caller account is not authorized to perform an operation.\n */\n error OwnableUnauthorizedAccount(address account);\n\n /**\n * @dev The owner is not a valid owner account. (eg. `address(0)`)\n */\n error OwnableInvalidOwner(address owner);\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the address provided by the deployer as the initial owner.\n */\n constructor(address initialOwner) {\n if (initialOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(initialOwner);\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n if (owner() != _msgSender()) {\n revert OwnableUnauthorizedAccount(_msgSender());\n }\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby disabling any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n if (newOwner == address(0)) {\n revert OwnableInvalidOwner(address(0));\n }\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" }, "@openzeppelin/contracts/access/Ownable2Step.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.20;\n\nimport {Ownable} from \"./Ownable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * This extension of the {Ownable} contract includes a two-step mechanism to transfer\n * ownership, where the new owner must call {acceptOwnership} in order to replace the\n * old one. This can help prevent common mistakes, such as transfers of ownership to\n * incorrect accounts, or to contracts that are unable to interact with the\n * permission system.\n *\n * The initial owner is specified at deployment time in the constructor for `Ownable`. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2Step is Ownable {\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n *\n * Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() public virtual {\n address sender = _msgSender();\n if (pendingOwner() != sender) {\n revert OwnableUnauthorizedAccount(sender);\n }\n _transferOwnership(sender);\n }\n}\n" }, - "@openzeppelin/contracts/proxy/Clones.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.5.0) (proxy/Clones.sol)\n\npragma solidity ^0.8.20;\n\nimport {Create2} from \"../utils/Create2.sol\";\nimport {Errors} from \"../utils/Errors.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-1167[ERC-1167] is a standard for\n * deploying minimal proxy contracts, also known as \"clones\".\n *\n * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies\n * > a minimal bytecode implementation that delegates all calls to a known, fixed address.\n *\n * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`\n * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the\n * deterministic method.\n */\nlibrary Clones {\n error CloneArgumentsTooLong();\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation`.\n *\n * This function uses the create opcode, which should never revert.\n *\n * WARNING: This function does not check if `implementation` has code. A clone that points to an address\n * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they\n * have no effect and leave the clone uninitialized, allowing a third party to initialize it later.\n */\n function clone(address implementation) internal returns (address instance) {\n return clone(implementation, 0);\n }\n\n /**\n * @dev Same as {xref-Clones-clone-address-}[clone], but with a `value` parameter to send native currency\n * to the new contract.\n *\n * WARNING: This function does not check if `implementation` has code. A clone that points to an address\n * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they\n * have no effect and leave the clone uninitialized, allowing a third party to initialize it later.\n *\n * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)\n * to always have enough balance for new deployments. Consider exposing this function under a payable method.\n */\n function clone(address implementation, uint256 value) internal returns (address instance) {\n if (address(this).balance < value) {\n revert Errors.InsufficientBalance(address(this).balance, value);\n }\n assembly (\"memory-safe\") {\n // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes\n // of the `implementation` address with the bytecode before the address.\n mstore(0x00, or(shr(232, shl(96, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))\n // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.\n mstore(0x20, or(shl(120, implementation), 0x5af43d82803e903d91602b57fd5bf3))\n instance := create(value, 0x09, 0x37)\n }\n if (instance == address(0)) {\n revert Errors.FailedDeployment();\n }\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation`.\n *\n * This function uses the create2 opcode and a `salt` to deterministically deploy\n * the clone. Using the same `implementation` and `salt` multiple times will revert, since\n * the clones cannot be deployed twice at the same address.\n *\n * WARNING: This function does not check if `implementation` has code. A clone that points to an address\n * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they\n * have no effect and leave the clone uninitialized, allowing a third party to initialize it later.\n */\n function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {\n return cloneDeterministic(implementation, salt, 0);\n }\n\n /**\n * @dev Same as {xref-Clones-cloneDeterministic-address-bytes32-}[cloneDeterministic], but with\n * a `value` parameter to send native currency to the new contract.\n *\n * WARNING: This function does not check if `implementation` has code. A clone that points to an address\n * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they\n * have no effect and leave the clone uninitialized, allowing a third party to initialize it later.\n *\n * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)\n * to always have enough balance for new deployments. Consider exposing this function under a payable method.\n */\n function cloneDeterministic(\n address implementation,\n bytes32 salt,\n uint256 value\n ) internal returns (address instance) {\n if (address(this).balance < value) {\n revert Errors.InsufficientBalance(address(this).balance, value);\n }\n assembly (\"memory-safe\") {\n // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes\n // of the `implementation` address with the bytecode before the address.\n mstore(0x00, or(shr(232, shl(96, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))\n // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.\n mstore(0x20, or(shl(120, implementation), 0x5af43d82803e903d91602b57fd5bf3))\n instance := create2(value, 0x09, 0x37, salt)\n }\n if (instance == address(0)) {\n revert Errors.FailedDeployment();\n }\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(\n address implementation,\n bytes32 salt,\n address deployer\n ) internal pure returns (address predicted) {\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n mstore(add(ptr, 0x38), deployer)\n mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)\n mstore(add(ptr, 0x14), implementation)\n mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)\n mstore(add(ptr, 0x58), salt)\n mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))\n predicted := and(keccak256(add(ptr, 0x43), 0x55), 0xffffffffffffffffffffffffffffffffffffffff)\n }\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.\n */\n function predictDeterministicAddress(\n address implementation,\n bytes32 salt\n ) internal view returns (address predicted) {\n return predictDeterministicAddress(implementation, salt, address(this));\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom\n * immutable arguments. These are provided through `args` and cannot be changed after deployment. To\n * access the arguments within the implementation, use {fetchCloneArgs}.\n *\n * This function uses the create opcode, which should never revert.\n *\n * WARNING: This function does not check if `implementation` has code. A clone that points to an address\n * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they\n * have no effect and leave the clone uninitialized, allowing a third party to initialize it later.\n */\n function cloneWithImmutableArgs(address implementation, bytes memory args) internal returns (address instance) {\n return cloneWithImmutableArgs(implementation, args, 0);\n }\n\n /**\n * @dev Same as {xref-Clones-cloneWithImmutableArgs-address-bytes-}[cloneWithImmutableArgs], but with a `value`\n * parameter to send native currency to the new contract.\n *\n * WARNING: This function does not check if `implementation` has code. A clone that points to an address\n * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they\n * have no effect and leave the clone uninitialized, allowing a third party to initialize it later.\n *\n * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)\n * to always have enough balance for new deployments. Consider exposing this function under a payable method.\n */\n function cloneWithImmutableArgs(\n address implementation,\n bytes memory args,\n uint256 value\n ) internal returns (address instance) {\n if (address(this).balance < value) {\n revert Errors.InsufficientBalance(address(this).balance, value);\n }\n bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);\n assembly (\"memory-safe\") {\n instance := create(value, add(bytecode, 0x20), mload(bytecode))\n }\n if (instance == address(0)) {\n revert Errors.FailedDeployment();\n }\n }\n\n /**\n * @dev Deploys and returns the address of a clone that mimics the behavior of `implementation` with custom\n * immutable arguments. These are provided through `args` and cannot be changed after deployment. To\n * access the arguments within the implementation, use {fetchCloneArgs}.\n *\n * This function uses the create2 opcode and a `salt` to deterministically deploy the clone. Using the same\n * `implementation`, `args` and `salt` multiple times will revert, since the clones cannot be deployed twice\n * at the same address.\n *\n * WARNING: This function does not check if `implementation` has code. A clone that points to an address\n * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they\n * have no effect and leave the clone uninitialized, allowing a third party to initialize it later.\n */\n function cloneDeterministicWithImmutableArgs(\n address implementation,\n bytes memory args,\n bytes32 salt\n ) internal returns (address instance) {\n return cloneDeterministicWithImmutableArgs(implementation, args, salt, 0);\n }\n\n /**\n * @dev Same as {xref-Clones-cloneDeterministicWithImmutableArgs-address-bytes-bytes32-}[cloneDeterministicWithImmutableArgs],\n * but with a `value` parameter to send native currency to the new contract.\n *\n * WARNING: This function does not check if `implementation` has code. A clone that points to an address\n * without code cannot be initialized. Initialization calls may appear to be successful when, in reality, they\n * have no effect and leave the clone uninitialized, allowing a third party to initialize it later.\n *\n * NOTE: Using a non-zero value at creation will require the contract using this function (e.g. a factory)\n * to always have enough balance for new deployments. Consider exposing this function under a payable method.\n */\n function cloneDeterministicWithImmutableArgs(\n address implementation,\n bytes memory args,\n bytes32 salt,\n uint256 value\n ) internal returns (address instance) {\n bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);\n return Create2.deploy(value, salt, bytecode);\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.\n */\n function predictDeterministicAddressWithImmutableArgs(\n address implementation,\n bytes memory args,\n bytes32 salt,\n address deployer\n ) internal pure returns (address predicted) {\n bytes memory bytecode = _cloneCodeWithImmutableArgs(implementation, args);\n return Create2.computeAddress(salt, keccak256(bytecode), deployer);\n }\n\n /**\n * @dev Computes the address of a clone deployed using {Clones-cloneDeterministicWithImmutableArgs}.\n */\n function predictDeterministicAddressWithImmutableArgs(\n address implementation,\n bytes memory args,\n bytes32 salt\n ) internal view returns (address predicted) {\n return predictDeterministicAddressWithImmutableArgs(implementation, args, salt, address(this));\n }\n\n /**\n * @dev Get the immutable args attached to a clone.\n *\n * - If `instance` is a clone that was deployed using `clone` or `cloneDeterministic`, this\n * function will return an empty array.\n * - If `instance` is a clone that was deployed using `cloneWithImmutableArgs` or\n * `cloneDeterministicWithImmutableArgs`, this function will return the args array used at\n * creation.\n * - If `instance` is NOT a clone deployed using this library, the behavior is undefined. This\n * function should only be used to check addresses that are known to be clones.\n */\n function fetchCloneArgs(address instance) internal view returns (bytes memory) {\n bytes memory result = new bytes(instance.code.length - 0x2d); // revert if length is too short\n assembly (\"memory-safe\") {\n extcodecopy(instance, add(result, 0x20), 0x2d, mload(result))\n }\n return result;\n }\n\n /**\n * @dev Helper that prepares the initcode of the proxy with immutable args.\n *\n * An assembly variant of this function requires copying the `args` array, which can be efficiently done using\n * `mcopy`. Unfortunately, that opcode is not available before cancun. A pure solidity implementation using\n * abi.encodePacked is more expensive but also more portable and easier to review.\n *\n * NOTE: https://eips.ethereum.org/EIPS/eip-170[EIP-170] limits the length of the contract code to 24576 bytes.\n * With the proxy code taking 45 bytes, that limits the length of the immutable args to 24531 bytes.\n */\n function _cloneCodeWithImmutableArgs(\n address implementation,\n bytes memory args\n ) private pure returns (bytes memory) {\n if (args.length > 0x5fd3) revert CloneArgumentsTooLong();\n return\n abi.encodePacked(\n hex\"61\",\n uint16(args.length + 0x2d),\n hex\"3d81600a3d39f3363d3d373d3d3d363d73\",\n implementation,\n hex\"5af43d82803e903d91602b57fd5bf3\",\n args\n );\n }\n}\n" + "@openzeppelin/contracts/account/Account.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (account/Account.sol)\n\npragma solidity ^0.8.20;\n\nimport {PackedUserOperation, IAccount, IEntryPoint} from \"../interfaces/draft-IERC4337.sol\";\nimport {ERC4337Utils} from \"./utils/draft-ERC4337Utils.sol\";\nimport {AbstractSigner} from \"../utils/cryptography/signers/AbstractSigner.sol\";\nimport {LowLevelCall} from \"../utils/LowLevelCall.sol\";\n\n/**\n * @dev A simple ERC4337 account implementation. This base implementation only includes the minimal logic to process\n * user operations.\n *\n * Developers must implement the {AbstractSigner-_rawSignatureValidation} function to define the account's validation logic.\n *\n * NOTE: This core account doesn't include any mechanism for performing arbitrary external calls. This is an essential\n * feature that all Account should have. We leave it up to the developers to implement the mechanism of their choice.\n * Common choices include ERC-6900, ERC-7579 and ERC-7821 (among others).\n *\n * IMPORTANT: Implementing a mechanism to validate signatures is a security-sensitive operation as it may allow an\n * attacker to bypass the account's security measures. Check out {SignerECDSA}, {SignerP256}, or {SignerRSA} for\n * digital signature validation implementations.\n *\n * @custom:stateless\n */\nabstract contract Account is AbstractSigner, IAccount {\n /**\n * @dev Unauthorized call to the account.\n */\n error AccountUnauthorized(address sender);\n\n /**\n * @dev Revert if the caller is not the entry point or the account itself.\n */\n modifier onlyEntryPointOrSelf() {\n _checkEntryPointOrSelf();\n _;\n }\n\n /**\n * @dev Revert if the caller is not the entry point.\n */\n modifier onlyEntryPoint() {\n _checkEntryPoint();\n _;\n }\n\n /**\n * @dev Canonical entry point for the account that forwards and validates user operations.\n */\n function entryPoint() public view virtual returns (IEntryPoint) {\n return ERC4337Utils.ENTRYPOINT_V09;\n }\n\n /**\n * @dev Return the account nonce for the canonical sequence.\n */\n function getNonce() public view virtual returns (uint256) {\n return getNonce(0);\n }\n\n /**\n * @dev Return the account nonce for a given sequence (key).\n */\n function getNonce(uint192 key) public view virtual returns (uint256) {\n return entryPoint().getNonce(address(this), key);\n }\n\n /**\n * @inheritdoc IAccount\n */\n function validateUserOp(\n PackedUserOperation calldata userOp,\n bytes32 userOpHash,\n uint256 missingAccountFunds\n ) public virtual onlyEntryPoint returns (uint256) {\n uint256 validationData = _validateUserOp(userOp, userOpHash, userOp.signature);\n _payPrefund(missingAccountFunds);\n return validationData;\n }\n\n /**\n * @dev Returns the validationData for a given user operation. By default, this checks the signature of the\n * signable hash (produced by {_signableUserOpHash}) using the abstract signer ({AbstractSigner-_rawSignatureValidation}).\n *\n * The `signature` parameter is taken directly from the user operation's `signature` field.\n * This design enables derived contracts to implement custom signature handling logic,\n * such as embedding additional data within the signature and processing it by overriding this function\n * and optionally invoking `super`.\n *\n * NOTE: The userOpHash is assumed to be correct. Calling this function with a userOpHash that does not match the\n * userOp will result in undefined behavior.\n */\n function _validateUserOp(\n PackedUserOperation calldata userOp,\n bytes32 userOpHash,\n bytes calldata signature\n ) internal virtual returns (uint256) {\n return\n _rawSignatureValidation(_signableUserOpHash(userOp, userOpHash), signature)\n ? ERC4337Utils.SIG_VALIDATION_SUCCESS\n : ERC4337Utils.SIG_VALIDATION_FAILED;\n }\n\n /**\n * @dev Virtual function that returns the signable hash for a user operations. Since v0.8.0 of the entrypoint,\n * `userOpHash` is an EIP-712 hash that can be signed directly.\n */\n function _signableUserOpHash(\n PackedUserOperation calldata /*userOp*/,\n bytes32 userOpHash\n ) internal view virtual returns (bytes32) {\n return userOpHash;\n }\n\n /**\n * @dev Sends the missing funds for executing the user operation to the {entrypoint}.\n * The `missingAccountFunds` must be defined by the entrypoint when calling {validateUserOp}.\n */\n function _payPrefund(uint256 missingAccountFunds) internal virtual {\n if (missingAccountFunds > 0) {\n LowLevelCall.callNoReturn(msg.sender, missingAccountFunds, \"\"); // The entrypoint should validate the result.\n }\n }\n\n /**\n * @dev Ensures the caller is the {entrypoint}.\n */\n function _checkEntryPoint() internal view virtual {\n address sender = msg.sender;\n if (sender != address(entryPoint())) {\n revert AccountUnauthorized(sender);\n }\n }\n\n /**\n * @dev Ensures the caller is the {entrypoint} or the account itself.\n */\n function _checkEntryPointOrSelf() internal view virtual {\n address sender = msg.sender;\n if (sender != address(this) && sender != address(entryPoint())) {\n revert AccountUnauthorized(sender);\n }\n }\n\n /**\n * @dev Receive Ether.\n */\n receive() external payable virtual {}\n}\n" + }, + "@openzeppelin/contracts/account/extensions/draft-ERC7821.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.5.0) (account/extensions/draft-ERC7821.sol)\n\npragma solidity ^0.8.20;\n\nimport {ERC7579Utils, Mode, CallType, ExecType, ModeSelector} from \"../utils/draft-ERC7579Utils.sol\";\nimport {IERC7821} from \"../../interfaces/draft-IERC7821.sol\";\nimport {Account} from \"../Account.sol\";\n\n/**\n * @dev Minimal batch executor following ERC-7821.\n *\n * Only supports single batch mode (`0x01000000000000000000`). Does not support optional \"opData\".\n *\n * @custom:stateless\n */\nabstract contract ERC7821 is IERC7821 {\n using ERC7579Utils for *;\n\n error UnsupportedExecutionMode();\n\n /**\n * @dev Executes the calls in `executionData` with no optional `opData` support.\n *\n * NOTE: Access to this function is controlled by {_erc7821AuthorizedExecutor}. Changing access permissions, for\n * example to approve calls by the ERC-4337 entrypoint, should be implemented by overriding it.\n *\n * Reverts and bubbles up error if any call fails.\n */\n function execute(bytes32 mode, bytes calldata executionData) public payable virtual {\n if (!_erc7821AuthorizedExecutor(msg.sender, mode, executionData))\n revert Account.AccountUnauthorized(msg.sender);\n if (!supportsExecutionMode(mode)) revert UnsupportedExecutionMode();\n executionData.execBatch(ERC7579Utils.EXECTYPE_DEFAULT);\n }\n\n /// @inheritdoc IERC7821\n function supportsExecutionMode(bytes32 mode) public view virtual returns (bool result) {\n (CallType callType, ExecType execType, ModeSelector modeSelector, ) = Mode.wrap(mode).decodeMode();\n return\n callType == ERC7579Utils.CALLTYPE_BATCH &&\n execType == ERC7579Utils.EXECTYPE_DEFAULT &&\n modeSelector == ModeSelector.wrap(0x00000000);\n }\n\n /**\n * @dev Access control mechanism for the {execute} function.\n * By default, only the contract itself is allowed to execute.\n *\n * Override this function to implement custom access control, for example to allow the\n * ERC-4337 entrypoint to execute.\n *\n * ```solidity\n * function _erc7821AuthorizedExecutor(\n * address caller,\n * bytes32 mode,\n * bytes calldata executionData\n * ) internal view virtual override returns (bool) {\n * return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData);\n * }\n * ```\n */\n function _erc7821AuthorizedExecutor(\n address caller,\n bytes32 /* mode */,\n bytes calldata /* executionData */\n ) internal view virtual returns (bool) {\n return caller == address(this);\n }\n}\n" + }, + "@openzeppelin/contracts/account/utils/draft-ERC4337Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (account/utils/draft-ERC4337Utils.sol)\n\npragma solidity ^0.8.20;\n\nimport {IEntryPoint, PackedUserOperation} from \"../../interfaces/draft-IERC4337.sol\";\nimport {Math} from \"../../utils/math/Math.sol\";\nimport {Calldata} from \"../../utils/Calldata.sol\";\nimport {Packing} from \"../../utils/Packing.sol\";\n\n/// @dev This is available on all entrypoint since v0.4.0, but is not formally part of the ERC.\ninterface IEntryPointExtra {\n function getUserOpHash(PackedUserOperation calldata userOp) external view returns (bytes32);\n}\n\n/**\n * @dev Library with common ERC-4337 utility functions.\n *\n * See https://eips.ethereum.org/EIPS/eip-4337[ERC-4337].\n */\nlibrary ERC4337Utils {\n using Packing for *;\n\n /// @dev Address of the entrypoint v0.7.0\n IEntryPoint internal constant ENTRYPOINT_V07 = IEntryPoint(0x0000000071727De22E5E9d8BAf0edAc6f37da032);\n\n /// @dev Address of the entrypoint v0.8.0\n IEntryPoint internal constant ENTRYPOINT_V08 = IEntryPoint(0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108);\n\n /// @dev Address of the entrypoint v0.9.0\n IEntryPoint internal constant ENTRYPOINT_V09 = IEntryPoint(0x433709009B8330FDa32311DF1C2AFA402eD8D009);\n\n /// @dev For simulation purposes, validateUserOp (and validatePaymasterUserOp) return this value on success.\n uint256 internal constant SIG_VALIDATION_SUCCESS = 0;\n\n /// @dev For simulation purposes, validateUserOp (and validatePaymasterUserOp) must return this value in case of signature failure, instead of revert.\n uint256 internal constant SIG_VALIDATION_FAILED = 1;\n\n /// @dev Magic value used in EntryPoint v0.9+ to detect the presence of a paymaster signature in `paymasterAndData`.\n bytes8 internal constant PAYMASTER_SIG_MAGIC = 0x22e325a297439656; // keccak256(\"PaymasterSignature\")[:8]\n\n /// @dev Highest bit set to 1 in a 6-bytes field.\n uint48 internal constant BLOCK_RANGE_FLAG = 0x800000000000;\n\n /// @dev Mask for the lower 47 bits of a 6-bytes field (equivalent to uint48(~BLOCK_RANGE_FLAG)).\n uint48 internal constant BLOCK_RANGE_MASK = 0x7fffffffffff;\n\n /// @dev Validity range of the validation data.\n enum ValidationRange {\n TIMESTAMP,\n BLOCK\n }\n\n /**\n * @dev Parses the validation data into its components and the validity range. See {packValidationData}.\n * Strips away the highest bit flag from the `validAfter` and `validUntil` fields.\n */\n function parseValidationData(\n uint256 validationData\n ) internal pure returns (address aggregator, uint48 validAfter, uint48 validUntil, ValidationRange range) {\n validAfter = uint48(bytes32(validationData).extract_32_6(0));\n validUntil = uint48(bytes32(validationData).extract_32_6(6));\n aggregator = address(bytes32(validationData).extract_32_20(12));\n range = ((validAfter & validUntil & BLOCK_RANGE_FLAG) == 0) ? ValidationRange.TIMESTAMP : ValidationRange.BLOCK;\n\n validAfter &= BLOCK_RANGE_MASK;\n validUntil &= BLOCK_RANGE_MASK;\n\n if (validUntil == 0) validUntil = BLOCK_RANGE_MASK;\n }\n\n /// @dev Packs the validation data into a single uint256. See {parseValidationData}.\n function packValidationData(\n address aggregator,\n uint48 validAfter,\n uint48 validUntil\n ) internal pure returns (uint256) {\n return\n packValidationData(\n aggregator,\n validAfter,\n validUntil,\n (validAfter & validUntil & BLOCK_RANGE_FLAG) == 0 ? ValidationRange.TIMESTAMP : ValidationRange.BLOCK\n );\n }\n\n /**\n * @dev Variant of {packValidationData} that forces which validity range to use. This overwrites the presence of\n * flags in `validAfter` and `validUntil`).\n */\n function packValidationData(\n address aggregator,\n uint48 validAfter,\n uint48 validUntil,\n ValidationRange range\n ) internal pure returns (uint256) {\n if (range == ValidationRange.TIMESTAMP) {\n validAfter &= BLOCK_RANGE_MASK;\n validUntil &= BLOCK_RANGE_MASK;\n } else if (range == ValidationRange.BLOCK) {\n validAfter |= BLOCK_RANGE_FLAG;\n validUntil |= BLOCK_RANGE_FLAG;\n }\n return uint256(bytes6(validAfter).pack_6_6(bytes6(validUntil)).pack_12_20(bytes20(aggregator)));\n }\n\n /// @dev Variant of {packValidationData} that uses a boolean success flag instead of an aggregator address.\n function packValidationData(bool sigSuccess, uint48 validAfter, uint48 validUntil) internal pure returns (uint256) {\n return\n packValidationData(\n address(uint160(Math.ternary(sigSuccess, SIG_VALIDATION_SUCCESS, SIG_VALIDATION_FAILED))),\n validAfter,\n validUntil\n );\n }\n\n /**\n * @dev Variant of {packValidationData} that uses a boolean success flag instead of an aggregator address and that\n * forces which validity range to use. This overwrites the presence of flags in `validAfter` and `validUntil`).\n */\n function packValidationData(\n bool sigSuccess,\n uint48 validAfter,\n uint48 validUntil,\n ValidationRange range\n ) internal pure returns (uint256) {\n return\n packValidationData(\n address(uint160(Math.ternary(sigSuccess, SIG_VALIDATION_SUCCESS, SIG_VALIDATION_FAILED))),\n validAfter,\n validUntil,\n range\n );\n }\n\n /**\n * @dev Combines two validation data into a single one.\n *\n * The `aggregator` is set to {SIG_VALIDATION_SUCCESS} if both are successful, while\n * the `validAfter` is the maximum and the `validUntil` is the minimum of both.\n *\n * NOTE: Returns `SIG_VALIDATION_FAILED` if the validation ranges differ.\n */\n function combineValidationData(uint256 validationData1, uint256 validationData2) internal pure returns (uint256) {\n (address aggregator1, uint48 validAfter1, uint48 validUntil1, ValidationRange range1) = parseValidationData(\n validationData1\n );\n (address aggregator2, uint48 validAfter2, uint48 validUntil2, ValidationRange range2) = parseValidationData(\n validationData2\n );\n\n if (range1 == range2) {\n bool success = aggregator1 == address(uint160(SIG_VALIDATION_SUCCESS)) &&\n aggregator2 == address(uint160(SIG_VALIDATION_SUCCESS));\n uint48 validAfter = uint48(Math.max(validAfter1, validAfter2));\n uint48 validUntil = uint48(Math.min(validUntil1, validUntil2));\n return packValidationData(success, validAfter, validUntil, range1);\n } else {\n return SIG_VALIDATION_FAILED;\n }\n }\n\n /// @dev Returns the aggregator of the `validationData` and whether it is out of time range.\n function getValidationData(uint256 validationData) internal view returns (address aggregator, bool outOfTimeRange) {\n (address aggregator_, uint48 validAfter, uint48 validUntil, ValidationRange range) = parseValidationData(\n validationData\n );\n uint256 current = Math.ternary(range == ValidationRange.TIMESTAMP, block.timestamp, block.number);\n return (aggregator_, current <= validAfter || validUntil < current);\n }\n\n /// @dev Get the hash of a user operation for a given entrypoint\n function hash(PackedUserOperation calldata self, address entrypoint) internal view returns (bytes32) {\n // NOTE: getUserOpHash is available since v0.4.0\n //\n // Prior to v0.8.0, this was easy to replicate for any entrypoint and chainId. Since v0.8.0 of the\n // entrypoint, this depends on the Entrypoint's domain separator, which cannot be hardcoded and is complex\n // to recompute. Domain separator could be fetch using the `getDomainSeparatorV4` getter, or recomputed from\n // the ERC-5267 getter, but both operation would require doing a view call to the entrypoint. Overall it feels\n // simpler and less error prone to get that functionality from the entrypoint directly.\n return IEntryPointExtra(entrypoint).getUserOpHash(self);\n }\n\n /// @dev Returns `factory` from the {PackedUserOperation}, or address(0) if the initCode is empty or not properly formatted.\n function factory(PackedUserOperation calldata self) internal pure returns (address) {\n return self.initCode.length < 20 ? address(0) : address(bytes20(self.initCode[0:20]));\n }\n\n /// @dev Returns `factoryData` from the {PackedUserOperation}, or empty bytes if the initCode is empty or not properly formatted.\n function factoryData(PackedUserOperation calldata self) internal pure returns (bytes calldata) {\n return self.initCode.length < 20 ? Calldata.emptyBytes() : self.initCode[20:];\n }\n\n /// @dev Returns `verificationGasLimit` from the {PackedUserOperation}.\n function verificationGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) {\n return uint128(self.accountGasLimits.extract_32_16(0));\n }\n\n /// @dev Returns `callGasLimit` from the {PackedUserOperation}.\n function callGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) {\n return uint128(self.accountGasLimits.extract_32_16(16));\n }\n\n /// @dev Returns the first section of `gasFees` from the {PackedUserOperation}.\n function maxPriorityFeePerGas(PackedUserOperation calldata self) internal pure returns (uint256) {\n return uint128(self.gasFees.extract_32_16(0));\n }\n\n /// @dev Returns the second section of `gasFees` from the {PackedUserOperation}.\n function maxFeePerGas(PackedUserOperation calldata self) internal pure returns (uint256) {\n return uint128(self.gasFees.extract_32_16(16));\n }\n\n /// @dev Returns the total gas price for the {PackedUserOperation} (ie. `maxFeePerGas` or `maxPriorityFeePerGas + basefee`).\n function gasPrice(PackedUserOperation calldata self) internal view returns (uint256) {\n unchecked {\n // Following values are \"per gas\"\n uint256 maxPriorityFee = maxPriorityFeePerGas(self);\n uint256 maxFee = maxFeePerGas(self);\n return Math.min(maxFee, maxPriorityFee + block.basefee);\n }\n }\n\n /// @dev Returns the first section of `paymasterAndData` from the {PackedUserOperation}.\n function paymaster(PackedUserOperation calldata self) internal pure returns (address) {\n return self.paymasterAndData.length < 52 ? address(0) : address(bytes20(self.paymasterAndData[0:20]));\n }\n\n /// @dev Returns the second section of `paymasterAndData` from the {PackedUserOperation}.\n function paymasterVerificationGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) {\n return self.paymasterAndData.length < 52 ? 0 : uint128(bytes16(self.paymasterAndData[20:36]));\n }\n\n /// @dev Returns the third section of `paymasterAndData` from the {PackedUserOperation}.\n function paymasterPostOpGasLimit(PackedUserOperation calldata self) internal pure returns (uint256) {\n return self.paymasterAndData.length < 52 ? 0 : uint128(bytes16(self.paymasterAndData[36:52]));\n }\n\n /**\n * @dev Returns the fourth section of `paymasterAndData` from the {PackedUserOperation}.\n * If a paymaster signature is present, it is excluded from the returned data.\n */\n function paymasterData(PackedUserOperation calldata self) internal pure returns (bytes calldata) {\n bool hasSignature = self.paymasterAndData.length > 9 &&\n bytes8(self.paymasterAndData[self.paymasterAndData.length - 8:]) == PAYMASTER_SIG_MAGIC;\n uint256 suffixLength = hasSignature ? _paymasterSignatureSize(self) + 10 : 0;\n return\n self.paymasterAndData.length < 52 + suffixLength\n ? Calldata.emptyBytes()\n : self.paymasterAndData[52:self.paymasterAndData.length - suffixLength];\n }\n\n /**\n * @dev Returns the paymaster signature from `paymasterAndData` (EntryPoint v0.9+).\n * Returns empty bytes if no paymaster signature is present.\n */\n function paymasterSignature(PackedUserOperation calldata self) internal pure returns (bytes calldata) {\n if (\n self.paymasterAndData.length < 10 ||\n bytes8(self.paymasterAndData[self.paymasterAndData.length - 8:]) != PAYMASTER_SIG_MAGIC\n ) return Calldata.emptyBytes();\n\n uint256 sigSize = _paymasterSignatureSize(self);\n uint256 sigEnd = self.paymasterAndData.length - 10;\n return\n self.paymasterAndData.length < 62 + sigSize\n ? Calldata.emptyBytes()\n : self.paymasterAndData[sigEnd - sigSize:sigEnd];\n }\n\n /**\n * @dev Returns the size of the paymaster signature in `paymasterAndData` (EntryPoint v0.9+).\n * Does not check minimum length of `paymasterAndData`.\n */\n function _paymasterSignatureSize(PackedUserOperation calldata self) private pure returns (uint256) {\n return\n uint16(bytes2(self.paymasterAndData[self.paymasterAndData.length - 10:self.paymasterAndData.length - 8]));\n }\n}\n" + }, + "@openzeppelin/contracts/account/utils/draft-ERC7579Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (account/utils/draft-ERC7579Utils.sol)\n\npragma solidity ^0.8.20;\n\nimport {Execution} from \"../../interfaces/draft-IERC7579.sol\";\nimport {Packing} from \"../../utils/Packing.sol\";\nimport {Address} from \"../../utils/Address.sol\";\n\ntype Mode is bytes32;\ntype CallType is bytes1;\ntype ExecType is bytes1;\ntype ModeSelector is bytes4;\ntype ModePayload is bytes22;\n\n/**\n * @dev Library with common ERC-7579 utility functions.\n *\n * See https://eips.ethereum.org/EIPS/eip-7579[ERC-7579].\n */\n// slither-disable-next-line unused-state\nlibrary ERC7579Utils {\n using Packing for *;\n\n /// @dev A single `call` execution.\n CallType internal constant CALLTYPE_SINGLE = CallType.wrap(0x00);\n\n /// @dev A batch of `call` executions.\n CallType internal constant CALLTYPE_BATCH = CallType.wrap(0x01);\n\n /// @dev A `delegatecall` execution.\n CallType internal constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF);\n\n /// @dev Default execution type that reverts on failure.\n ExecType internal constant EXECTYPE_DEFAULT = ExecType.wrap(0x00);\n\n /// @dev Execution type that does not revert on failure.\n ExecType internal constant EXECTYPE_TRY = ExecType.wrap(0x01);\n\n /**\n * @dev Emits when an {EXECTYPE_TRY} execution fails.\n * @param batchExecutionIndex The index of the failed call in the execution batch.\n * @param returndata The returned data from the failed call.\n */\n event ERC7579TryExecuteFail(uint256 batchExecutionIndex, bytes returndata);\n\n /// @dev The provided {CallType} is not supported.\n error ERC7579UnsupportedCallType(CallType callType);\n\n /// @dev The provided {ExecType} is not supported.\n error ERC7579UnsupportedExecType(ExecType execType);\n\n /// @dev The provided module doesn't match the provided module type.\n error ERC7579MismatchedModuleTypeId(uint256 moduleTypeId, address module);\n\n /// @dev The module is not installed.\n error ERC7579UninstalledModule(uint256 moduleTypeId, address module);\n\n /// @dev The module is already installed.\n error ERC7579AlreadyInstalledModule(uint256 moduleTypeId, address module);\n\n /// @dev The module type is not supported.\n error ERC7579UnsupportedModuleType(uint256 moduleTypeId);\n\n /// @dev Input calldata not properly formatted and possibly malicious.\n error ERC7579DecodingError();\n\n /// @dev Executes a single call.\n function execSingle(\n bytes calldata executionCalldata,\n ExecType execType\n ) internal returns (bytes[] memory returnData) {\n (address target, uint256 value, bytes calldata callData) = decodeSingle(executionCalldata);\n returnData = new bytes[](1);\n returnData[0] = _call(0, execType, target, value, callData);\n }\n\n /// @dev Executes a batch of calls.\n function execBatch(\n bytes calldata executionCalldata,\n ExecType execType\n ) internal returns (bytes[] memory returnData) {\n Execution[] calldata executionBatch = decodeBatch(executionCalldata);\n returnData = new bytes[](executionBatch.length);\n for (uint256 i = 0; i < executionBatch.length; ++i) {\n returnData[i] = _call(\n i,\n execType,\n executionBatch[i].target,\n executionBatch[i].value,\n executionBatch[i].callData\n );\n }\n }\n\n /// @dev Executes a delegate call.\n function execDelegateCall(\n bytes calldata executionCalldata,\n ExecType execType\n ) internal returns (bytes[] memory returnData) {\n (address target, bytes calldata callData) = decodeDelegate(executionCalldata);\n returnData = new bytes[](1);\n returnData[0] = _delegatecall(0, execType, target, callData);\n }\n\n /// @dev Encodes the mode with the provided parameters. See {decodeMode}.\n function encodeMode(\n CallType callType,\n ExecType execType,\n ModeSelector selector,\n ModePayload payload\n ) internal pure returns (Mode mode) {\n return\n Mode.wrap(\n CallType\n .unwrap(callType)\n .pack_1_1(ExecType.unwrap(execType))\n .pack_2_4(bytes4(0))\n .pack_6_4(ModeSelector.unwrap(selector))\n .pack_10_22(ModePayload.unwrap(payload))\n );\n }\n\n /// @dev Decodes the mode into its parameters. See {encodeMode}.\n function decodeMode(\n Mode mode\n ) internal pure returns (CallType callType, ExecType execType, ModeSelector selector, ModePayload payload) {\n return (\n CallType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 0x00)),\n ExecType.wrap(Packing.extract_32_1(Mode.unwrap(mode), 0x01)),\n ModeSelector.wrap(Packing.extract_32_4(Mode.unwrap(mode), 0x06)),\n ModePayload.wrap(Packing.extract_32_22(Mode.unwrap(mode), 0x0a))\n );\n }\n\n /// @dev Encodes a single call execution. See {decodeSingle}.\n function encodeSingle(\n address target,\n uint256 value,\n bytes calldata callData\n ) internal pure returns (bytes memory executionCalldata) {\n return abi.encodePacked(target, value, callData);\n }\n\n /// @dev Decodes a single call execution. See {encodeSingle}.\n function decodeSingle(\n bytes calldata executionCalldata\n ) internal pure returns (address target, uint256 value, bytes calldata callData) {\n target = address(bytes20(executionCalldata));\n value = uint256(bytes32(executionCalldata[20:52]));\n callData = executionCalldata[52:];\n }\n\n /// @dev Encodes a delegate call execution. See {decodeDelegate}.\n function encodeDelegate(\n address target,\n bytes calldata callData\n ) internal pure returns (bytes memory executionCalldata) {\n return abi.encodePacked(target, callData);\n }\n\n /// @dev Decodes a delegate call execution. See {encodeDelegate}.\n function decodeDelegate(\n bytes calldata executionCalldata\n ) internal pure returns (address target, bytes calldata callData) {\n target = address(bytes20(executionCalldata));\n callData = executionCalldata[20:];\n }\n\n /// @dev Encodes a batch of executions. See {decodeBatch}.\n function encodeBatch(Execution[] memory executionBatch) internal pure returns (bytes memory executionCalldata) {\n return abi.encode(executionBatch);\n }\n\n /// @dev Decodes a batch of executions. See {encodeBatch}.\n ///\n /// NOTE: This function runs some checks and will throw a {ERC7579DecodingError} if the input is not properly formatted.\n function decodeBatch(bytes calldata executionCalldata) internal pure returns (Execution[] calldata executionBatch) {\n unchecked {\n uint256 bufferLength = executionCalldata.length;\n\n // Check executionCalldata is not empty.\n if (bufferLength < 0x20) revert ERC7579DecodingError();\n\n // Get the offset of the array (pointer to the array length).\n uint256 arrayLengthOffset = uint256(bytes32(executionCalldata[0x00:0x20]));\n\n // The array length (at arrayLengthOffset) should be 32 bytes long. We check that this is within the\n // buffer bounds. Since we know bufferLength is at least 32, we can subtract with no overflow risk.\n if (arrayLengthOffset > bufferLength - 0x20) revert ERC7579DecodingError();\n\n // Get the array length. arrayLengthOffset + 32 is bounded by bufferLength so it does not overflow.\n uint256 arrayLength = uint256(bytes32(executionCalldata[arrayLengthOffset:arrayLengthOffset + 0x20]));\n\n // Check that the buffer is long enough to store the array elements as \"offset pointer\":\n // - each element of the array is an \"offset pointer\" to the data.\n // - each \"offset pointer\" (to an array element) takes 32 bytes.\n // - validity of the calldata at that location is checked when the array element is accessed, so we only\n // need to check that the buffer is large enough to hold the pointers.\n //\n // Since we know bufferLength is at least arrayLengthOffset + 32, we can subtract with no overflow risk.\n // Solidity limits length of such arrays to 2**64-1, this guarantees `arrayLength * 32` does not overflow.\n if (arrayLength > type(uint64).max || bufferLength - arrayLengthOffset - 0x20 < arrayLength * 0x20)\n revert ERC7579DecodingError();\n\n assembly (\"memory-safe\") {\n executionBatch.offset := add(add(executionCalldata.offset, arrayLengthOffset), 0x20)\n executionBatch.length := arrayLength\n }\n }\n }\n\n /// @dev Executes a `call` to the target with the provided {ExecType}.\n function _call(\n uint256 index,\n ExecType execType,\n address target,\n uint256 value,\n bytes calldata data\n ) private returns (bytes memory) {\n (bool success, bytes memory returndata) = (target == address(0) ? address(this) : target).call{value: value}(\n data\n );\n return _validateExecutionMode(index, execType, success, returndata);\n }\n\n /// @dev Executes a `delegatecall` to the target with the provided {ExecType}.\n function _delegatecall(\n uint256 index,\n ExecType execType,\n address target,\n bytes calldata data\n ) private returns (bytes memory) {\n (bool success, bytes memory returndata) = (target == address(0) ? address(this) : target).delegatecall(data);\n return _validateExecutionMode(index, execType, success, returndata);\n }\n\n /// @dev Validates the execution mode and returns the returndata.\n function _validateExecutionMode(\n uint256 index,\n ExecType execType,\n bool success,\n bytes memory returndata\n ) private returns (bytes memory) {\n if (execType == ERC7579Utils.EXECTYPE_DEFAULT) {\n Address.verifyCallResult(success, returndata);\n } else if (execType == ERC7579Utils.EXECTYPE_TRY) {\n if (!success) emit ERC7579TryExecuteFail(index, returndata);\n } else {\n revert ERC7579UnsupportedExecType(execType);\n }\n return returndata;\n }\n}\n\n// Operators\nusing {eqCallType as ==} for CallType global;\nusing {eqExecType as ==} for ExecType global;\nusing {eqModeSelector as ==} for ModeSelector global;\nusing {eqModePayload as ==} for ModePayload global;\n\n/// @dev Compares two `CallType` values for equality.\nfunction eqCallType(CallType a, CallType b) pure returns (bool) {\n return CallType.unwrap(a) == CallType.unwrap(b);\n}\n\n/// @dev Compares two `ExecType` values for equality.\nfunction eqExecType(ExecType a, ExecType b) pure returns (bool) {\n return ExecType.unwrap(a) == ExecType.unwrap(b);\n}\n\n/// @dev Compares two `ModeSelector` values for equality.\nfunction eqModeSelector(ModeSelector a, ModeSelector b) pure returns (bool) {\n return ModeSelector.unwrap(a) == ModeSelector.unwrap(b);\n}\n\n/// @dev Compares two `ModePayload` values for equality.\nfunction eqModePayload(ModePayload a, ModePayload b) pure returns (bool) {\n return ModePayload.unwrap(a) == ModePayload.unwrap(b);\n}\n" + }, + "@openzeppelin/contracts/account/utils/EIP7702Utils.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (account/utils/EIP7702Utils.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library with common EIP-7702 utility functions.\n *\n * See https://eips.ethereum.org/EIPS/eip-7702[EIP-7702].\n */\nlibrary EIP7702Utils {\n bytes3 internal constant EIP7702_PREFIX = 0xef0100;\n\n /**\n * @dev Returns the address of the delegate if `account` has an EIP-7702 delegation setup, or address(0) otherwise.\n */\n function fetchDelegate(address account) internal view returns (address) {\n bytes23 delegation = bytes23(account.code);\n return bytes3(delegation) == EIP7702_PREFIX ? address(bytes20(delegation << 24)) : address(0);\n }\n}\n" + }, + "@openzeppelin/contracts/interfaces/draft-IERC4337.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (interfaces/draft-IERC4337.sol)\n\npragma solidity >=0.8.4;\n\n/**\n * @dev A https://github.com/ethereum/ercs/blob/master/ERCS/erc-4337.md#useroperation[user operation] is composed of the following elements:\n * - `sender` (`address`): The account making the operation\n * - `nonce` (`uint256`): Anti-replay parameter (see “Semi-abstracted Nonce Support” )\n * - `factory` (`address`): account factory, only for new accounts\n * - `factoryData` (`bytes`): data for account factory (only if account factory exists)\n * - `callData` (`bytes`): The data to pass to the sender during the main execution call\n * - `callGasLimit` (`uint256`): The amount of gas to allocate the main execution call\n * - `verificationGasLimit` (`uint256`): The amount of gas to allocate for the verification step\n * - `preVerificationGas` (`uint256`): Extra gas to pay the bundler\n * - `maxFeePerGas` (`uint256`): Maximum fee per gas (similar to EIP-1559 max_fee_per_gas)\n * - `maxPriorityFeePerGas` (`uint256`): Maximum priority fee per gas (similar to EIP-1559 max_priority_fee_per_gas)\n * - `paymaster` (`address`): Address of paymaster contract, (or empty, if account pays for itself)\n * - `paymasterVerificationGasLimit` (`uint256`): The amount of gas to allocate for the paymaster validation code\n * - `paymasterPostOpGasLimit` (`uint256`): The amount of gas to allocate for the paymaster post-operation code\n * - `paymasterData` (`bytes`): Data for paymaster (only if paymaster exists)\n * - `signature` (`bytes`): Data passed into the account to verify authorization\n *\n * When passed to on-chain contracts, the following packed version is used.\n * - `sender` (`address`)\n * - `nonce` (`uint256`)\n * - `initCode` (`bytes`): concatenation of factory address and factoryData (or empty)\n * - `callData` (`bytes`)\n * - `accountGasLimits` (`bytes32`): concatenation of verificationGas (16 bytes) and callGas (16 bytes)\n * - `preVerificationGas` (`uint256`)\n * - `gasFees` (`bytes32`): concatenation of maxPriorityFeePerGas (16 bytes) and maxFeePerGas (16 bytes)\n * - `paymasterAndData` (`bytes`): concatenation of paymaster fields (or empty)\n * For EntryPoint v0.9+, may optionally include `paymasterSignature` at the end:\n * `paymaster || paymasterVerificationGasLimit || paymasterPostOpGasLimit || paymasterData || paymasterSignature || paymasterSignatureSize || PAYMASTER_SIG_MAGIC`\n * - `signature` (`bytes`)\n */\nstruct PackedUserOperation {\n address sender;\n uint256 nonce;\n bytes initCode; // `abi.encodePacked(factory, factoryData)`\n bytes callData;\n bytes32 accountGasLimits; // `abi.encodePacked(verificationGasLimit, callGasLimit)` 16 bytes each\n uint256 preVerificationGas;\n bytes32 gasFees; // `abi.encodePacked(maxPriorityFeePerGas, maxFeePerGas)` 16 bytes each\n bytes paymasterAndData; // `abi.encodePacked(paymaster, paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymasterData[, paymasterSignature, paymasterSignatureSize, PAYMASTER_SIG_MAGIC])` (20 bytes, 16 bytes, 16 bytes, dynamic[, dynamic, 2 bytes, 8 bytes])\n bytes signature;\n}\n\n/**\n * @dev Aggregates and validates multiple signatures for a batch of user operations.\n *\n * A contract could implement this interface with custom validation schemes that allow signature aggregation,\n * enabling significant optimizations and gas savings for execution and transaction data cost.\n *\n * Bundlers and clients whitelist supported aggregators.\n *\n * See https://eips.ethereum.org/EIPS/eip-7766[ERC-7766]\n */\ninterface IAggregator {\n /**\n * @dev Validates the signature for a user operation.\n * Returns an alternative signature that should be used during bundling.\n */\n function validateUserOpSignature(\n PackedUserOperation calldata userOp\n ) external view returns (bytes memory sigForUserOp);\n\n /**\n * @dev Returns an aggregated signature for a batch of user operation's signatures.\n */\n function aggregateSignatures(\n PackedUserOperation[] calldata userOps\n ) external view returns (bytes memory aggregatesSignature);\n\n /**\n * @dev Validates that the aggregated signature is valid for the user operations.\n *\n * Requirements:\n *\n * - The aggregated signature MUST match the given list of operations.\n */\n function validateSignatures(PackedUserOperation[] calldata userOps, bytes calldata signature) external view;\n}\n\n/**\n * @dev Handle nonce management for accounts.\n *\n * Nonces are used in accounts as a replay protection mechanism and to ensure the order of user operations.\n * To avoid limiting the number of operations an account can perform, the interface allows using parallel\n * nonces by using a `key` parameter.\n *\n * See https://eips.ethereum.org/EIPS/eip-4337#semi-abstracted-nonce-support[ERC-4337 semi-abstracted nonce support].\n */\ninterface IEntryPointNonces {\n /**\n * @dev Returns the nonce for a `sender` account and a `key`.\n *\n * Nonces for a certain `key` are always increasing.\n */\n function getNonce(address sender, uint192 key) external view returns (uint256 nonce);\n}\n\n/**\n * @dev Handle stake management for entities (i.e. accounts, paymasters, factories).\n *\n * The EntryPoint must implement the following API to let entities like paymasters have a stake,\n * and thus have more flexibility in their storage access\n * (see https://eips.ethereum.org/EIPS/eip-4337#reputation-scoring-and-throttlingbanning-for-global-entities[reputation, throttling and banning.])\n */\ninterface IEntryPointStake {\n /**\n * @dev Returns the balance of the account.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Deposits `msg.value` to the account.\n */\n function depositTo(address account) external payable;\n\n /**\n * @dev Withdraws `withdrawAmount` from the account to `withdrawAddress`.\n */\n function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external;\n\n /**\n * @dev Adds stake to the account with an unstake delay of `unstakeDelaySec`.\n */\n function addStake(uint32 unstakeDelaySec) external payable;\n\n /**\n * @dev Unlocks the stake of the account.\n */\n function unlockStake() external;\n\n /**\n * @dev Withdraws the stake of the account to `withdrawAddress`.\n */\n function withdrawStake(address payable withdrawAddress) external;\n}\n\n/**\n * @dev Entry point for user operations.\n *\n * User operations are validated and executed by this contract.\n */\ninterface IEntryPoint is IEntryPointNonces, IEntryPointStake {\n /**\n * @dev A user operation at `opIndex` failed with `reason`.\n */\n error FailedOp(uint256 opIndex, string reason);\n\n /**\n * @dev A user operation at `opIndex` failed with `reason` and `inner` returned data.\n */\n error FailedOpWithRevert(uint256 opIndex, string reason, bytes inner);\n\n /**\n * @dev Batch of aggregated user operations per aggregator.\n */\n struct UserOpsPerAggregator {\n PackedUserOperation[] userOps;\n IAggregator aggregator;\n bytes signature;\n }\n\n /**\n * @dev Executes a batch of user operations.\n * @param beneficiary Address to which gas is refunded upon completing the execution.\n */\n function handleOps(PackedUserOperation[] calldata ops, address payable beneficiary) external;\n\n /**\n * @dev Executes a batch of aggregated user operations per aggregator.\n * @param beneficiary Address to which gas is refunded upon completing the execution.\n */\n function handleAggregatedOps(\n UserOpsPerAggregator[] calldata opsPerAggregator,\n address payable beneficiary\n ) external;\n}\n\n/**\n * @dev Base interface for an ERC-4337 account.\n */\ninterface IAccount {\n /**\n * @dev Validates a user operation.\n *\n * * MUST validate the caller is a trusted EntryPoint\n * * MUST validate that the signature is a valid signature of the userOpHash, and SHOULD\n * return SIG_VALIDATION_FAILED (and not revert) on signature mismatch. Any other error MUST revert.\n * * MUST pay the entryPoint (caller) at least the “missingAccountFunds” (which might\n * be zero, in case the current account’s deposit is high enough)\n *\n * Returns an encoded packed validation data that is composed of the following elements:\n *\n * - `authorizer` (`address`): 0 for success, 1 for failure, otherwise the address of an authorizer contract\n * - `validUntil` (`uint48`): The UserOp is valid only up to this time. Zero for “infinite”.\n * - `validAfter` (`uint48`): The UserOp is valid only after this time.\n */\n function validateUserOp(\n PackedUserOperation calldata userOp,\n bytes32 userOpHash,\n uint256 missingAccountFunds\n ) external returns (uint256 validationData);\n}\n\n/**\n * @dev Support for executing user operations by prepending the {executeUserOp} function selector\n * to the UserOperation's `callData`.\n */\ninterface IAccountExecute {\n /**\n * @dev Executes a user operation.\n */\n function executeUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external;\n}\n\n/**\n * @dev Interface for a paymaster contract that agrees to pay for the gas costs of a user operation.\n *\n * NOTE: A paymaster must hold a stake to cover the required entrypoint stake and also the gas for the transaction.\n */\ninterface IPaymaster {\n enum PostOpMode {\n opSucceeded,\n opReverted,\n postOpReverted\n }\n\n /**\n * @dev Validates whether the paymaster is willing to pay for the user operation. See\n * {IAccount-validateUserOp} for additional information on the return value.\n *\n * NOTE: Bundlers will reject this method if it modifies the state, unless it's whitelisted.\n */\n function validatePaymasterUserOp(\n PackedUserOperation calldata userOp,\n bytes32 userOpHash,\n uint256 maxCost\n ) external returns (bytes memory context, uint256 validationData);\n\n /**\n * @dev Verifies the sender is the entrypoint.\n * @param actualGasCost the actual amount paid (by account or paymaster) for this UserOperation\n * @param actualUserOpFeePerGas total gas used by this UserOperation (including preVerification, creation, validation and execution)\n */\n function postOp(\n PostOpMode mode,\n bytes calldata context,\n uint256 actualGasCost,\n uint256 actualUserOpFeePerGas\n ) external;\n}\n" + }, + "@openzeppelin/contracts/interfaces/draft-IERC7579.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (interfaces/draft-IERC7579.sol)\n\npragma solidity >=0.8.4;\n\nimport {PackedUserOperation} from \"./draft-IERC4337.sol\";\n\nuint256 constant VALIDATION_SUCCESS = 0;\nuint256 constant VALIDATION_FAILED = 1;\nuint256 constant MODULE_TYPE_VALIDATOR = 1;\nuint256 constant MODULE_TYPE_EXECUTOR = 2;\nuint256 constant MODULE_TYPE_FALLBACK = 3;\nuint256 constant MODULE_TYPE_HOOK = 4;\n\n/// @dev Minimal configuration interface for ERC-7579 modules\ninterface IERC7579Module {\n /**\n * @dev This function is called by the smart account during installation of the module\n * @param data arbitrary data that may be passed to the module during `onInstall` initialization\n *\n * MUST revert on error (e.g. if module is already enabled)\n */\n function onInstall(bytes calldata data) external;\n\n /**\n * @dev This function is called by the smart account during uninstallation of the module\n * @param data arbitrary data that may be passed to the module during `onUninstall` de-initialization\n *\n * MUST revert on error\n */\n function onUninstall(bytes calldata data) external;\n\n /**\n * @dev Returns boolean value if module is a certain type\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n *\n * MUST return true if the module is of the given type and false otherwise\n */\n function isModuleType(uint256 moduleTypeId) external view returns (bool);\n}\n\n/**\n * @dev ERC-7579 Validation module (type 1).\n *\n * A module that implements logic to validate user operations and signatures.\n */\ninterface IERC7579Validator is IERC7579Module {\n /**\n * @dev Validates a UserOperation\n * @param userOp the ERC-4337 PackedUserOperation\n * @param userOpHash the hash of the ERC-4337 PackedUserOperation\n *\n * MUST validate that the signature is a valid signature of the userOpHash\n * SHOULD return ERC-4337's SIG_VALIDATION_FAILED (and not revert) on signature mismatch\n * See {IAccount-validateUserOp} for additional information on the return value\n */\n function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash) external returns (uint256);\n\n /**\n * @dev Validates a signature using ERC-1271\n * @param sender the address that sent the ERC-1271 request to the smart account\n * @param hash the hash of the ERC-1271 request\n * @param signature the signature of the ERC-1271 request\n *\n * MUST return the ERC-1271 `MAGIC_VALUE` if the signature is valid\n * MUST NOT modify state\n */\n function isValidSignatureWithSender(\n address sender,\n bytes32 hash,\n bytes calldata signature\n ) external view returns (bytes4);\n}\n\n/**\n * @dev ERC-7579 Hooks module (type 4).\n *\n * A module that implements logic to execute before and after the account executes a user operation,\n * either individually or batched.\n */\ninterface IERC7579Hook is IERC7579Module {\n /**\n * @dev Called by the smart account before execution\n * @param msgSender the address that called the smart account\n * @param value the value that was sent to the smart account\n * @param msgData the data that was sent to the smart account\n *\n * MAY return arbitrary data in the `hookData` return value\n */\n function preCheck(\n address msgSender,\n uint256 value,\n bytes calldata msgData\n ) external returns (bytes memory hookData);\n\n /**\n * @dev Called by the smart account after execution\n * @param hookData the data that was returned by the `preCheck` function\n *\n * MAY validate the `hookData` to validate transaction context of the `preCheck` function\n */\n function postCheck(bytes calldata hookData) external;\n}\n\nstruct Execution {\n address target;\n uint256 value;\n bytes callData;\n}\n\n/**\n * @dev ERC-7579 Execution.\n *\n * Accounts should implement this interface so that the Entrypoint and ERC-7579 modules can execute operations.\n */\ninterface IERC7579Execution {\n /**\n * @dev Executes a transaction on behalf of the account.\n * @param mode The encoded execution mode of the transaction. See account/utils/draft-ERC7579Utils.sol (Mode encoding via encodeMode/decodeMode) for details\n * @param executionCalldata The encoded execution call data\n *\n * MUST ensure adequate authorization control: e.g. onlyEntryPointOrSelf if used with ERC-4337\n * If a mode is requested that is not supported by the Account, it MUST revert\n */\n function execute(bytes32 mode, bytes calldata executionCalldata) external payable;\n\n /**\n * @dev Executes a transaction on behalf of the account.\n * This function is intended to be called by Executor Modules\n * @param mode The encoded execution mode of the transaction. See account/utils/draft-ERC7579Utils.sol (Mode encoding via encodeMode/decodeMode) for details\n * @param executionCalldata The encoded execution call data\n * @return returnData An array with the returned data of each executed subcall\n *\n * MUST ensure adequate authorization control: i.e. onlyExecutorModule\n * If a mode is requested that is not supported by the Account, it MUST revert\n */\n function executeFromExecutor(\n bytes32 mode,\n bytes calldata executionCalldata\n ) external payable returns (bytes[] memory returnData);\n}\n\n/**\n * @dev ERC-7579 Account Config.\n *\n * Accounts should implement this interface to expose information that identifies the account, supported modules and capabilities.\n */\ninterface IERC7579AccountConfig {\n /**\n * @dev Returns the account id of the smart account\n * @return accountImplementationId the account id of the smart account\n *\n * MUST return a non-empty string\n * The accountId SHOULD be structured like so:\n * \"vendorname.accountname.semver\"\n * The id SHOULD be unique across all smart accounts\n */\n function accountId() external view returns (string memory accountImplementationId);\n\n /**\n * @dev Function to check if the account supports a certain execution mode (see above)\n * @param encodedMode the encoded mode\n *\n * MUST return true if the account supports the mode and false otherwise\n */\n function supportsExecutionMode(bytes32 encodedMode) external view returns (bool);\n\n /**\n * @dev Function to check if the account supports a certain module typeId\n * @param moduleTypeId the module type ID according to the ERC-7579 spec\n *\n * MUST return true if the account supports the module type and false otherwise\n */\n function supportsModule(uint256 moduleTypeId) external view returns (bool);\n}\n\n/**\n * @dev ERC-7579 Module Config.\n *\n * Accounts should implement this interface to allow installing and uninstalling modules.\n */\ninterface IERC7579ModuleConfig {\n event ModuleInstalled(uint256 moduleTypeId, address module);\n event ModuleUninstalled(uint256 moduleTypeId, address module);\n\n /**\n * @dev Installs a Module of a certain type on the smart account\n * @param moduleTypeId the module type ID according to the ERC-7579 spec\n * @param module the module address\n * @param initData arbitrary data that may be passed to the module during `onInstall`\n * initialization.\n *\n * MUST implement authorization control\n * MUST call `onInstall` on the module with the `initData` parameter if provided\n * MUST emit ModuleInstalled event\n * MUST revert if the module is already installed or the initialization on the module failed\n */\n function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external;\n\n /**\n * @dev Uninstalls a Module of a certain type on the smart account\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * @param module the module address\n * @param deInitData arbitrary data that may be passed to the module during `onUninstall`\n * deinitialization.\n *\n * MUST implement authorization control\n * MUST call `onUninstall` on the module with the `deInitData` parameter if provided\n * MUST emit ModuleUninstalled event\n * MUST revert if the module is not installed or the deInitialization on the module failed\n */\n function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external;\n\n /**\n * @dev Returns whether a module is installed on the smart account\n * @param moduleTypeId the module type ID according the ERC-7579 spec\n * @param module the module address\n * @param additionalContext arbitrary data that may be passed to determine if the module is installed\n *\n * MUST return true if the module is installed and false otherwise\n */\n function isModuleInstalled(\n uint256 moduleTypeId,\n address module,\n bytes calldata additionalContext\n ) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/interfaces/draft-IERC7821.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/draft-IERC7821.sol)\n\npragma solidity >=0.5.0;\n\n/**\n * @dev Interface for minimal batch executor.\n */\ninterface IERC7821 {\n /**\n * @dev Executes the calls in `executionData`.\n * Reverts and bubbles up error if any call fails.\n *\n * `executionData` encoding:\n * - If `opData` is empty, `executionData` is simply `abi.encode(calls)`.\n * - Else, `executionData` is `abi.encode(calls, opData)`.\n * See: https://eips.ethereum.org/EIPS/eip-7579\n *\n * Supported modes:\n * - `bytes32(0x01000000000000000000...)`: does not support optional `opData`.\n * - `bytes32(0x01000000000078210001...)`: supports optional `opData`.\n *\n * Authorization checks:\n * - If `opData` is empty, the implementation SHOULD require that\n * `msg.sender == address(this)`.\n * - If `opData` is not empty, the implementation SHOULD use the signature\n * encoded in `opData` to determine if the caller can perform the execution.\n *\n * `opData` may be used to store additional data for authentication,\n * paymaster data, gas limits, etc.\n *\n * For calldata compression efficiency, if a Call.to is `address(0)`,\n * it will be replaced with `address(this)`.\n */\n function execute(bytes32 mode, bytes calldata executionData) external payable;\n\n /**\n * @dev This function is provided for frontends to detect support.\n * Only returns true for:\n * - `bytes32(0x01000000000000000000...)`: does not support optional `opData`.\n * - `bytes32(0x01000000000078210001...)`: supports optional `opData`.\n */\n function supportsExecutionMode(bytes32 mode) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/interfaces/IERC5267.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC5267.sol)\n\npragma solidity >=0.4.16;\n\ninterface IERC5267 {\n /**\n * @dev MAY be emitted to signal that the domain could have changed.\n */\n event EIP712DomainChanged();\n\n /**\n * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712\n * signature.\n */\n function eip712Domain()\n external\n view\n returns (\n bytes1 fields,\n string memory name,\n string memory version,\n uint256 chainId,\n address verifyingContract,\n bytes32 salt,\n uint256[] memory extensions\n );\n}\n" + }, + "@openzeppelin/contracts/utils/Address.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.5.0) (utils/Address.sol)\n\npragma solidity ^0.8.20;\n\nimport {Errors} from \"./Errors.sol\";\nimport {LowLevelCall} from \"./LowLevelCall.sol\";\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n /**\n * @dev There's no code at `target` (it is not a contract).\n */\n error AddressEmptyCode(address target);\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n if (address(this).balance < amount) {\n revert Errors.InsufficientBalance(address(this).balance, amount);\n }\n if (LowLevelCall.callNoReturn(recipient, amount, \"\")) {\n // call successful, nothing to do\n return;\n } else if (LowLevelCall.returnDataSize() > 0) {\n LowLevelCall.bubbleRevert();\n } else {\n revert Errors.FailedCall();\n }\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason or custom error, it is bubbled\n * up by this function (like regular Solidity function calls). However, if\n * the call reverted with no returned reason, this function reverts with a\n * {Errors.FailedCall} error.\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n */\n function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {\n if (address(this).balance < value) {\n revert Errors.InsufficientBalance(address(this).balance, value);\n }\n bool success = LowLevelCall.callNoReturn(target, value, data);\n if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) {\n return LowLevelCall.returnData();\n } else if (success) {\n revert AddressEmptyCode(target);\n } else if (LowLevelCall.returnDataSize() > 0) {\n LowLevelCall.bubbleRevert();\n } else {\n revert Errors.FailedCall();\n }\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n bool success = LowLevelCall.staticcallNoReturn(target, data);\n if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) {\n return LowLevelCall.returnData();\n } else if (success) {\n revert AddressEmptyCode(target);\n } else if (LowLevelCall.returnDataSize() > 0) {\n LowLevelCall.bubbleRevert();\n } else {\n revert Errors.FailedCall();\n }\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a delegate call.\n */\n function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n bool success = LowLevelCall.delegatecallNoReturn(target, data);\n if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) {\n return LowLevelCall.returnData();\n } else if (success) {\n revert AddressEmptyCode(target);\n } else if (LowLevelCall.returnDataSize() > 0) {\n LowLevelCall.bubbleRevert();\n } else {\n revert Errors.FailedCall();\n }\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target\n * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case\n * of an unsuccessful call.\n *\n * NOTE: This function is DEPRECATED and may be removed in the next major release.\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata\n ) internal view returns (bytes memory) {\n // only check if target is a contract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n if (success && (returndata.length > 0 || target.code.length > 0)) {\n return returndata;\n } else if (success) {\n revert AddressEmptyCode(target);\n } else if (returndata.length > 0) {\n LowLevelCall.bubbleRevert(returndata);\n } else {\n revert Errors.FailedCall();\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the\n * revert reason or with a default {Errors.FailedCall} error.\n */\n function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else if (returndata.length > 0) {\n LowLevelCall.bubbleRevert(returndata);\n } else {\n revert Errors.FailedCall();\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Bytes.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (utils/Bytes.sol)\n\npragma solidity ^0.8.24;\n\nimport {Math} from \"./math/Math.sol\";\n\n/**\n * @dev Bytes operations.\n */\nlibrary Bytes {\n /**\n * @dev Forward search for `s` in `buffer`\n * * If `s` is present in the buffer, returns the index of the first instance\n * * If `s` is not present in the buffer, returns type(uint256).max\n *\n * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf[Javascript's `Array.indexOf`]\n */\n function indexOf(bytes memory buffer, bytes1 s) internal pure returns (uint256) {\n return indexOf(buffer, s, 0);\n }\n\n /**\n * @dev Forward search for `s` in `buffer` starting at position `pos`\n * * If `s` is present in the buffer (at or after `pos`), returns the index of the next instance\n * * If `s` is not present in the buffer (at or after `pos`), returns type(uint256).max\n *\n * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf[Javascript's `Array.indexOf`]\n */\n function indexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) {\n uint256 length = buffer.length;\n for (uint256 i = pos; i < length; ++i) {\n if (bytes1(_unsafeReadBytesOffset(buffer, i)) == s) {\n return i;\n }\n }\n return type(uint256).max;\n }\n\n /**\n * @dev Backward search for `s` in `buffer`\n * * If `s` is present in the buffer, returns the index of the last instance\n * * If `s` is not present in the buffer, returns type(uint256).max\n *\n * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf[Javascript's `Array.lastIndexOf`]\n */\n function lastIndexOf(bytes memory buffer, bytes1 s) internal pure returns (uint256) {\n return lastIndexOf(buffer, s, type(uint256).max);\n }\n\n /**\n * @dev Backward search for `s` in `buffer` starting at position `pos`\n * * If `s` is present in the buffer (at or before `pos`), returns the index of the previous instance\n * * If `s` is not present in the buffer (at or before `pos`), returns type(uint256).max\n *\n * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf[Javascript's `Array.lastIndexOf`]\n */\n function lastIndexOf(bytes memory buffer, bytes1 s, uint256 pos) internal pure returns (uint256) {\n unchecked {\n uint256 length = buffer.length;\n for (uint256 i = Math.min(Math.saturatingAdd(pos, 1), length); i > 0; --i) {\n if (bytes1(_unsafeReadBytesOffset(buffer, i - 1)) == s) {\n return i - 1;\n }\n }\n return type(uint256).max;\n }\n }\n\n /**\n * @dev Copies the content of `buffer`, from `start` (included) to the end of `buffer` into a new bytes object in\n * memory.\n *\n * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]\n */\n function slice(bytes memory buffer, uint256 start) internal pure returns (bytes memory) {\n return slice(buffer, start, buffer.length);\n }\n\n /**\n * @dev Copies the content of `buffer`, from `start` (included) to `end` (excluded) into a new bytes object in\n * memory. The `end` argument is truncated to the length of the `buffer`.\n *\n * NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]\n */\n function slice(bytes memory buffer, uint256 start, uint256 end) internal pure returns (bytes memory) {\n // sanitize\n end = Math.min(end, buffer.length);\n start = Math.min(start, end);\n\n // allocate and copy\n bytes memory result = new bytes(end - start);\n assembly (\"memory-safe\") {\n mcopy(add(result, 0x20), add(add(buffer, 0x20), start), sub(end, start))\n }\n\n return result;\n }\n\n /**\n * @dev Moves the content of `buffer`, from `start` (included) to the end of `buffer` to the start of that buffer,\n * and shrinks the buffer length accordingly, effectively overriding the content of buffer with buffer[start:].\n *\n * NOTE: This function modifies the provided buffer in place. If you need to preserve the original buffer, use {slice} instead\n */\n function splice(bytes memory buffer, uint256 start) internal pure returns (bytes memory) {\n return splice(buffer, start, buffer.length);\n }\n\n /**\n * @dev Moves the content of `buffer`, from `start` (included) to `end` (excluded) to the start of that buffer,\n * and shrinks the buffer length accordingly, effectively overriding the content of buffer with buffer[start:end].\n * The `end` argument is truncated to the length of the `buffer`.\n *\n * NOTE: This function modifies the provided buffer in place. If you need to preserve the original buffer, use {slice} instead\n */\n function splice(bytes memory buffer, uint256 start, uint256 end) internal pure returns (bytes memory) {\n // sanitize\n end = Math.min(end, buffer.length);\n start = Math.min(start, end);\n\n // move and resize\n assembly (\"memory-safe\") {\n mcopy(add(buffer, 0x20), add(add(buffer, 0x20), start), sub(end, start))\n mstore(buffer, sub(end, start))\n }\n\n return buffer;\n }\n\n /**\n * @dev Replaces bytes in `buffer` starting at `pos` with all bytes from `replacement`.\n *\n * Parameters are clamped to valid ranges (i.e. `pos` is clamped to `[0, buffer.length]`).\n * If `pos >= buffer.length`, no replacement occurs and the buffer is returned unchanged.\n *\n * NOTE: This function modifies the provided buffer in place.\n */\n function replace(bytes memory buffer, uint256 pos, bytes memory replacement) internal pure returns (bytes memory) {\n return replace(buffer, pos, replacement, 0, replacement.length);\n }\n\n /**\n * @dev Replaces bytes in `buffer` starting at `pos` with bytes from `replacement` starting at `offset`.\n * Copies at most `length` bytes from `replacement` to `buffer`.\n *\n * Parameters are clamped to valid ranges (i.e. `pos` is clamped to `[0, buffer.length]`, `offset` is\n * clamped to `[0, replacement.length]`, and `length` is clamped to `min(length, replacement.length - offset,\n * buffer.length - pos))`. If `pos >= buffer.length` or `offset >= replacement.length`, no replacement occurs\n * and the buffer is returned unchanged.\n *\n * NOTE: This function modifies the provided buffer in place.\n */\n function replace(\n bytes memory buffer,\n uint256 pos,\n bytes memory replacement,\n uint256 offset,\n uint256 length\n ) internal pure returns (bytes memory) {\n // sanitize\n pos = Math.min(pos, buffer.length);\n offset = Math.min(offset, replacement.length);\n length = Math.min(length, Math.min(replacement.length - offset, buffer.length - pos));\n\n // replace\n assembly (\"memory-safe\") {\n mcopy(add(add(buffer, 0x20), pos), add(add(replacement, 0x20), offset), length)\n }\n\n return buffer;\n }\n\n /**\n * @dev Concatenate an array of bytes into a single bytes object.\n *\n * For fixed bytes types, we recommend using the solidity built-in `bytes.concat` or (equivalent)\n * `abi.encodePacked`.\n *\n * NOTE: this could be done in assembly with a single loop that expands starting at the FMP, but that would be\n * significantly less readable. It might be worth benchmarking the savings of the full-assembly approach.\n */\n function concat(bytes[] memory buffers) internal pure returns (bytes memory) {\n uint256 length = 0;\n for (uint256 i = 0; i < buffers.length; ++i) {\n length += buffers[i].length;\n }\n\n bytes memory result = new bytes(length);\n\n uint256 offset = 0x20;\n for (uint256 i = 0; i < buffers.length; ++i) {\n bytes memory input = buffers[i];\n assembly (\"memory-safe\") {\n mcopy(add(result, offset), add(input, 0x20), mload(input))\n }\n unchecked {\n offset += input.length;\n }\n }\n\n return result;\n }\n\n /**\n * @dev Split each byte in `input` into two nibbles (4 bits each)\n *\n * Example: hex\"01234567\" → hex\"0001020304050607\"\n */\n function toNibbles(bytes memory input) internal pure returns (bytes memory output) {\n assembly (\"memory-safe\") {\n let length := mload(input)\n output := mload(0x40)\n mstore(0x40, add(add(output, 0x20), mul(length, 2)))\n mstore(output, mul(length, 2))\n for {\n let i := 0\n } lt(i, length) {\n i := add(i, 0x10)\n } {\n let chunk := shr(128, mload(add(add(input, 0x20), i)))\n chunk := and(\n 0x0000000000000000ffffffffffffffff0000000000000000ffffffffffffffff,\n or(shl(64, chunk), chunk)\n )\n chunk := and(\n 0x00000000ffffffff00000000ffffffff00000000ffffffff00000000ffffffff,\n or(shl(32, chunk), chunk)\n )\n chunk := and(\n 0x0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff,\n or(shl(16, chunk), chunk)\n )\n chunk := and(\n 0x00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff,\n or(shl(8, chunk), chunk)\n )\n chunk := and(\n 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f,\n or(shl(4, chunk), chunk)\n )\n mstore(add(add(output, 0x20), mul(i, 2)), chunk)\n }\n }\n }\n\n /**\n * @dev Returns true if the two byte buffers are equal.\n */\n function equal(bytes memory a, bytes memory b) internal pure returns (bool) {\n return a.length == b.length && keccak256(a) == keccak256(b);\n }\n\n /**\n * @dev Reverses the byte order of a bytes32 value, converting between little-endian and big-endian.\n * Inspired by https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel[Reverse Parallel]\n */\n function reverseBytes32(bytes32 value) internal pure returns (bytes32) {\n value = // swap bytes\n ((value >> 8) & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |\n ((value & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8);\n value = // swap 2-byte long pairs\n ((value >> 16) & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |\n ((value & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16);\n value = // swap 4-byte long pairs\n ((value >> 32) & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |\n ((value & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32);\n value = // swap 8-byte long pairs\n ((value >> 64) & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |\n ((value & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64);\n return (value >> 128) | (value << 128); // swap 16-byte long pairs\n }\n\n /// @dev Same as {reverseBytes32} but optimized for 128-bit values.\n function reverseBytes16(bytes16 value) internal pure returns (bytes16) {\n value = // swap bytes\n ((value & 0xFF00FF00FF00FF00FF00FF00FF00FF00) >> 8) |\n ((value & 0x00FF00FF00FF00FF00FF00FF00FF00FF) << 8);\n value = // swap 2-byte long pairs\n ((value & 0xFFFF0000FFFF0000FFFF0000FFFF0000) >> 16) |\n ((value & 0x0000FFFF0000FFFF0000FFFF0000FFFF) << 16);\n value = // swap 4-byte long pairs\n ((value & 0xFFFFFFFF00000000FFFFFFFF00000000) >> 32) |\n ((value & 0x00000000FFFFFFFF00000000FFFFFFFF) << 32);\n return (value >> 64) | (value << 64); // swap 8-byte long pairs\n }\n\n /// @dev Same as {reverseBytes32} but optimized for 64-bit values.\n function reverseBytes8(bytes8 value) internal pure returns (bytes8) {\n value = ((value & 0xFF00FF00FF00FF00) >> 8) | ((value & 0x00FF00FF00FF00FF) << 8); // swap bytes\n value = ((value & 0xFFFF0000FFFF0000) >> 16) | ((value & 0x0000FFFF0000FFFF) << 16); // swap 2-byte long pairs\n return (value >> 32) | (value << 32); // swap 4-byte long pairs\n }\n\n /// @dev Same as {reverseBytes32} but optimized for 32-bit values.\n function reverseBytes4(bytes4 value) internal pure returns (bytes4) {\n value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); // swap bytes\n return (value >> 16) | (value << 16); // swap 2-byte long pairs\n }\n\n /// @dev Same as {reverseBytes32} but optimized for 16-bit values.\n function reverseBytes2(bytes2 value) internal pure returns (bytes2) {\n return (value >> 8) | (value << 8);\n }\n\n /**\n * @dev Counts the number of leading zero bits a bytes array. Returns `8 * buffer.length`\n * if the buffer is all zeros.\n */\n function clz(bytes memory buffer) internal pure returns (uint256) {\n for (uint256 i = 0; i < buffer.length; i += 0x20) {\n bytes32 chunk = _unsafeReadBytesOffset(buffer, i);\n if (chunk != bytes32(0)) {\n return Math.min(8 * i + Math.clz(uint256(chunk)), 8 * buffer.length);\n }\n }\n return 8 * buffer.length;\n }\n\n /**\n * @dev Reads a bytes32 from a bytes array without bounds checking.\n *\n * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the\n * assembly block as such would prevent some optimizations.\n */\n function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {\n // This is not memory safe in the general case, but all calls to this private function are within bounds.\n assembly (\"memory-safe\") {\n value := mload(add(add(buffer, 0x20), offset))\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Calldata.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/Calldata.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for manipulating objects in calldata.\n */\nlibrary Calldata {\n // slither-disable-next-line write-after-write\n function emptyBytes() internal pure returns (bytes calldata result) {\n assembly (\"memory-safe\") {\n result.offset := 0\n result.length := 0\n }\n }\n\n // slither-disable-next-line write-after-write\n function emptyString() internal pure returns (string calldata result) {\n assembly (\"memory-safe\") {\n result.offset := 0\n result.length := 0\n }\n }\n}\n" }, "@openzeppelin/contracts/utils/Context.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n function _contextSuffixLength() internal view virtual returns (uint256) {\n return 0;\n }\n}\n" }, - "@openzeppelin/contracts/utils/Create2.sol": { - "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.5.0) (utils/Create2.sol)\n\npragma solidity ^0.8.20;\n\nimport {Errors} from \"./Errors.sol\";\nimport {LowLevelCall} from \"./LowLevelCall.sol\";\n\n/**\n * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer.\n * `CREATE2` can be used to compute in advance the address where a smart\n * contract will be deployed, which allows for interesting new mechanisms known\n * as 'counterfactual interactions'.\n *\n * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more\n * information.\n */\nlibrary Create2 {\n /**\n * @dev There's no code to deploy.\n */\n error Create2EmptyBytecode();\n\n /**\n * @dev Deploys a contract using `CREATE2`. The address where the contract\n * will be deployed can be known in advance via {computeAddress}.\n *\n * The bytecode for a contract can be obtained from Solidity with\n * `type(contractName).creationCode`.\n *\n * Requirements:\n *\n * - `bytecode` must not be empty.\n * - `salt` must have not been used for `bytecode` already.\n * - the factory must have a balance of at least `amount`.\n * - if `amount` is non-zero, `bytecode` must have a `payable` constructor.\n */\n function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) {\n if (address(this).balance < amount) {\n revert Errors.InsufficientBalance(address(this).balance, amount);\n }\n if (bytecode.length == 0) {\n revert Create2EmptyBytecode();\n }\n assembly (\"memory-safe\") {\n addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)\n }\n if (addr == address(0)) {\n if (LowLevelCall.returnDataSize() == 0) {\n revert Errors.FailedDeployment();\n } else {\n LowLevelCall.bubbleRevert();\n }\n }\n }\n\n /**\n * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the\n * `bytecodeHash` or `salt` will result in a new destination address.\n */\n function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) {\n return computeAddress(salt, bytecodeHash, address(this));\n }\n\n /**\n * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at\n * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}.\n */\n function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) {\n assembly (\"memory-safe\") {\n let ptr := mload(0x40) // Get free memory pointer\n\n // | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... |\n // |---------------------|---------------------------------------------------------------------------|\n // | bytecodeHash | CCCCCCCCCCCCC...CC |\n // | salt | BBBBBBBBBBBBB...BB |\n // | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA |\n // | 0xFF | FF |\n // |---------------------|---------------------------------------------------------------------------|\n // | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC |\n // | keccak(start, 0x55) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ |\n\n mstore(add(ptr, 0x40), bytecodeHash)\n mstore(add(ptr, 0x20), salt)\n mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes\n let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff\n mstore8(start, 0xff)\n addr := and(keccak256(start, 0x55), 0xffffffffffffffffffffffffffffffffffffffff)\n }\n }\n}\n" + "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n enum RecoverError {\n NoError,\n InvalidSignature,\n InvalidSignatureLength,\n InvalidSignatureS\n }\n\n /**\n * @dev The signature is invalid.\n */\n error ECDSAInvalidSignature();\n\n /**\n * @dev The signature has an invalid length.\n */\n error ECDSAInvalidSignatureLength(uint256 length);\n\n /**\n * @dev The signature has an S value that is in the upper half order.\n */\n error ECDSAInvalidSignatureS(bytes32 s);\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not\n * return address(0) without also returning an error description. Errors are documented using an enum (error type)\n * and a bytes32 providing additional information about the error.\n *\n * If no error is returned, then the address can be used for verification purposes.\n *\n * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * NOTE: This function only supports 65-byte signatures. ERC-2098 short signatures are rejected. This restriction\n * is DEPRECATED and will be removed in v6.0. Developers SHOULD NOT use signatures as unique identifiers; use hash\n * invalidation or nonces for replay protection.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n *\n * Documentation for signature generation:\n *\n * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n */\n function tryRecover(\n bytes32 hash,\n bytes memory signature\n ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, and the only way to get them\n // currently is to use assembly.\n assembly (\"memory-safe\") {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));\n }\n }\n\n /**\n * @dev Variant of {tryRecover} that takes a signature in calldata\n */\n function tryRecoverCalldata(\n bytes32 hash,\n bytes calldata signature\n ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n if (signature.length == 65) {\n bytes32 r;\n bytes32 s;\n uint8 v;\n // ecrecover takes the signature parameters, calldata slices would work here, but are\n // significantly more expensive (length check) than using calldataload in assembly.\n assembly (\"memory-safe\") {\n r := calldataload(signature.offset)\n s := calldataload(add(signature.offset, 0x20))\n v := byte(0, calldataload(add(signature.offset, 0x40)))\n }\n return tryRecover(hash, v, r, s);\n } else {\n return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));\n }\n }\n\n /**\n * @dev Returns the address that signed a hashed message (`hash`) with\n * `signature`. This address can then be used for verification purposes.\n *\n * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:\n * this function rejects them by requiring the `s` value to be in the lower\n * half order, and the `v` value to be either 27 or 28.\n *\n * NOTE: This function only supports 65-byte signatures. ERC-2098 short signatures are rejected. This restriction\n * is DEPRECATED and will be removed in v6.0. Developers SHOULD NOT use signatures as unique identifiers; use hash\n * invalidation or nonces for replay protection.\n *\n * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n * verification to be secure: it is possible to craft signatures that\n * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n * this is by receiving a hash of the original message (which may otherwise\n * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.\n */\n function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);\n _throwError(error, errorArg);\n return recovered;\n }\n\n /**\n * @dev Variant of {recover} that takes a signature in calldata\n */\n function recoverCalldata(bytes32 hash, bytes calldata signature) internal pure returns (address) {\n (address recovered, RecoverError error, bytes32 errorArg) = tryRecoverCalldata(hash, signature);\n _throwError(error, errorArg);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n *\n * See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]\n */\n function tryRecover(\n bytes32 hash,\n bytes32 r,\n bytes32 vs\n ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n unchecked {\n bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n // We do not check for an overflow here since the shift operation results in 0 or 1.\n uint8 v = uint8((uint256(vs) >> 255) + 27);\n return tryRecover(hash, v, r, s);\n }\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `r` and `vs` short-signature fields separately.\n */\n function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {\n (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);\n _throwError(error, errorArg);\n return recovered;\n }\n\n /**\n * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function tryRecover(\n bytes32 hash,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {\n // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n //\n // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n // these malleable signatures as well.\n if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n return (address(0), RecoverError.InvalidSignatureS, s);\n }\n\n // If the signature is valid (and not malleable), return the signer address\n address signer = ecrecover(hash, v, r, s);\n if (signer == address(0)) {\n return (address(0), RecoverError.InvalidSignature, bytes32(0));\n }\n\n return (signer, RecoverError.NoError, bytes32(0));\n }\n\n /**\n * @dev Overload of {ECDSA-recover} that receives the `v`,\n * `r` and `s` signature fields separately.\n */\n function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {\n (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);\n _throwError(error, errorArg);\n return recovered;\n }\n\n /**\n * @dev Parse a signature into its `v`, `r` and `s` components. Supports 65-byte and 64-byte (ERC-2098)\n * formats. Returns (0,0,0) for invalid signatures.\n *\n * For 64-byte signatures, `v` is automatically normalized to 27 or 28.\n * For 65-byte signatures, `v` is returned as-is and MUST already be 27 or 28 for use with ecrecover.\n *\n * Consider validating the result before use, or use {tryRecover}/{recover} which perform full validation.\n */\n function parse(bytes memory signature) internal pure returns (uint8 v, bytes32 r, bytes32 s) {\n assembly (\"memory-safe\") {\n // Check the signature length\n switch mload(signature)\n // - case 65: r,s,v signature (standard)\n case 65 {\n r := mload(add(signature, 0x20))\n s := mload(add(signature, 0x40))\n v := byte(0, mload(add(signature, 0x60)))\n }\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098)\n case 64 {\n let vs := mload(add(signature, 0x40))\n r := mload(add(signature, 0x20))\n s := and(vs, shr(1, not(0)))\n v := add(shr(255, vs), 27)\n }\n default {\n r := 0\n s := 0\n v := 0\n }\n }\n }\n\n /**\n * @dev Variant of {parse} that takes a signature in calldata\n */\n function parseCalldata(bytes calldata signature) internal pure returns (uint8 v, bytes32 r, bytes32 s) {\n assembly (\"memory-safe\") {\n // Check the signature length\n switch signature.length\n // - case 65: r,s,v signature (standard)\n case 65 {\n r := calldataload(signature.offset)\n s := calldataload(add(signature.offset, 0x20))\n v := byte(0, calldataload(add(signature.offset, 0x40)))\n }\n // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098)\n case 64 {\n let vs := calldataload(add(signature.offset, 0x20))\n r := calldataload(signature.offset)\n s := and(vs, shr(1, not(0)))\n v := add(shr(255, vs), 27)\n }\n default {\n r := 0\n s := 0\n v := 0\n }\n }\n }\n\n /**\n * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.\n */\n function _throwError(RecoverError error, bytes32 errorArg) private pure {\n if (error == RecoverError.NoError) {\n return; // no error: do nothing\n } else if (error == RecoverError.InvalidSignature) {\n revert ECDSAInvalidSignature();\n } else if (error == RecoverError.InvalidSignatureLength) {\n revert ECDSAInvalidSignatureLength(uint256(errorArg));\n } else if (error == RecoverError.InvalidSignatureS) {\n revert ECDSAInvalidSignatureS(errorArg);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/EIP712.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.5.0) (utils/cryptography/EIP712.sol)\n\npragma solidity ^0.8.24;\n\nimport {MessageHashUtils} from \"./MessageHashUtils.sol\";\nimport {ShortStrings, ShortString} from \"../ShortStrings.sol\";\nimport {IERC5267} from \"../../interfaces/IERC5267.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP-712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose\n * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract\n * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to\n * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP-712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain\n * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the\n * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.\n *\n * @custom:oz-upgrades-unsafe-allow state-variable-immutable\n */\nabstract contract EIP712 is IERC5267 {\n using ShortStrings for *;\n\n bytes32 private constant TYPE_HASH =\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\");\n\n // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n // invalidate the cached domain separator if the chain id changes.\n bytes32 private immutable _cachedDomainSeparator;\n uint256 private immutable _cachedChainId;\n address private immutable _cachedThis;\n\n bytes32 private immutable _hashedName;\n bytes32 private immutable _hashedVersion;\n\n ShortString private immutable _name;\n ShortString private immutable _version;\n // slither-disable-next-line constable-states\n string private _nameFallback;\n // slither-disable-next-line constable-states\n string private _versionFallback;\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP-712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n constructor(string memory name, string memory version) {\n _name = name.toShortStringWithFallback(_nameFallback);\n _version = version.toShortStringWithFallback(_versionFallback);\n _hashedName = keccak256(bytes(name));\n _hashedVersion = keccak256(bytes(version));\n\n _cachedChainId = block.chainid;\n _cachedDomainSeparator = _buildDomainSeparator();\n _cachedThis = address(this);\n }\n\n /**\n * @dev Returns the domain separator for the current chain.\n */\n function _domainSeparatorV4() internal view returns (bytes32) {\n if (address(this) == _cachedThis && block.chainid == _cachedChainId) {\n return _cachedDomainSeparator;\n } else {\n return _buildDomainSeparator();\n }\n }\n\n function _buildDomainSeparator() private view returns (bytes32) {\n return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * )));\n * address signer = ECDSA.recover(digest, signature);\n * ```\n */\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);\n }\n\n /// @inheritdoc IERC5267\n function eip712Domain()\n public\n view\n virtual\n returns (\n bytes1 fields,\n string memory name,\n string memory version,\n uint256 chainId,\n address verifyingContract,\n bytes32 salt,\n uint256[] memory extensions\n )\n {\n return (\n hex\"0f\", // 01111\n _EIP712Name(),\n _EIP712Version(),\n block.chainid,\n address(this),\n bytes32(0),\n new uint256[](0)\n );\n }\n\n /**\n * @dev The name parameter for the EIP712 domain.\n *\n * NOTE: By default this function reads _name which is an immutable value.\n * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).\n */\n // solhint-disable-next-line func-name-mixedcase\n function _EIP712Name() internal view returns (string memory) {\n return _name.toStringWithFallback(_nameFallback);\n }\n\n /**\n * @dev The version parameter for the EIP712 domain.\n *\n * NOTE: By default this function reads _version which is an immutable value.\n * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).\n */\n // solhint-disable-next-line func-name-mixedcase\n function _EIP712Version() internal view returns (string memory) {\n return _version.toStringWithFallback(_versionFallback);\n }\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (utils/cryptography/MessageHashUtils.sol)\n\npragma solidity ^0.8.24;\n\nimport {Strings} from \"../Strings.sol\";\n\n/**\n * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.\n *\n * The library provides methods for generating a hash of a message that conforms to the\n * https://eips.ethereum.org/EIPS/eip-191[ERC-191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]\n * specifications.\n */\nlibrary MessageHashUtils {\n error ERC5267ExtensionsNotSupported();\n\n /**\n * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n * `0x45` (`personal_sign` messages).\n *\n * The digest is calculated by prefixing a bytes32 `messageHash` with\n * `\"\\x19Ethereum Signed Message:\\n32\"` and hashing the result. It corresponds with the\n * hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.\n *\n * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with\n * keccak256, although any bytes32 value can be safely used because the final digest will\n * be re-hashed.\n *\n * See {ECDSA-recover}.\n */\n function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {\n assembly (\"memory-safe\") {\n mstore(0x00, \"\\x19Ethereum Signed Message:\\n32\") // 32 is the bytes-length of messageHash\n mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix\n digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)\n }\n }\n\n /**\n * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n * `0x45` (`personal_sign` messages).\n *\n * The digest is calculated by prefixing an arbitrary `message` with\n * `\"\\x19Ethereum Signed Message:\\n\" + len(message)` and hashing the result. It corresponds with the\n * hash signed when using the https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sign[`eth_sign`] JSON-RPC method.\n *\n * See {ECDSA-recover}.\n */\n function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) {\n return\n keccak256(bytes.concat(\"\\x19Ethereum Signed Message:\\n\", bytes(Strings.toString(message.length)), message));\n }\n\n /**\n * @dev Returns the keccak256 digest of an ERC-191 signed data with version\n * `0x00` (data with intended validator).\n *\n * The digest is calculated by prefixing an arbitrary `data` with `\"\\x19\\x00\"` and the intended\n * `validator` address. Then hashing the result.\n *\n * See {ECDSA-recover}.\n */\n function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {\n return keccak256(abi.encodePacked(hex\"19_00\", validator, data));\n }\n\n /**\n * @dev Variant of {toDataWithIntendedValidatorHash-address-bytes} optimized for cases where `data` is a bytes32.\n */\n function toDataWithIntendedValidatorHash(\n address validator,\n bytes32 messageHash\n ) internal pure returns (bytes32 digest) {\n assembly (\"memory-safe\") {\n mstore(0x00, hex\"19_00\")\n mstore(0x02, shl(96, validator))\n mstore(0x16, messageHash)\n digest := keccak256(0x00, 0x36)\n }\n }\n\n /**\n * @dev Returns the keccak256 digest of an EIP-712 typed data (ERC-191 version `0x01`).\n *\n * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with\n * `\\x19\\x01` and hashing the result. It corresponds to the hash signed by the\n * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.\n *\n * See {ECDSA-recover}.\n */\n function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n mstore(ptr, hex\"19_01\")\n mstore(add(ptr, 0x02), domainSeparator)\n mstore(add(ptr, 0x22), structHash)\n digest := keccak256(ptr, 0x42)\n }\n }\n\n /**\n * @dev Returns the EIP-712 domain separator constructed from an `eip712Domain`. See {IERC5267-eip712Domain}\n *\n * This function dynamically constructs the domain separator based on which fields are present in the\n * `fields` parameter. It contains flags that indicate which domain fields are present:\n *\n * * Bit 0 (0x01): name\n * * Bit 1 (0x02): version\n * * Bit 2 (0x04): chainId\n * * Bit 3 (0x08): verifyingContract\n * * Bit 4 (0x10): salt\n *\n * Arguments that correspond to fields which are not present in `fields` are ignored. For example, if `fields` is\n * `0x0f` (`0b01111`), then the `salt` parameter is ignored.\n */\n function toDomainSeparator(\n bytes1 fields,\n string memory name,\n string memory version,\n uint256 chainId,\n address verifyingContract,\n bytes32 salt\n ) internal pure returns (bytes32 hash) {\n return\n toDomainSeparator(\n fields,\n keccak256(bytes(name)),\n keccak256(bytes(version)),\n chainId,\n verifyingContract,\n salt\n );\n }\n\n /// @dev Variant of {toDomainSeparator-bytes1-string-string-uint256-address-bytes32} that uses hashed name and version.\n function toDomainSeparator(\n bytes1 fields,\n bytes32 nameHash,\n bytes32 versionHash,\n uint256 chainId,\n address verifyingContract,\n bytes32 salt\n ) internal pure returns (bytes32 hash) {\n bytes32 domainTypeHash = toDomainTypeHash(fields);\n\n assembly (\"memory-safe\") {\n // align fields to the right for easy processing\n fields := shr(248, fields)\n\n // FMP used as scratch space\n let fmp := mload(0x40)\n mstore(fmp, domainTypeHash)\n\n let ptr := add(fmp, 0x20)\n if and(fields, 0x01) {\n mstore(ptr, nameHash)\n ptr := add(ptr, 0x20)\n }\n if and(fields, 0x02) {\n mstore(ptr, versionHash)\n ptr := add(ptr, 0x20)\n }\n if and(fields, 0x04) {\n mstore(ptr, chainId)\n ptr := add(ptr, 0x20)\n }\n if and(fields, 0x08) {\n mstore(ptr, verifyingContract)\n ptr := add(ptr, 0x20)\n }\n if and(fields, 0x10) {\n mstore(ptr, salt)\n ptr := add(ptr, 0x20)\n }\n\n hash := keccak256(fmp, sub(ptr, fmp))\n }\n }\n\n /// @dev Builds an EIP-712 domain type hash depending on the `fields` provided, following https://eips.ethereum.org/EIPS/eip-5267[ERC-5267]\n function toDomainTypeHash(bytes1 fields) internal pure returns (bytes32 hash) {\n if (fields & 0x20 == 0x20) revert ERC5267ExtensionsNotSupported();\n\n assembly (\"memory-safe\") {\n // align fields to the right for easy processing\n fields := shr(248, fields)\n\n // FMP used as scratch space\n let fmp := mload(0x40)\n mstore(fmp, \"EIP712Domain(\")\n\n let ptr := add(fmp, 0x0d)\n // name field\n if and(fields, 0x01) {\n mstore(ptr, \"string name,\")\n ptr := add(ptr, 0x0c)\n }\n // version field\n if and(fields, 0x02) {\n mstore(ptr, \"string version,\")\n ptr := add(ptr, 0x0f)\n }\n // chainId field\n if and(fields, 0x04) {\n mstore(ptr, \"uint256 chainId,\")\n ptr := add(ptr, 0x10)\n }\n // verifyingContract field\n if and(fields, 0x08) {\n mstore(ptr, \"address verifyingContract,\")\n ptr := add(ptr, 0x1a)\n }\n // salt field\n if and(fields, 0x10) {\n mstore(ptr, \"bytes32 salt,\")\n ptr := add(ptr, 0x0d)\n }\n // if any field is enabled, remove the trailing comma\n ptr := sub(ptr, iszero(iszero(and(fields, 0x1f))))\n // add the closing brace\n mstore8(ptr, 0x29) // add closing brace\n ptr := add(ptr, 1)\n\n hash := keccak256(fmp, sub(ptr, fmp))\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/signers/AbstractSigner.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/cryptography/signers/AbstractSigner.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Abstract contract for signature validation.\n *\n * Developers must implement {_rawSignatureValidation} and use it as the lowest-level signature validation mechanism.\n *\n * @custom:stateless\n */\nabstract contract AbstractSigner {\n /**\n * @dev Signature validation algorithm.\n *\n * WARNING: Implementing a signature validation algorithm is a security-sensitive operation as it involves\n * cryptographic verification. It is important to review and test thoroughly before deployment. Consider\n * using one of the signature verification libraries (xref:api:utils/cryptography#ECDSA[ECDSA],\n * xref:api:utils/cryptography#P256[P256] or xref:api:utils/cryptography#RSA[RSA]).\n */\n function _rawSignatureValidation(bytes32 hash, bytes calldata signature) internal view virtual returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/cryptography/signers/SignerEIP7702.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (utils/cryptography/signers/SignerEIP7702.sol)\n\npragma solidity ^0.8.20;\n\nimport {AbstractSigner} from \"./AbstractSigner.sol\";\nimport {ECDSA} from \"../ECDSA.sol\";\n\n/**\n * @dev Implementation of {AbstractSigner} for implementation for an EOA. Useful for EIP-7702 accounts.\n *\n * @custom:stateless\n */\nabstract contract SignerEIP7702 is AbstractSigner {\n /**\n * @dev Validates the signature using the EOA's address (i.e. `address(this)`).\n */\n function _rawSignatureValidation(\n bytes32 hash,\n bytes calldata signature\n ) internal view virtual override returns (bool) {\n (address recovered, ECDSA.RecoverError err, ) = ECDSA.tryRecoverCalldata(hash, signature);\n return address(this) == recovered && err == ECDSA.RecoverError.NoError;\n }\n}\n" }, "@openzeppelin/contracts/utils/Errors.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Collection of common custom errors used in multiple contracts\n *\n * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.\n * It is recommended to avoid relying on the error API for critical functionality.\n *\n * _Available since v5.1._\n */\nlibrary Errors {\n /**\n * @dev The ETH balance of the account is not enough to perform the operation.\n */\n error InsufficientBalance(uint256 balance, uint256 needed);\n\n /**\n * @dev A call to an address target failed. The target may have reverted.\n */\n error FailedCall();\n\n /**\n * @dev The deployment failed.\n */\n error FailedDeployment();\n\n /**\n * @dev A necessary precompile is missing.\n */\n error MissingPrecompile(address);\n}\n" }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n */\nabstract contract ERC165 is IERC165 {\n /// @inheritdoc IERC165\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, "@openzeppelin/contracts/utils/introspection/IERC165.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" }, "@openzeppelin/contracts/utils/LowLevelCall.sol": { "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (utils/LowLevelCall.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library of low level call functions that implement different calling strategies to deal with the return data.\n *\n * WARNING: Using this library requires an advanced understanding of Solidity and how the EVM works. It is recommended\n * to use the {Address} library instead.\n */\nlibrary LowLevelCall {\n /// @dev Performs a Solidity function call using a low level `call` and ignoring the return data.\n function callNoReturn(address target, bytes memory data) internal returns (bool success) {\n return callNoReturn(target, 0, data);\n }\n\n /// @dev Same as {callNoReturn-address-bytes}, but allows specifying the value to be sent in the call.\n function callNoReturn(address target, uint256 value, bytes memory data) internal returns (bool success) {\n assembly (\"memory-safe\") {\n success := call(gas(), target, value, add(data, 0x20), mload(data), 0x00, 0x00)\n }\n }\n\n /// @dev Performs a Solidity function call using a low level `call` and returns the first 64 bytes of the result\n /// in the scratch space of memory. Useful for functions that return a tuple with two single-word values.\n ///\n /// WARNING: Do not assume that the results are zero if `success` is false. Memory can be already allocated\n /// and this function doesn't zero it out.\n function callReturn64Bytes(\n address target,\n bytes memory data\n ) internal returns (bool success, bytes32 result1, bytes32 result2) {\n return callReturn64Bytes(target, 0, data);\n }\n\n /// @dev Same as {callReturn64Bytes-address-bytes}, but allows specifying the value to be sent in the call.\n function callReturn64Bytes(\n address target,\n uint256 value,\n bytes memory data\n ) internal returns (bool success, bytes32 result1, bytes32 result2) {\n assembly (\"memory-safe\") {\n success := call(gas(), target, value, add(data, 0x20), mload(data), 0x00, 0x40)\n result1 := mload(0x00)\n result2 := mload(0x20)\n }\n }\n\n /// @dev Performs a Solidity function call using a low level `staticcall` and ignoring the return data.\n function staticcallNoReturn(address target, bytes memory data) internal view returns (bool success) {\n assembly (\"memory-safe\") {\n success := staticcall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x00)\n }\n }\n\n /// @dev Performs a Solidity function call using a low level `staticcall` and returns the first 64 bytes of the result\n /// in the scratch space of memory. Useful for functions that return a tuple with two single-word values.\n ///\n /// WARNING: Do not assume that the results are zero if `success` is false. Memory can be already allocated\n /// and this function doesn't zero it out.\n function staticcallReturn64Bytes(\n address target,\n bytes memory data\n ) internal view returns (bool success, bytes32 result1, bytes32 result2) {\n assembly (\"memory-safe\") {\n success := staticcall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x40)\n result1 := mload(0x00)\n result2 := mload(0x20)\n }\n }\n\n /// @dev Performs a Solidity function call using a low level `delegatecall` and ignoring the return data.\n function delegatecallNoReturn(address target, bytes memory data) internal returns (bool success) {\n assembly (\"memory-safe\") {\n success := delegatecall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x00)\n }\n }\n\n /// @dev Performs a Solidity function call using a low level `delegatecall` and returns the first 64 bytes of the result\n /// in the scratch space of memory. Useful for functions that return a tuple with two single-word values.\n ///\n /// WARNING: Do not assume that the results are zero if `success` is false. Memory can be already allocated\n /// and this function doesn't zero it out.\n function delegatecallReturn64Bytes(\n address target,\n bytes memory data\n ) internal returns (bool success, bytes32 result1, bytes32 result2) {\n assembly (\"memory-safe\") {\n success := delegatecall(gas(), target, add(data, 0x20), mload(data), 0x00, 0x40)\n result1 := mload(0x00)\n result2 := mload(0x20)\n }\n }\n\n /// @dev Returns the size of the return data buffer.\n function returnDataSize() internal pure returns (uint256 size) {\n assembly (\"memory-safe\") {\n size := returndatasize()\n }\n }\n\n /// @dev Returns a buffer containing the return data from the last call.\n function returnData() internal pure returns (bytes memory result) {\n assembly (\"memory-safe\") {\n result := mload(0x40)\n mstore(result, returndatasize())\n returndatacopy(add(result, 0x20), 0x00, returndatasize())\n mstore(0x40, add(result, add(0x20, returndatasize())))\n }\n }\n\n /// @dev Revert with the return data from the last call.\n function bubbleRevert() internal pure {\n assembly (\"memory-safe\") {\n let fmp := mload(0x40)\n returndatacopy(fmp, 0x00, returndatasize())\n revert(fmp, returndatasize())\n }\n }\n\n function bubbleRevert(bytes memory returndata) internal pure {\n assembly (\"memory-safe\") {\n revert(add(returndata, 0x20), mload(returndata))\n }\n }\n}\n" }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.20;\n\nimport {Panic} from \"../Panic.sol\";\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Floor, // Toward negative infinity\n Ceil, // Toward positive infinity\n Trunc, // Toward zero\n Expand // Away from zero\n }\n\n /**\n * @dev Return the 512-bit addition of two uint256.\n *\n * The result is stored in two 256 variables such that sum = high * 2²⁵⁶ + low.\n */\n function add512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n assembly (\"memory-safe\") {\n low := add(a, b)\n high := lt(low, a)\n }\n }\n\n /**\n * @dev Return the 512-bit multiplication of two uint256.\n *\n * The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.\n */\n function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {\n // 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use\n // the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = high * 2²⁵⁶ + low.\n assembly (\"memory-safe\") {\n let mm := mulmod(a, b, not(0))\n low := mul(a, b)\n high := sub(sub(mm, low), lt(mm, low))\n }\n }\n\n /**\n * @dev Returns the addition of two unsigned integers, with a success flag (no overflow).\n */\n function tryAdd(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a + b;\n success = c >= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, with a success flag (no overflow).\n */\n function trySub(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a - b;\n success = c <= a;\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the multiplication of two unsigned integers, with a success flag (no overflow).\n */\n function tryMul(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n uint256 c = a * b;\n assembly (\"memory-safe\") {\n // Only true when the multiplication doesn't overflow\n // (c / a == b) || (a == 0)\n success := or(eq(div(c, a), b), iszero(a))\n }\n // equivalent to: success ? c : 0\n result = c * SafeCast.toUint(success);\n }\n }\n\n /**\n * @dev Returns the division of two unsigned integers, with a success flag (no division by zero).\n */\n function tryDiv(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `DIV` opcode returns zero when the denominator is 0.\n result := div(a, b)\n }\n }\n }\n\n /**\n * @dev Returns the remainder of dividing two unsigned integers, with a success flag (no division by zero).\n */\n function tryMod(uint256 a, uint256 b) internal pure returns (bool success, uint256 result) {\n unchecked {\n success = b > 0;\n assembly (\"memory-safe\") {\n // The `MOD` opcode returns zero when the denominator is 0.\n result := mod(a, b)\n }\n }\n }\n\n /**\n * @dev Unsigned saturating addition, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingAdd(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryAdd(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Unsigned saturating subtraction, bounds to zero instead of overflowing.\n */\n function saturatingSub(uint256 a, uint256 b) internal pure returns (uint256) {\n (, uint256 result) = trySub(a, b);\n return result;\n }\n\n /**\n * @dev Unsigned saturating multiplication, bounds to `2²⁵⁶ - 1` instead of overflowing.\n */\n function saturatingMul(uint256 a, uint256 b) internal pure returns (uint256) {\n (bool success, uint256 result) = tryMul(a, b);\n return ternary(success, result, type(uint256).max);\n }\n\n /**\n * @dev Branchless ternary evaluation for `condition ? a : b`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `condition ? a : b`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * SafeCast.toUint(condition));\n }\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a > b, a, b);\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return ternary(a < b, a, b);\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n unchecked {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds towards infinity instead\n * of rounding towards zero.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n if (b == 0) {\n // Guarantee the same behavior as in a regular Solidity division.\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n\n // The following calculation ensures accurate ceiling division without overflow.\n // Since a is non-zero, (a - 1) / b will not overflow.\n // The largest possible result occurs when (a - 1) / b is type(uint256).max,\n // but the largest value we can obtain is type(uint256).max - 1, which happens\n // when a = type(uint256).max and b = 1.\n unchecked {\n return SafeCast.toUint(a > 0) * ((a - 1) / b + 1);\n }\n }\n\n /**\n * @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or\n * denominator == 0.\n *\n * Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by\n * Uniswap Labs also under MIT license.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n\n // Handle non-overflow cases, 256 by 256 division.\n if (high == 0) {\n // Solidity will revert if denominator == 0, unlike the div opcode on its own.\n // The surrounding unchecked block does not change this fact.\n // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.\n return low / denominator;\n }\n\n // Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.\n if (denominator <= high) {\n Panic.panic(ternary(denominator == 0, Panic.DIVISION_BY_ZERO, Panic.UNDER_OVERFLOW));\n }\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [high low].\n uint256 remainder;\n assembly (\"memory-safe\") {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n high := sub(high, gt(remainder, low))\n low := sub(low, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator.\n // Always >= 1. See https://cs.stackexchange.com/q/138556/92363.\n\n uint256 twos = denominator & (0 - denominator);\n assembly (\"memory-safe\") {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [high low] by twos.\n low := div(low, twos)\n\n // Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from high into low.\n low |= high * twos;\n\n // Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such\n // that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv ≡ 1 mod 2⁴.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also\n // works in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶\n inverse *= 2 - denominator * inverse; // inverse mod 2³²\n inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴\n inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸\n inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is\n // less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high\n // is no longer required.\n result = low * inverse;\n return result;\n }\n }\n\n /**\n * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {\n return mulDiv(x, y, denominator) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);\n }\n\n /**\n * @dev Calculates floor(x * y >> n) with full precision. Throws if result overflows a uint256.\n */\n function mulShr(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 result) {\n unchecked {\n (uint256 high, uint256 low) = mul512(x, y);\n if (high >= 1 << n) {\n Panic.panic(Panic.UNDER_OVERFLOW);\n }\n return (high << (256 - n)) | (low >> n);\n }\n }\n\n /**\n * @dev Calculates x * y >> n with full precision, following the selected rounding direction.\n */\n function mulShr(uint256 x, uint256 y, uint8 n, Rounding rounding) internal pure returns (uint256) {\n return mulShr(x, y, n) + SafeCast.toUint(unsignedRoundsUp(rounding) && mulmod(x, y, 1 << n) > 0);\n }\n\n /**\n * @dev Calculate the modular multiplicative inverse of a number in Z/nZ.\n *\n * If n is a prime, then Z/nZ is a field. In that case all elements are inversible, except 0.\n * If n is not a prime, then Z/nZ is not a field, and some elements might not be inversible.\n *\n * If the input value is not inversible, 0 is returned.\n *\n * NOTE: If you know for sure that n is (big) a prime, it may be cheaper to use Fermat's little theorem and get the\n * inverse using `Math.modExp(a, n - 2, n)`. See {invModPrime}.\n */\n function invMod(uint256 a, uint256 n) internal pure returns (uint256) {\n unchecked {\n if (n == 0) return 0;\n\n // The inverse modulo is calculated using the Extended Euclidean Algorithm (iterative version)\n // Used to compute integers x and y such that: ax + ny = gcd(a, n).\n // When the gcd is 1, then the inverse of a modulo n exists and it's x.\n // ax + ny = 1\n // ax = 1 + (-y)n\n // ax ≡ 1 (mod n) # x is the inverse of a modulo n\n\n // If the remainder is 0 the gcd is n right away.\n uint256 remainder = a % n;\n uint256 gcd = n;\n\n // Therefore the initial coefficients are:\n // ax + ny = gcd(a, n) = n\n // 0a + 1n = n\n int256 x = 0;\n int256 y = 1;\n\n while (remainder != 0) {\n uint256 quotient = gcd / remainder;\n\n (gcd, remainder) = (\n // The old remainder is the next gcd to try.\n remainder,\n // Compute the next remainder.\n // Can't overflow given that (a % gcd) * (gcd // (a % gcd)) <= gcd\n // where gcd is at most n (capped to type(uint256).max)\n gcd - remainder * quotient\n );\n\n (x, y) = (\n // Increment the coefficient of a.\n y,\n // Decrement the coefficient of n.\n // Can overflow, but the result is casted to uint256 so that the\n // next value of y is \"wrapped around\" to a value between 0 and n - 1.\n x - y * int256(quotient)\n );\n }\n\n if (gcd != 1) return 0; // No inverse exists.\n return ternary(x < 0, n - uint256(-x), uint256(x)); // Wrap the result if it's negative.\n }\n }\n\n /**\n * @dev Variant of {invMod}. More efficient, but only works if `p` is known to be a prime greater than `2`.\n *\n * From https://en.wikipedia.org/wiki/Fermat%27s_little_theorem[Fermat's little theorem], we know that if p is\n * prime, then `a**(p-1) ≡ 1 mod p`. As a consequence, we have `a * a**(p-2) ≡ 1 mod p`, which means that\n * `a**(p-2)` is the modular multiplicative inverse of a in Fp.\n *\n * NOTE: this function does NOT check that `p` is a prime greater than `2`.\n */\n function invModPrime(uint256 a, uint256 p) internal view returns (uint256) {\n unchecked {\n return Math.modExp(a, p - 2, p);\n }\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m)\n *\n * Requirements:\n * - modulus can't be zero\n * - underlying staticcall to precompile must succeed\n *\n * IMPORTANT: The result is only valid if the underlying call succeeds. When using this function, make\n * sure the chain you're using it on supports the precompiled contract for modular exponentiation\n * at address 0x05 as specified in https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise,\n * the underlying function will succeed given the lack of a revert, but the result may be incorrectly\n * interpreted as 0.\n */\n function modExp(uint256 b, uint256 e, uint256 m) internal view returns (uint256) {\n (bool success, uint256 result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Returns the modular exponentiation of the specified base, exponent and modulus (b ** e % m).\n * It includes a success flag indicating if the operation succeeded. Operation will be marked as failed if trying\n * to operate modulo 0 or if the underlying precompile reverted.\n *\n * IMPORTANT: The result is only valid if the success flag is true. When using this function, make sure the chain\n * you're using it on supports the precompiled contract for modular exponentiation at address 0x05 as specified in\n * https://eips.ethereum.org/EIPS/eip-198[EIP-198]. Otherwise, the underlying function will succeed given the lack\n * of a revert, but the result may be incorrectly interpreted as 0.\n */\n function tryModExp(uint256 b, uint256 e, uint256 m) internal view returns (bool success, uint256 result) {\n if (m == 0) return (false, 0);\n assembly (\"memory-safe\") {\n let ptr := mload(0x40)\n // | Offset | Content | Content (Hex) |\n // |-----------|------------|--------------------------------------------------------------------|\n // | 0x00:0x1f | size of b | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x20:0x3f | size of e | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x40:0x5f | size of m | 0x0000000000000000000000000000000000000000000000000000000000000020 |\n // | 0x60:0x7f | value of b | 0x<.............................................................b> |\n // | 0x80:0x9f | value of e | 0x<.............................................................e> |\n // | 0xa0:0xbf | value of m | 0x<.............................................................m> |\n mstore(ptr, 0x20)\n mstore(add(ptr, 0x20), 0x20)\n mstore(add(ptr, 0x40), 0x20)\n mstore(add(ptr, 0x60), b)\n mstore(add(ptr, 0x80), e)\n mstore(add(ptr, 0xa0), m)\n\n // Given the result < m, it's guaranteed to fit in 32 bytes,\n // so we can use the memory scratch space located at offset 0.\n success := staticcall(gas(), 0x05, ptr, 0xc0, 0x00, 0x20)\n result := mload(0x00)\n }\n }\n\n /**\n * @dev Variant of {modExp} that supports inputs of arbitrary length.\n */\n function modExp(bytes memory b, bytes memory e, bytes memory m) internal view returns (bytes memory) {\n (bool success, bytes memory result) = tryModExp(b, e, m);\n if (!success) {\n Panic.panic(Panic.DIVISION_BY_ZERO);\n }\n return result;\n }\n\n /**\n * @dev Variant of {tryModExp} that supports inputs of arbitrary length.\n */\n function tryModExp(\n bytes memory b,\n bytes memory e,\n bytes memory m\n ) internal view returns (bool success, bytes memory result) {\n if (_zeroBytes(m)) return (false, new bytes(0));\n\n uint256 mLen = m.length;\n\n // Encode call args in result and move the free memory pointer\n result = abi.encodePacked(b.length, e.length, mLen, b, e, m);\n\n assembly (\"memory-safe\") {\n let dataPtr := add(result, 0x20)\n // Write result on top of args to avoid allocating extra memory.\n success := staticcall(gas(), 0x05, dataPtr, mload(result), dataPtr, mLen)\n // Overwrite the length.\n // result.length > returndatasize() is guaranteed because returndatasize() == m.length\n mstore(result, mLen)\n // Set the memory pointer after the returned data.\n mstore(0x40, add(dataPtr, mLen))\n }\n }\n\n /**\n * @dev Returns whether the provided byte array is zero.\n */\n function _zeroBytes(bytes memory buffer) private pure returns (bool) {\n uint256 chunk;\n for (uint256 i = 0; i < buffer.length; i += 0x20) {\n // See _unsafeReadBytesOffset from utils/Bytes.sol\n assembly (\"memory-safe\") {\n chunk := mload(add(add(buffer, 0x20), i))\n }\n if (chunk >> (8 * saturatingSub(i + 0x20, buffer.length)) != 0) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded\n * towards zero.\n *\n * This method is based on Newton's method for computing square roots; the algorithm is restricted to only\n * using integer operations.\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n unchecked {\n // Take care of easy edge cases when a == 0 or a == 1\n if (a <= 1) {\n return a;\n }\n\n // In this function, we use Newton's method to get a root of `f(x) := x² - a`. It involves building a\n // sequence x_n that converges toward sqrt(a). For each iteration x_n, we also define the error between\n // the current value as `ε_n = | x_n - sqrt(a) |`.\n //\n // For our first estimation, we consider `e` the smallest power of 2 which is bigger than the square root\n // of the target. (i.e. `2**(e-1) ≤ sqrt(a) < 2**e`). We know that `e ≤ 128` because `(2¹²⁸)² = 2²⁵⁶` is\n // bigger than any uint256.\n //\n // By noticing that\n // `2**(e-1) ≤ sqrt(a) < 2**e → (2**(e-1))² ≤ a < (2**e)² → 2**(2*e-2) ≤ a < 2**(2*e)`\n // we can deduce that `e - 1` is `log2(a) / 2`. We can thus compute `x_n = 2**(e-1)` using a method similar\n // to the msb function.\n uint256 aa = a;\n uint256 xn = 1;\n\n if (aa >= (1 << 128)) {\n aa >>= 128;\n xn <<= 64;\n }\n if (aa >= (1 << 64)) {\n aa >>= 64;\n xn <<= 32;\n }\n if (aa >= (1 << 32)) {\n aa >>= 32;\n xn <<= 16;\n }\n if (aa >= (1 << 16)) {\n aa >>= 16;\n xn <<= 8;\n }\n if (aa >= (1 << 8)) {\n aa >>= 8;\n xn <<= 4;\n }\n if (aa >= (1 << 4)) {\n aa >>= 4;\n xn <<= 2;\n }\n if (aa >= (1 << 2)) {\n xn <<= 1;\n }\n\n // 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).\n //\n // We can refine our estimation by noticing that the middle of that interval minimizes the error.\n // If we move x_n to equal 2**(e-1) + 2**(e-2), then we reduce the error to ε_n ≤ 2**(e-2).\n // This is going to be our x_0 (and ε_0)\n xn = (3 * xn) >> 1; // ε_0 := | x_0 - sqrt(a) | ≤ 2**(e-2)\n\n // From here, Newton's method give us:\n // x_{n+1} = (x_n + a / x_n) / 2\n //\n // One should note that:\n // x_{n+1}² - a = ((x_n + a / x_n) / 2)² - a\n // = ((x_n² + a) / (2 * x_n))² - a\n // = (x_n⁴ + 2 * a * x_n² + a²) / (4 * x_n²) - a\n // = (x_n⁴ + 2 * a * x_n² + a² - 4 * a * x_n²) / (4 * x_n²)\n // = (x_n⁴ - 2 * a * x_n² + a²) / (4 * x_n²)\n // = (x_n² - a)² / (2 * x_n)²\n // = ((x_n² - a) / (2 * x_n))²\n // ≥ 0\n // Which proves that for all n ≥ 1, sqrt(a) ≤ x_n\n //\n // This gives us the proof of quadratic convergence of the sequence:\n // ε_{n+1} = | x_{n+1} - sqrt(a) |\n // = | (x_n + a / x_n) / 2 - sqrt(a) |\n // = | (x_n² + a - 2*x_n*sqrt(a)) / (2 * x_n) |\n // = | (x_n - sqrt(a))² / (2 * x_n) |\n // = | ε_n² / (2 * x_n) |\n // = ε_n² / | (2 * x_n) |\n //\n // For the first iteration, we have a special case where x_0 is known:\n // ε_1 = ε_0² / | (2 * x_0) |\n // ≤ (2**(e-2))² / (2 * (2**(e-1) + 2**(e-2)))\n // ≤ 2**(2*e-4) / (3 * 2**(e-1))\n // ≤ 2**(e-3) / 3\n // ≤ 2**(e-3-log2(3))\n // ≤ 2**(e-4.5)\n //\n // For the following iterations, we use the fact that, 2**(e-1) ≤ sqrt(a) ≤ x_n:\n // ε_{n+1} = ε_n² / | (2 * x_n) |\n // ≤ (2**(e-k))² / (2 * 2**(e-1))\n // ≤ 2**(2*e-2*k) / 2**e\n // ≤ 2**(e-2*k)\n xn = (xn + a / xn) >> 1; // ε_1 := | x_1 - sqrt(a) | ≤ 2**(e-4.5) -- special case, see above\n xn = (xn + a / xn) >> 1; // ε_2 := | x_2 - sqrt(a) | ≤ 2**(e-9) -- general case with k = 4.5\n xn = (xn + a / xn) >> 1; // ε_3 := | x_3 - sqrt(a) | ≤ 2**(e-18) -- general case with k = 9\n xn = (xn + a / xn) >> 1; // ε_4 := | x_4 - sqrt(a) | ≤ 2**(e-36) -- general case with k = 18\n xn = (xn + a / xn) >> 1; // ε_5 := | x_5 - sqrt(a) | ≤ 2**(e-72) -- general case with k = 36\n xn = (xn + a / xn) >> 1; // ε_6 := | x_6 - sqrt(a) | ≤ 2**(e-144) -- general case with k = 72\n\n // Because e ≤ 128 (as discussed during the first estimation phase), we know have reached a precision\n // ε_6 ≤ 2**(e-144) < 1. Given we're operating on integers, then we can ensure that xn is now either\n // sqrt(a) or sqrt(a) + 1.\n return xn - SafeCast.toUint(xn > a / xn);\n }\n }\n\n /**\n * @dev Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && result * result < a);\n }\n }\n\n /**\n * @dev Return the log in base 2 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log2(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // If upper 8 bits of 16-bit half set, add 8 to result\n r |= SafeCast.toUint((x >> r) > 0xff) << 3;\n // If upper 4 bits of 8-bit half set, add 4 to result\n r |= SafeCast.toUint((x >> r) > 0xf) << 2;\n\n // Shifts value right by the current result and use it as an index into this lookup table:\n //\n // | x (4 bits) | index | table[index] = MSB position |\n // |------------|---------|-----------------------------|\n // | 0000 | 0 | table[0] = 0 |\n // | 0001 | 1 | table[1] = 0 |\n // | 0010 | 2 | table[2] = 1 |\n // | 0011 | 3 | table[3] = 1 |\n // | 0100 | 4 | table[4] = 2 |\n // | 0101 | 5 | table[5] = 2 |\n // | 0110 | 6 | table[6] = 2 |\n // | 0111 | 7 | table[7] = 2 |\n // | 1000 | 8 | table[8] = 3 |\n // | 1001 | 9 | table[9] = 3 |\n // | 1010 | 10 | table[10] = 3 |\n // | 1011 | 11 | table[11] = 3 |\n // | 1100 | 12 | table[12] = 3 |\n // | 1101 | 13 | table[13] = 3 |\n // | 1110 | 14 | table[14] = 3 |\n // | 1111 | 15 | table[15] = 3 |\n //\n // The lookup table is represented as a 32-byte value with the MSB positions for 0-15 in the first 16 bytes (most significant half).\n assembly (\"memory-safe\") {\n r := or(r, byte(shr(r, x), 0x0000010102020202030303030303030300000000000000000000000000000000))\n }\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << result < value);\n }\n }\n\n /**\n * @dev Return the log in base 10 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10 ** 64) {\n value /= 10 ** 64;\n result += 64;\n }\n if (value >= 10 ** 32) {\n value /= 10 ** 32;\n result += 32;\n }\n if (value >= 10 ** 16) {\n value /= 10 ** 16;\n result += 16;\n }\n if (value >= 10 ** 8) {\n value /= 10 ** 8;\n result += 8;\n }\n if (value >= 10 ** 4) {\n value /= 10 ** 4;\n result += 4;\n }\n if (value >= 10 ** 2) {\n value /= 10 ** 2;\n result += 2;\n }\n if (value >= 10 ** 1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 10 ** result < value);\n }\n }\n\n /**\n * @dev Return the log in base 256 of a positive value rounded towards zero.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 x) internal pure returns (uint256 r) {\n // If value has upper 128 bits set, log2 result is at least 128\n r = SafeCast.toUint(x > 0xffffffffffffffffffffffffffffffff) << 7;\n // If upper 64 bits of 128-bit half set, add 64 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffffffffffff) << 6;\n // If upper 32 bits of 64-bit half set, add 32 to result\n r |= SafeCast.toUint((x >> r) > 0xffffffff) << 5;\n // If upper 16 bits of 32-bit half set, add 16 to result\n r |= SafeCast.toUint((x >> r) > 0xffff) << 4;\n // Add 1 if upper 8 bits of 16-bit half set, and divide accumulated result by 8\n return (r >> 3) | SafeCast.toUint((x >> r) > 0xff);\n }\n\n /**\n * @dev Return the log in base 256, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + SafeCast.toUint(unsignedRoundsUp(rounding) && 1 << (result << 3) < value);\n }\n }\n\n /**\n * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.\n */\n function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {\n return uint8(rounding) % 2 == 1;\n }\n\n /**\n * @dev Counts the number of leading zero bits in a uint256.\n */\n function clz(uint256 x) internal pure returns (uint256) {\n return ternary(x == 0, 256, 255 - log2(x));\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/SafeCast.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (utils/math/SafeCast.sol)\n// This file was procedurally generated from scripts/generate/templates/SafeCast.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeCast {\n /**\n * @dev Value doesn't fit in a uint of `bits` size.\n */\n error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);\n\n /**\n * @dev An int value doesn't fit in a uint of `bits` size.\n */\n error SafeCastOverflowedIntToUint(int256 value);\n\n /**\n * @dev Value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);\n\n /**\n * @dev A uint value doesn't fit in an int of `bits` size.\n */\n error SafeCastOverflowedUintToInt(uint256 value);\n\n /**\n * @dev Returns the downcasted uint248 from uint256, reverting on\n * overflow (when the input is greater than largest uint248).\n *\n * Counterpart to Solidity's `uint248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toUint248(uint256 value) internal pure returns (uint248) {\n if (value > type(uint248).max) {\n revert SafeCastOverflowedUintDowncast(248, value);\n }\n return uint248(value);\n }\n\n /**\n * @dev Returns the downcasted uint240 from uint256, reverting on\n * overflow (when the input is greater than largest uint240).\n *\n * Counterpart to Solidity's `uint240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toUint240(uint256 value) internal pure returns (uint240) {\n if (value > type(uint240).max) {\n revert SafeCastOverflowedUintDowncast(240, value);\n }\n return uint240(value);\n }\n\n /**\n * @dev Returns the downcasted uint232 from uint256, reverting on\n * overflow (when the input is greater than largest uint232).\n *\n * Counterpart to Solidity's `uint232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toUint232(uint256 value) internal pure returns (uint232) {\n if (value > type(uint232).max) {\n revert SafeCastOverflowedUintDowncast(232, value);\n }\n return uint232(value);\n }\n\n /**\n * @dev Returns the downcasted uint224 from uint256, reverting on\n * overflow (when the input is greater than largest uint224).\n *\n * Counterpart to Solidity's `uint224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toUint224(uint256 value) internal pure returns (uint224) {\n if (value > type(uint224).max) {\n revert SafeCastOverflowedUintDowncast(224, value);\n }\n return uint224(value);\n }\n\n /**\n * @dev Returns the downcasted uint216 from uint256, reverting on\n * overflow (when the input is greater than largest uint216).\n *\n * Counterpart to Solidity's `uint216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toUint216(uint256 value) internal pure returns (uint216) {\n if (value > type(uint216).max) {\n revert SafeCastOverflowedUintDowncast(216, value);\n }\n return uint216(value);\n }\n\n /**\n * @dev Returns the downcasted uint208 from uint256, reverting on\n * overflow (when the input is greater than largest uint208).\n *\n * Counterpart to Solidity's `uint208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toUint208(uint256 value) internal pure returns (uint208) {\n if (value > type(uint208).max) {\n revert SafeCastOverflowedUintDowncast(208, value);\n }\n return uint208(value);\n }\n\n /**\n * @dev Returns the downcasted uint200 from uint256, reverting on\n * overflow (when the input is greater than largest uint200).\n *\n * Counterpart to Solidity's `uint200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toUint200(uint256 value) internal pure returns (uint200) {\n if (value > type(uint200).max) {\n revert SafeCastOverflowedUintDowncast(200, value);\n }\n return uint200(value);\n }\n\n /**\n * @dev Returns the downcasted uint192 from uint256, reverting on\n * overflow (when the input is greater than largest uint192).\n *\n * Counterpart to Solidity's `uint192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toUint192(uint256 value) internal pure returns (uint192) {\n if (value > type(uint192).max) {\n revert SafeCastOverflowedUintDowncast(192, value);\n }\n return uint192(value);\n }\n\n /**\n * @dev Returns the downcasted uint184 from uint256, reverting on\n * overflow (when the input is greater than largest uint184).\n *\n * Counterpart to Solidity's `uint184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toUint184(uint256 value) internal pure returns (uint184) {\n if (value > type(uint184).max) {\n revert SafeCastOverflowedUintDowncast(184, value);\n }\n return uint184(value);\n }\n\n /**\n * @dev Returns the downcasted uint176 from uint256, reverting on\n * overflow (when the input is greater than largest uint176).\n *\n * Counterpart to Solidity's `uint176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toUint176(uint256 value) internal pure returns (uint176) {\n if (value > type(uint176).max) {\n revert SafeCastOverflowedUintDowncast(176, value);\n }\n return uint176(value);\n }\n\n /**\n * @dev Returns the downcasted uint168 from uint256, reverting on\n * overflow (when the input is greater than largest uint168).\n *\n * Counterpart to Solidity's `uint168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toUint168(uint256 value) internal pure returns (uint168) {\n if (value > type(uint168).max) {\n revert SafeCastOverflowedUintDowncast(168, value);\n }\n return uint168(value);\n }\n\n /**\n * @dev Returns the downcasted uint160 from uint256, reverting on\n * overflow (when the input is greater than largest uint160).\n *\n * Counterpart to Solidity's `uint160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toUint160(uint256 value) internal pure returns (uint160) {\n if (value > type(uint160).max) {\n revert SafeCastOverflowedUintDowncast(160, value);\n }\n return uint160(value);\n }\n\n /**\n * @dev Returns the downcasted uint152 from uint256, reverting on\n * overflow (when the input is greater than largest uint152).\n *\n * Counterpart to Solidity's `uint152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toUint152(uint256 value) internal pure returns (uint152) {\n if (value > type(uint152).max) {\n revert SafeCastOverflowedUintDowncast(152, value);\n }\n return uint152(value);\n }\n\n /**\n * @dev Returns the downcasted uint144 from uint256, reverting on\n * overflow (when the input is greater than largest uint144).\n *\n * Counterpart to Solidity's `uint144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toUint144(uint256 value) internal pure returns (uint144) {\n if (value > type(uint144).max) {\n revert SafeCastOverflowedUintDowncast(144, value);\n }\n return uint144(value);\n }\n\n /**\n * @dev Returns the downcasted uint136 from uint256, reverting on\n * overflow (when the input is greater than largest uint136).\n *\n * Counterpart to Solidity's `uint136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toUint136(uint256 value) internal pure returns (uint136) {\n if (value > type(uint136).max) {\n revert SafeCastOverflowedUintDowncast(136, value);\n }\n return uint136(value);\n }\n\n /**\n * @dev Returns the downcasted uint128 from uint256, reverting on\n * overflow (when the input is greater than largest uint128).\n *\n * Counterpart to Solidity's `uint128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toUint128(uint256 value) internal pure returns (uint128) {\n if (value > type(uint128).max) {\n revert SafeCastOverflowedUintDowncast(128, value);\n }\n return uint128(value);\n }\n\n /**\n * @dev Returns the downcasted uint120 from uint256, reverting on\n * overflow (when the input is greater than largest uint120).\n *\n * Counterpart to Solidity's `uint120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toUint120(uint256 value) internal pure returns (uint120) {\n if (value > type(uint120).max) {\n revert SafeCastOverflowedUintDowncast(120, value);\n }\n return uint120(value);\n }\n\n /**\n * @dev Returns the downcasted uint112 from uint256, reverting on\n * overflow (when the input is greater than largest uint112).\n *\n * Counterpart to Solidity's `uint112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toUint112(uint256 value) internal pure returns (uint112) {\n if (value > type(uint112).max) {\n revert SafeCastOverflowedUintDowncast(112, value);\n }\n return uint112(value);\n }\n\n /**\n * @dev Returns the downcasted uint104 from uint256, reverting on\n * overflow (when the input is greater than largest uint104).\n *\n * Counterpart to Solidity's `uint104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toUint104(uint256 value) internal pure returns (uint104) {\n if (value > type(uint104).max) {\n revert SafeCastOverflowedUintDowncast(104, value);\n }\n return uint104(value);\n }\n\n /**\n * @dev Returns the downcasted uint96 from uint256, reverting on\n * overflow (when the input is greater than largest uint96).\n *\n * Counterpart to Solidity's `uint96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toUint96(uint256 value) internal pure returns (uint96) {\n if (value > type(uint96).max) {\n revert SafeCastOverflowedUintDowncast(96, value);\n }\n return uint96(value);\n }\n\n /**\n * @dev Returns the downcasted uint88 from uint256, reverting on\n * overflow (when the input is greater than largest uint88).\n *\n * Counterpart to Solidity's `uint88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toUint88(uint256 value) internal pure returns (uint88) {\n if (value > type(uint88).max) {\n revert SafeCastOverflowedUintDowncast(88, value);\n }\n return uint88(value);\n }\n\n /**\n * @dev Returns the downcasted uint80 from uint256, reverting on\n * overflow (when the input is greater than largest uint80).\n *\n * Counterpart to Solidity's `uint80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toUint80(uint256 value) internal pure returns (uint80) {\n if (value > type(uint80).max) {\n revert SafeCastOverflowedUintDowncast(80, value);\n }\n return uint80(value);\n }\n\n /**\n * @dev Returns the downcasted uint72 from uint256, reverting on\n * overflow (when the input is greater than largest uint72).\n *\n * Counterpart to Solidity's `uint72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toUint72(uint256 value) internal pure returns (uint72) {\n if (value > type(uint72).max) {\n revert SafeCastOverflowedUintDowncast(72, value);\n }\n return uint72(value);\n }\n\n /**\n * @dev Returns the downcasted uint64 from uint256, reverting on\n * overflow (when the input is greater than largest uint64).\n *\n * Counterpart to Solidity's `uint64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toUint64(uint256 value) internal pure returns (uint64) {\n if (value > type(uint64).max) {\n revert SafeCastOverflowedUintDowncast(64, value);\n }\n return uint64(value);\n }\n\n /**\n * @dev Returns the downcasted uint56 from uint256, reverting on\n * overflow (when the input is greater than largest uint56).\n *\n * Counterpart to Solidity's `uint56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toUint56(uint256 value) internal pure returns (uint56) {\n if (value > type(uint56).max) {\n revert SafeCastOverflowedUintDowncast(56, value);\n }\n return uint56(value);\n }\n\n /**\n * @dev Returns the downcasted uint48 from uint256, reverting on\n * overflow (when the input is greater than largest uint48).\n *\n * Counterpart to Solidity's `uint48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toUint48(uint256 value) internal pure returns (uint48) {\n if (value > type(uint48).max) {\n revert SafeCastOverflowedUintDowncast(48, value);\n }\n return uint48(value);\n }\n\n /**\n * @dev Returns the downcasted uint40 from uint256, reverting on\n * overflow (when the input is greater than largest uint40).\n *\n * Counterpart to Solidity's `uint40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toUint40(uint256 value) internal pure returns (uint40) {\n if (value > type(uint40).max) {\n revert SafeCastOverflowedUintDowncast(40, value);\n }\n return uint40(value);\n }\n\n /**\n * @dev Returns the downcasted uint32 from uint256, reverting on\n * overflow (when the input is greater than largest uint32).\n *\n * Counterpart to Solidity's `uint32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toUint32(uint256 value) internal pure returns (uint32) {\n if (value > type(uint32).max) {\n revert SafeCastOverflowedUintDowncast(32, value);\n }\n return uint32(value);\n }\n\n /**\n * @dev Returns the downcasted uint24 from uint256, reverting on\n * overflow (when the input is greater than largest uint24).\n *\n * Counterpart to Solidity's `uint24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toUint24(uint256 value) internal pure returns (uint24) {\n if (value > type(uint24).max) {\n revert SafeCastOverflowedUintDowncast(24, value);\n }\n return uint24(value);\n }\n\n /**\n * @dev Returns the downcasted uint16 from uint256, reverting on\n * overflow (when the input is greater than largest uint16).\n *\n * Counterpart to Solidity's `uint16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toUint16(uint256 value) internal pure returns (uint16) {\n if (value > type(uint16).max) {\n revert SafeCastOverflowedUintDowncast(16, value);\n }\n return uint16(value);\n }\n\n /**\n * @dev Returns the downcasted uint8 from uint256, reverting on\n * overflow (when the input is greater than largest uint8).\n *\n * Counterpart to Solidity's `uint8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toUint8(uint256 value) internal pure returns (uint8) {\n if (value > type(uint8).max) {\n revert SafeCastOverflowedUintDowncast(8, value);\n }\n return uint8(value);\n }\n\n /**\n * @dev Converts a signed int256 into an unsigned uint256.\n *\n * Requirements:\n *\n * - input must be greater than or equal to 0.\n */\n function toUint256(int256 value) internal pure returns (uint256) {\n if (value < 0) {\n revert SafeCastOverflowedIntToUint(value);\n }\n return uint256(value);\n }\n\n /**\n * @dev Returns the downcasted int248 from int256, reverting on\n * overflow (when the input is less than smallest int248 or\n * greater than largest int248).\n *\n * Counterpart to Solidity's `int248` operator.\n *\n * Requirements:\n *\n * - input must fit into 248 bits\n */\n function toInt248(int256 value) internal pure returns (int248 downcasted) {\n downcasted = int248(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(248, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int240 from int256, reverting on\n * overflow (when the input is less than smallest int240 or\n * greater than largest int240).\n *\n * Counterpart to Solidity's `int240` operator.\n *\n * Requirements:\n *\n * - input must fit into 240 bits\n */\n function toInt240(int256 value) internal pure returns (int240 downcasted) {\n downcasted = int240(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(240, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int232 from int256, reverting on\n * overflow (when the input is less than smallest int232 or\n * greater than largest int232).\n *\n * Counterpart to Solidity's `int232` operator.\n *\n * Requirements:\n *\n * - input must fit into 232 bits\n */\n function toInt232(int256 value) internal pure returns (int232 downcasted) {\n downcasted = int232(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(232, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int224 from int256, reverting on\n * overflow (when the input is less than smallest int224 or\n * greater than largest int224).\n *\n * Counterpart to Solidity's `int224` operator.\n *\n * Requirements:\n *\n * - input must fit into 224 bits\n */\n function toInt224(int256 value) internal pure returns (int224 downcasted) {\n downcasted = int224(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(224, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int216 from int256, reverting on\n * overflow (when the input is less than smallest int216 or\n * greater than largest int216).\n *\n * Counterpart to Solidity's `int216` operator.\n *\n * Requirements:\n *\n * - input must fit into 216 bits\n */\n function toInt216(int256 value) internal pure returns (int216 downcasted) {\n downcasted = int216(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(216, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int208 from int256, reverting on\n * overflow (when the input is less than smallest int208 or\n * greater than largest int208).\n *\n * Counterpart to Solidity's `int208` operator.\n *\n * Requirements:\n *\n * - input must fit into 208 bits\n */\n function toInt208(int256 value) internal pure returns (int208 downcasted) {\n downcasted = int208(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(208, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int200 from int256, reverting on\n * overflow (when the input is less than smallest int200 or\n * greater than largest int200).\n *\n * Counterpart to Solidity's `int200` operator.\n *\n * Requirements:\n *\n * - input must fit into 200 bits\n */\n function toInt200(int256 value) internal pure returns (int200 downcasted) {\n downcasted = int200(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(200, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int192 from int256, reverting on\n * overflow (when the input is less than smallest int192 or\n * greater than largest int192).\n *\n * Counterpart to Solidity's `int192` operator.\n *\n * Requirements:\n *\n * - input must fit into 192 bits\n */\n function toInt192(int256 value) internal pure returns (int192 downcasted) {\n downcasted = int192(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(192, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int184 from int256, reverting on\n * overflow (when the input is less than smallest int184 or\n * greater than largest int184).\n *\n * Counterpart to Solidity's `int184` operator.\n *\n * Requirements:\n *\n * - input must fit into 184 bits\n */\n function toInt184(int256 value) internal pure returns (int184 downcasted) {\n downcasted = int184(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(184, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int176 from int256, reverting on\n * overflow (when the input is less than smallest int176 or\n * greater than largest int176).\n *\n * Counterpart to Solidity's `int176` operator.\n *\n * Requirements:\n *\n * - input must fit into 176 bits\n */\n function toInt176(int256 value) internal pure returns (int176 downcasted) {\n downcasted = int176(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(176, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int168 from int256, reverting on\n * overflow (when the input is less than smallest int168 or\n * greater than largest int168).\n *\n * Counterpart to Solidity's `int168` operator.\n *\n * Requirements:\n *\n * - input must fit into 168 bits\n */\n function toInt168(int256 value) internal pure returns (int168 downcasted) {\n downcasted = int168(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(168, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int160 from int256, reverting on\n * overflow (when the input is less than smallest int160 or\n * greater than largest int160).\n *\n * Counterpart to Solidity's `int160` operator.\n *\n * Requirements:\n *\n * - input must fit into 160 bits\n */\n function toInt160(int256 value) internal pure returns (int160 downcasted) {\n downcasted = int160(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(160, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int152 from int256, reverting on\n * overflow (when the input is less than smallest int152 or\n * greater than largest int152).\n *\n * Counterpart to Solidity's `int152` operator.\n *\n * Requirements:\n *\n * - input must fit into 152 bits\n */\n function toInt152(int256 value) internal pure returns (int152 downcasted) {\n downcasted = int152(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(152, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int144 from int256, reverting on\n * overflow (when the input is less than smallest int144 or\n * greater than largest int144).\n *\n * Counterpart to Solidity's `int144` operator.\n *\n * Requirements:\n *\n * - input must fit into 144 bits\n */\n function toInt144(int256 value) internal pure returns (int144 downcasted) {\n downcasted = int144(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(144, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int136 from int256, reverting on\n * overflow (when the input is less than smallest int136 or\n * greater than largest int136).\n *\n * Counterpart to Solidity's `int136` operator.\n *\n * Requirements:\n *\n * - input must fit into 136 bits\n */\n function toInt136(int256 value) internal pure returns (int136 downcasted) {\n downcasted = int136(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(136, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int128 from int256, reverting on\n * overflow (when the input is less than smallest int128 or\n * greater than largest int128).\n *\n * Counterpart to Solidity's `int128` operator.\n *\n * Requirements:\n *\n * - input must fit into 128 bits\n */\n function toInt128(int256 value) internal pure returns (int128 downcasted) {\n downcasted = int128(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(128, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int120 from int256, reverting on\n * overflow (when the input is less than smallest int120 or\n * greater than largest int120).\n *\n * Counterpart to Solidity's `int120` operator.\n *\n * Requirements:\n *\n * - input must fit into 120 bits\n */\n function toInt120(int256 value) internal pure returns (int120 downcasted) {\n downcasted = int120(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(120, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int112 from int256, reverting on\n * overflow (when the input is less than smallest int112 or\n * greater than largest int112).\n *\n * Counterpart to Solidity's `int112` operator.\n *\n * Requirements:\n *\n * - input must fit into 112 bits\n */\n function toInt112(int256 value) internal pure returns (int112 downcasted) {\n downcasted = int112(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(112, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int104 from int256, reverting on\n * overflow (when the input is less than smallest int104 or\n * greater than largest int104).\n *\n * Counterpart to Solidity's `int104` operator.\n *\n * Requirements:\n *\n * - input must fit into 104 bits\n */\n function toInt104(int256 value) internal pure returns (int104 downcasted) {\n downcasted = int104(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(104, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int96 from int256, reverting on\n * overflow (when the input is less than smallest int96 or\n * greater than largest int96).\n *\n * Counterpart to Solidity's `int96` operator.\n *\n * Requirements:\n *\n * - input must fit into 96 bits\n */\n function toInt96(int256 value) internal pure returns (int96 downcasted) {\n downcasted = int96(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(96, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int88 from int256, reverting on\n * overflow (when the input is less than smallest int88 or\n * greater than largest int88).\n *\n * Counterpart to Solidity's `int88` operator.\n *\n * Requirements:\n *\n * - input must fit into 88 bits\n */\n function toInt88(int256 value) internal pure returns (int88 downcasted) {\n downcasted = int88(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(88, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int80 from int256, reverting on\n * overflow (when the input is less than smallest int80 or\n * greater than largest int80).\n *\n * Counterpart to Solidity's `int80` operator.\n *\n * Requirements:\n *\n * - input must fit into 80 bits\n */\n function toInt80(int256 value) internal pure returns (int80 downcasted) {\n downcasted = int80(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(80, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int72 from int256, reverting on\n * overflow (when the input is less than smallest int72 or\n * greater than largest int72).\n *\n * Counterpart to Solidity's `int72` operator.\n *\n * Requirements:\n *\n * - input must fit into 72 bits\n */\n function toInt72(int256 value) internal pure returns (int72 downcasted) {\n downcasted = int72(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(72, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int64 from int256, reverting on\n * overflow (when the input is less than smallest int64 or\n * greater than largest int64).\n *\n * Counterpart to Solidity's `int64` operator.\n *\n * Requirements:\n *\n * - input must fit into 64 bits\n */\n function toInt64(int256 value) internal pure returns (int64 downcasted) {\n downcasted = int64(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(64, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int56 from int256, reverting on\n * overflow (when the input is less than smallest int56 or\n * greater than largest int56).\n *\n * Counterpart to Solidity's `int56` operator.\n *\n * Requirements:\n *\n * - input must fit into 56 bits\n */\n function toInt56(int256 value) internal pure returns (int56 downcasted) {\n downcasted = int56(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(56, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int48 from int256, reverting on\n * overflow (when the input is less than smallest int48 or\n * greater than largest int48).\n *\n * Counterpart to Solidity's `int48` operator.\n *\n * Requirements:\n *\n * - input must fit into 48 bits\n */\n function toInt48(int256 value) internal pure returns (int48 downcasted) {\n downcasted = int48(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(48, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int40 from int256, reverting on\n * overflow (when the input is less than smallest int40 or\n * greater than largest int40).\n *\n * Counterpart to Solidity's `int40` operator.\n *\n * Requirements:\n *\n * - input must fit into 40 bits\n */\n function toInt40(int256 value) internal pure returns (int40 downcasted) {\n downcasted = int40(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(40, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int32 from int256, reverting on\n * overflow (when the input is less than smallest int32 or\n * greater than largest int32).\n *\n * Counterpart to Solidity's `int32` operator.\n *\n * Requirements:\n *\n * - input must fit into 32 bits\n */\n function toInt32(int256 value) internal pure returns (int32 downcasted) {\n downcasted = int32(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(32, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int24 from int256, reverting on\n * overflow (when the input is less than smallest int24 or\n * greater than largest int24).\n *\n * Counterpart to Solidity's `int24` operator.\n *\n * Requirements:\n *\n * - input must fit into 24 bits\n */\n function toInt24(int256 value) internal pure returns (int24 downcasted) {\n downcasted = int24(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(24, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int16 from int256, reverting on\n * overflow (when the input is less than smallest int16 or\n * greater than largest int16).\n *\n * Counterpart to Solidity's `int16` operator.\n *\n * Requirements:\n *\n * - input must fit into 16 bits\n */\n function toInt16(int256 value) internal pure returns (int16 downcasted) {\n downcasted = int16(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(16, value);\n }\n }\n\n /**\n * @dev Returns the downcasted int8 from int256, reverting on\n * overflow (when the input is less than smallest int8 or\n * greater than largest int8).\n *\n * Counterpart to Solidity's `int8` operator.\n *\n * Requirements:\n *\n * - input must fit into 8 bits\n */\n function toInt8(int256 value) internal pure returns (int8 downcasted) {\n downcasted = int8(value);\n if (downcasted != value) {\n revert SafeCastOverflowedIntDowncast(8, value);\n }\n }\n\n /**\n * @dev Converts an unsigned uint256 into a signed int256.\n *\n * Requirements:\n *\n * - input must be less than or equal to maxInt256.\n */\n function toInt256(uint256 value) internal pure returns (int256) {\n // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n if (value > uint256(type(int256).max)) {\n revert SafeCastOverflowedUintToInt(value);\n }\n return int256(value);\n }\n\n /**\n * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.\n */\n function toUint(bool b) internal pure returns (uint256 u) {\n assembly (\"memory-safe\") {\n u := iszero(iszero(b))\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/math/SignedMath.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SignedMath.sol)\n\npragma solidity ^0.8.20;\n\nimport {SafeCast} from \"./SafeCast.sol\";\n\n/**\n * @dev Standard signed math utilities missing in the Solidity language.\n */\nlibrary SignedMath {\n /**\n * @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.\n *\n * IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.\n * However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute\n * one branch when needed, making this function more expensive.\n */\n function ternary(bool condition, int256 a, int256 b) internal pure returns (int256) {\n unchecked {\n // branchless ternary works because:\n // b ^ (a ^ b) == a\n // b ^ 0 == b\n return b ^ ((a ^ b) * int256(SafeCast.toUint(condition)));\n }\n }\n\n /**\n * @dev Returns the largest of two signed numbers.\n */\n function max(int256 a, int256 b) internal pure returns (int256) {\n return ternary(a > b, a, b);\n }\n\n /**\n * @dev Returns the smallest of two signed numbers.\n */\n function min(int256 a, int256 b) internal pure returns (int256) {\n return ternary(a < b, a, b);\n }\n\n /**\n * @dev Returns the average of two signed numbers without overflow.\n * The result is rounded towards zero.\n */\n function average(int256 a, int256 b) internal pure returns (int256) {\n // Formula from the book \"Hacker's Delight\"\n int256 x = (a & b) + ((a ^ b) >> 1);\n return x + (int256(uint256(x) >> 255) & (a ^ b));\n }\n\n /**\n * @dev Returns the absolute unsigned value of a signed value.\n */\n function abs(int256 n) internal pure returns (uint256) {\n unchecked {\n // Formula from the \"Bit Twiddling Hacks\" by Sean Eron Anderson.\n // Since `n` is a signed integer, the generated bytecode will use the SAR opcode to perform the right shift,\n // taking advantage of the most significant (or \"sign\" bit) in two's complement representation.\n // This opcode adds new most significant bits set to the value of the previous most significant bit. As a result,\n // the mask will either be `bytes32(0)` (if n is positive) or `~bytes32(0)` (if n is negative).\n int256 mask = n >> 255;\n\n // A `bytes32(0)` mask leaves the input unchanged, while a `~bytes32(0)` mask complements it.\n return uint256((n + mask) ^ mask);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Packing.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.2.0) (utils/Packing.sol)\n// This file was procedurally generated from scripts/generate/templates/Packing.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library packing and unpacking multiple values into bytesXX.\n *\n * Example usage:\n *\n * ```solidity\n * library MyPacker {\n * type MyType is bytes32;\n *\n * function _pack(address account, bytes4 selector, uint64 period) external pure returns (MyType) {\n * bytes12 subpack = Packing.pack_4_8(selector, bytes8(period));\n * bytes32 pack = Packing.pack_20_12(bytes20(account), subpack);\n * return MyType.wrap(pack);\n * }\n *\n * function _unpack(MyType self) external pure returns (address, bytes4, uint64) {\n * bytes32 pack = MyType.unwrap(self);\n * return (\n * address(Packing.extract_32_20(pack, 0)),\n * Packing.extract_32_4(pack, 20),\n * uint64(Packing.extract_32_8(pack, 24))\n * );\n * }\n * }\n * ```\n *\n * _Available since v5.1._\n */\n// solhint-disable func-name-mixedcase\nlibrary Packing {\n error OutOfRangeAccess();\n\n function pack_1_1(bytes1 left, bytes1 right) internal pure returns (bytes2 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(248, not(0)))\n right := and(right, shl(248, not(0)))\n result := or(left, shr(8, right))\n }\n }\n\n function pack_2_2(bytes2 left, bytes2 right) internal pure returns (bytes4 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(240, not(0)))\n right := and(right, shl(240, not(0)))\n result := or(left, shr(16, right))\n }\n }\n\n function pack_2_4(bytes2 left, bytes4 right) internal pure returns (bytes6 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(240, not(0)))\n right := and(right, shl(224, not(0)))\n result := or(left, shr(16, right))\n }\n }\n\n function pack_2_6(bytes2 left, bytes6 right) internal pure returns (bytes8 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(240, not(0)))\n right := and(right, shl(208, not(0)))\n result := or(left, shr(16, right))\n }\n }\n\n function pack_2_8(bytes2 left, bytes8 right) internal pure returns (bytes10 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(240, not(0)))\n right := and(right, shl(192, not(0)))\n result := or(left, shr(16, right))\n }\n }\n\n function pack_2_10(bytes2 left, bytes10 right) internal pure returns (bytes12 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(240, not(0)))\n right := and(right, shl(176, not(0)))\n result := or(left, shr(16, right))\n }\n }\n\n function pack_2_20(bytes2 left, bytes20 right) internal pure returns (bytes22 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(240, not(0)))\n right := and(right, shl(96, not(0)))\n result := or(left, shr(16, right))\n }\n }\n\n function pack_2_22(bytes2 left, bytes22 right) internal pure returns (bytes24 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(240, not(0)))\n right := and(right, shl(80, not(0)))\n result := or(left, shr(16, right))\n }\n }\n\n function pack_4_2(bytes4 left, bytes2 right) internal pure returns (bytes6 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(224, not(0)))\n right := and(right, shl(240, not(0)))\n result := or(left, shr(32, right))\n }\n }\n\n function pack_4_4(bytes4 left, bytes4 right) internal pure returns (bytes8 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(224, not(0)))\n right := and(right, shl(224, not(0)))\n result := or(left, shr(32, right))\n }\n }\n\n function pack_4_6(bytes4 left, bytes6 right) internal pure returns (bytes10 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(224, not(0)))\n right := and(right, shl(208, not(0)))\n result := or(left, shr(32, right))\n }\n }\n\n function pack_4_8(bytes4 left, bytes8 right) internal pure returns (bytes12 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(224, not(0)))\n right := and(right, shl(192, not(0)))\n result := or(left, shr(32, right))\n }\n }\n\n function pack_4_12(bytes4 left, bytes12 right) internal pure returns (bytes16 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(224, not(0)))\n right := and(right, shl(160, not(0)))\n result := or(left, shr(32, right))\n }\n }\n\n function pack_4_16(bytes4 left, bytes16 right) internal pure returns (bytes20 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(224, not(0)))\n right := and(right, shl(128, not(0)))\n result := or(left, shr(32, right))\n }\n }\n\n function pack_4_20(bytes4 left, bytes20 right) internal pure returns (bytes24 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(224, not(0)))\n right := and(right, shl(96, not(0)))\n result := or(left, shr(32, right))\n }\n }\n\n function pack_4_24(bytes4 left, bytes24 right) internal pure returns (bytes28 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(224, not(0)))\n right := and(right, shl(64, not(0)))\n result := or(left, shr(32, right))\n }\n }\n\n function pack_4_28(bytes4 left, bytes28 right) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(224, not(0)))\n right := and(right, shl(32, not(0)))\n result := or(left, shr(32, right))\n }\n }\n\n function pack_6_2(bytes6 left, bytes2 right) internal pure returns (bytes8 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(208, not(0)))\n right := and(right, shl(240, not(0)))\n result := or(left, shr(48, right))\n }\n }\n\n function pack_6_4(bytes6 left, bytes4 right) internal pure returns (bytes10 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(208, not(0)))\n right := and(right, shl(224, not(0)))\n result := or(left, shr(48, right))\n }\n }\n\n function pack_6_6(bytes6 left, bytes6 right) internal pure returns (bytes12 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(208, not(0)))\n right := and(right, shl(208, not(0)))\n result := or(left, shr(48, right))\n }\n }\n\n function pack_6_10(bytes6 left, bytes10 right) internal pure returns (bytes16 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(208, not(0)))\n right := and(right, shl(176, not(0)))\n result := or(left, shr(48, right))\n }\n }\n\n function pack_6_16(bytes6 left, bytes16 right) internal pure returns (bytes22 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(208, not(0)))\n right := and(right, shl(128, not(0)))\n result := or(left, shr(48, right))\n }\n }\n\n function pack_6_22(bytes6 left, bytes22 right) internal pure returns (bytes28 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(208, not(0)))\n right := and(right, shl(80, not(0)))\n result := or(left, shr(48, right))\n }\n }\n\n function pack_8_2(bytes8 left, bytes2 right) internal pure returns (bytes10 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(192, not(0)))\n right := and(right, shl(240, not(0)))\n result := or(left, shr(64, right))\n }\n }\n\n function pack_8_4(bytes8 left, bytes4 right) internal pure returns (bytes12 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(192, not(0)))\n right := and(right, shl(224, not(0)))\n result := or(left, shr(64, right))\n }\n }\n\n function pack_8_8(bytes8 left, bytes8 right) internal pure returns (bytes16 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(192, not(0)))\n right := and(right, shl(192, not(0)))\n result := or(left, shr(64, right))\n }\n }\n\n function pack_8_12(bytes8 left, bytes12 right) internal pure returns (bytes20 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(192, not(0)))\n right := and(right, shl(160, not(0)))\n result := or(left, shr(64, right))\n }\n }\n\n function pack_8_16(bytes8 left, bytes16 right) internal pure returns (bytes24 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(192, not(0)))\n right := and(right, shl(128, not(0)))\n result := or(left, shr(64, right))\n }\n }\n\n function pack_8_20(bytes8 left, bytes20 right) internal pure returns (bytes28 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(192, not(0)))\n right := and(right, shl(96, not(0)))\n result := or(left, shr(64, right))\n }\n }\n\n function pack_8_24(bytes8 left, bytes24 right) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(192, not(0)))\n right := and(right, shl(64, not(0)))\n result := or(left, shr(64, right))\n }\n }\n\n function pack_10_2(bytes10 left, bytes2 right) internal pure returns (bytes12 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(176, not(0)))\n right := and(right, shl(240, not(0)))\n result := or(left, shr(80, right))\n }\n }\n\n function pack_10_6(bytes10 left, bytes6 right) internal pure returns (bytes16 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(176, not(0)))\n right := and(right, shl(208, not(0)))\n result := or(left, shr(80, right))\n }\n }\n\n function pack_10_10(bytes10 left, bytes10 right) internal pure returns (bytes20 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(176, not(0)))\n right := and(right, shl(176, not(0)))\n result := or(left, shr(80, right))\n }\n }\n\n function pack_10_12(bytes10 left, bytes12 right) internal pure returns (bytes22 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(176, not(0)))\n right := and(right, shl(160, not(0)))\n result := or(left, shr(80, right))\n }\n }\n\n function pack_10_22(bytes10 left, bytes22 right) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(176, not(0)))\n right := and(right, shl(80, not(0)))\n result := or(left, shr(80, right))\n }\n }\n\n function pack_12_4(bytes12 left, bytes4 right) internal pure returns (bytes16 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(160, not(0)))\n right := and(right, shl(224, not(0)))\n result := or(left, shr(96, right))\n }\n }\n\n function pack_12_8(bytes12 left, bytes8 right) internal pure returns (bytes20 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(160, not(0)))\n right := and(right, shl(192, not(0)))\n result := or(left, shr(96, right))\n }\n }\n\n function pack_12_10(bytes12 left, bytes10 right) internal pure returns (bytes22 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(160, not(0)))\n right := and(right, shl(176, not(0)))\n result := or(left, shr(96, right))\n }\n }\n\n function pack_12_12(bytes12 left, bytes12 right) internal pure returns (bytes24 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(160, not(0)))\n right := and(right, shl(160, not(0)))\n result := or(left, shr(96, right))\n }\n }\n\n function pack_12_16(bytes12 left, bytes16 right) internal pure returns (bytes28 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(160, not(0)))\n right := and(right, shl(128, not(0)))\n result := or(left, shr(96, right))\n }\n }\n\n function pack_12_20(bytes12 left, bytes20 right) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(160, not(0)))\n right := and(right, shl(96, not(0)))\n result := or(left, shr(96, right))\n }\n }\n\n function pack_16_4(bytes16 left, bytes4 right) internal pure returns (bytes20 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(128, not(0)))\n right := and(right, shl(224, not(0)))\n result := or(left, shr(128, right))\n }\n }\n\n function pack_16_6(bytes16 left, bytes6 right) internal pure returns (bytes22 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(128, not(0)))\n right := and(right, shl(208, not(0)))\n result := or(left, shr(128, right))\n }\n }\n\n function pack_16_8(bytes16 left, bytes8 right) internal pure returns (bytes24 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(128, not(0)))\n right := and(right, shl(192, not(0)))\n result := or(left, shr(128, right))\n }\n }\n\n function pack_16_12(bytes16 left, bytes12 right) internal pure returns (bytes28 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(128, not(0)))\n right := and(right, shl(160, not(0)))\n result := or(left, shr(128, right))\n }\n }\n\n function pack_16_16(bytes16 left, bytes16 right) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(128, not(0)))\n right := and(right, shl(128, not(0)))\n result := or(left, shr(128, right))\n }\n }\n\n function pack_20_2(bytes20 left, bytes2 right) internal pure returns (bytes22 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(96, not(0)))\n right := and(right, shl(240, not(0)))\n result := or(left, shr(160, right))\n }\n }\n\n function pack_20_4(bytes20 left, bytes4 right) internal pure returns (bytes24 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(96, not(0)))\n right := and(right, shl(224, not(0)))\n result := or(left, shr(160, right))\n }\n }\n\n function pack_20_8(bytes20 left, bytes8 right) internal pure returns (bytes28 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(96, not(0)))\n right := and(right, shl(192, not(0)))\n result := or(left, shr(160, right))\n }\n }\n\n function pack_20_12(bytes20 left, bytes12 right) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(96, not(0)))\n right := and(right, shl(160, not(0)))\n result := or(left, shr(160, right))\n }\n }\n\n function pack_22_2(bytes22 left, bytes2 right) internal pure returns (bytes24 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(80, not(0)))\n right := and(right, shl(240, not(0)))\n result := or(left, shr(176, right))\n }\n }\n\n function pack_22_6(bytes22 left, bytes6 right) internal pure returns (bytes28 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(80, not(0)))\n right := and(right, shl(208, not(0)))\n result := or(left, shr(176, right))\n }\n }\n\n function pack_22_10(bytes22 left, bytes10 right) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(80, not(0)))\n right := and(right, shl(176, not(0)))\n result := or(left, shr(176, right))\n }\n }\n\n function pack_24_4(bytes24 left, bytes4 right) internal pure returns (bytes28 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(64, not(0)))\n right := and(right, shl(224, not(0)))\n result := or(left, shr(192, right))\n }\n }\n\n function pack_24_8(bytes24 left, bytes8 right) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(64, not(0)))\n right := and(right, shl(192, not(0)))\n result := or(left, shr(192, right))\n }\n }\n\n function pack_28_4(bytes28 left, bytes4 right) internal pure returns (bytes32 result) {\n assembly (\"memory-safe\") {\n left := and(left, shl(32, not(0)))\n right := and(right, shl(224, not(0)))\n result := or(left, shr(224, right))\n }\n }\n\n function extract_2_1(bytes2 self, uint8 offset) internal pure returns (bytes1 result) {\n if (offset > 1) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(248, not(0)))\n }\n }\n\n function replace_2_1(bytes2 self, bytes1 value, uint8 offset) internal pure returns (bytes2 result) {\n bytes1 oldValue = extract_2_1(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(248, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_4_1(bytes4 self, uint8 offset) internal pure returns (bytes1 result) {\n if (offset > 3) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(248, not(0)))\n }\n }\n\n function replace_4_1(bytes4 self, bytes1 value, uint8 offset) internal pure returns (bytes4 result) {\n bytes1 oldValue = extract_4_1(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(248, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_4_2(bytes4 self, uint8 offset) internal pure returns (bytes2 result) {\n if (offset > 2) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(240, not(0)))\n }\n }\n\n function replace_4_2(bytes4 self, bytes2 value, uint8 offset) internal pure returns (bytes4 result) {\n bytes2 oldValue = extract_4_2(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(240, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_6_1(bytes6 self, uint8 offset) internal pure returns (bytes1 result) {\n if (offset > 5) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(248, not(0)))\n }\n }\n\n function replace_6_1(bytes6 self, bytes1 value, uint8 offset) internal pure returns (bytes6 result) {\n bytes1 oldValue = extract_6_1(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(248, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_6_2(bytes6 self, uint8 offset) internal pure returns (bytes2 result) {\n if (offset > 4) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(240, not(0)))\n }\n }\n\n function replace_6_2(bytes6 self, bytes2 value, uint8 offset) internal pure returns (bytes6 result) {\n bytes2 oldValue = extract_6_2(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(240, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_6_4(bytes6 self, uint8 offset) internal pure returns (bytes4 result) {\n if (offset > 2) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(224, not(0)))\n }\n }\n\n function replace_6_4(bytes6 self, bytes4 value, uint8 offset) internal pure returns (bytes6 result) {\n bytes4 oldValue = extract_6_4(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(224, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_8_1(bytes8 self, uint8 offset) internal pure returns (bytes1 result) {\n if (offset > 7) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(248, not(0)))\n }\n }\n\n function replace_8_1(bytes8 self, bytes1 value, uint8 offset) internal pure returns (bytes8 result) {\n bytes1 oldValue = extract_8_1(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(248, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_8_2(bytes8 self, uint8 offset) internal pure returns (bytes2 result) {\n if (offset > 6) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(240, not(0)))\n }\n }\n\n function replace_8_2(bytes8 self, bytes2 value, uint8 offset) internal pure returns (bytes8 result) {\n bytes2 oldValue = extract_8_2(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(240, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_8_4(bytes8 self, uint8 offset) internal pure returns (bytes4 result) {\n if (offset > 4) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(224, not(0)))\n }\n }\n\n function replace_8_4(bytes8 self, bytes4 value, uint8 offset) internal pure returns (bytes8 result) {\n bytes4 oldValue = extract_8_4(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(224, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_8_6(bytes8 self, uint8 offset) internal pure returns (bytes6 result) {\n if (offset > 2) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(208, not(0)))\n }\n }\n\n function replace_8_6(bytes8 self, bytes6 value, uint8 offset) internal pure returns (bytes8 result) {\n bytes6 oldValue = extract_8_6(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(208, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_10_1(bytes10 self, uint8 offset) internal pure returns (bytes1 result) {\n if (offset > 9) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(248, not(0)))\n }\n }\n\n function replace_10_1(bytes10 self, bytes1 value, uint8 offset) internal pure returns (bytes10 result) {\n bytes1 oldValue = extract_10_1(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(248, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_10_2(bytes10 self, uint8 offset) internal pure returns (bytes2 result) {\n if (offset > 8) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(240, not(0)))\n }\n }\n\n function replace_10_2(bytes10 self, bytes2 value, uint8 offset) internal pure returns (bytes10 result) {\n bytes2 oldValue = extract_10_2(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(240, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_10_4(bytes10 self, uint8 offset) internal pure returns (bytes4 result) {\n if (offset > 6) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(224, not(0)))\n }\n }\n\n function replace_10_4(bytes10 self, bytes4 value, uint8 offset) internal pure returns (bytes10 result) {\n bytes4 oldValue = extract_10_4(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(224, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_10_6(bytes10 self, uint8 offset) internal pure returns (bytes6 result) {\n if (offset > 4) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(208, not(0)))\n }\n }\n\n function replace_10_6(bytes10 self, bytes6 value, uint8 offset) internal pure returns (bytes10 result) {\n bytes6 oldValue = extract_10_6(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(208, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_10_8(bytes10 self, uint8 offset) internal pure returns (bytes8 result) {\n if (offset > 2) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(192, not(0)))\n }\n }\n\n function replace_10_8(bytes10 self, bytes8 value, uint8 offset) internal pure returns (bytes10 result) {\n bytes8 oldValue = extract_10_8(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(192, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_12_1(bytes12 self, uint8 offset) internal pure returns (bytes1 result) {\n if (offset > 11) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(248, not(0)))\n }\n }\n\n function replace_12_1(bytes12 self, bytes1 value, uint8 offset) internal pure returns (bytes12 result) {\n bytes1 oldValue = extract_12_1(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(248, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_12_2(bytes12 self, uint8 offset) internal pure returns (bytes2 result) {\n if (offset > 10) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(240, not(0)))\n }\n }\n\n function replace_12_2(bytes12 self, bytes2 value, uint8 offset) internal pure returns (bytes12 result) {\n bytes2 oldValue = extract_12_2(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(240, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_12_4(bytes12 self, uint8 offset) internal pure returns (bytes4 result) {\n if (offset > 8) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(224, not(0)))\n }\n }\n\n function replace_12_4(bytes12 self, bytes4 value, uint8 offset) internal pure returns (bytes12 result) {\n bytes4 oldValue = extract_12_4(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(224, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_12_6(bytes12 self, uint8 offset) internal pure returns (bytes6 result) {\n if (offset > 6) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(208, not(0)))\n }\n }\n\n function replace_12_6(bytes12 self, bytes6 value, uint8 offset) internal pure returns (bytes12 result) {\n bytes6 oldValue = extract_12_6(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(208, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_12_8(bytes12 self, uint8 offset) internal pure returns (bytes8 result) {\n if (offset > 4) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(192, not(0)))\n }\n }\n\n function replace_12_8(bytes12 self, bytes8 value, uint8 offset) internal pure returns (bytes12 result) {\n bytes8 oldValue = extract_12_8(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(192, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_12_10(bytes12 self, uint8 offset) internal pure returns (bytes10 result) {\n if (offset > 2) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(176, not(0)))\n }\n }\n\n function replace_12_10(bytes12 self, bytes10 value, uint8 offset) internal pure returns (bytes12 result) {\n bytes10 oldValue = extract_12_10(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(176, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_16_1(bytes16 self, uint8 offset) internal pure returns (bytes1 result) {\n if (offset > 15) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(248, not(0)))\n }\n }\n\n function replace_16_1(bytes16 self, bytes1 value, uint8 offset) internal pure returns (bytes16 result) {\n bytes1 oldValue = extract_16_1(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(248, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_16_2(bytes16 self, uint8 offset) internal pure returns (bytes2 result) {\n if (offset > 14) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(240, not(0)))\n }\n }\n\n function replace_16_2(bytes16 self, bytes2 value, uint8 offset) internal pure returns (bytes16 result) {\n bytes2 oldValue = extract_16_2(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(240, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_16_4(bytes16 self, uint8 offset) internal pure returns (bytes4 result) {\n if (offset > 12) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(224, not(0)))\n }\n }\n\n function replace_16_4(bytes16 self, bytes4 value, uint8 offset) internal pure returns (bytes16 result) {\n bytes4 oldValue = extract_16_4(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(224, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_16_6(bytes16 self, uint8 offset) internal pure returns (bytes6 result) {\n if (offset > 10) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(208, not(0)))\n }\n }\n\n function replace_16_6(bytes16 self, bytes6 value, uint8 offset) internal pure returns (bytes16 result) {\n bytes6 oldValue = extract_16_6(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(208, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_16_8(bytes16 self, uint8 offset) internal pure returns (bytes8 result) {\n if (offset > 8) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(192, not(0)))\n }\n }\n\n function replace_16_8(bytes16 self, bytes8 value, uint8 offset) internal pure returns (bytes16 result) {\n bytes8 oldValue = extract_16_8(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(192, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_16_10(bytes16 self, uint8 offset) internal pure returns (bytes10 result) {\n if (offset > 6) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(176, not(0)))\n }\n }\n\n function replace_16_10(bytes16 self, bytes10 value, uint8 offset) internal pure returns (bytes16 result) {\n bytes10 oldValue = extract_16_10(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(176, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_16_12(bytes16 self, uint8 offset) internal pure returns (bytes12 result) {\n if (offset > 4) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(160, not(0)))\n }\n }\n\n function replace_16_12(bytes16 self, bytes12 value, uint8 offset) internal pure returns (bytes16 result) {\n bytes12 oldValue = extract_16_12(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(160, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_20_1(bytes20 self, uint8 offset) internal pure returns (bytes1 result) {\n if (offset > 19) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(248, not(0)))\n }\n }\n\n function replace_20_1(bytes20 self, bytes1 value, uint8 offset) internal pure returns (bytes20 result) {\n bytes1 oldValue = extract_20_1(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(248, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_20_2(bytes20 self, uint8 offset) internal pure returns (bytes2 result) {\n if (offset > 18) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(240, not(0)))\n }\n }\n\n function replace_20_2(bytes20 self, bytes2 value, uint8 offset) internal pure returns (bytes20 result) {\n bytes2 oldValue = extract_20_2(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(240, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_20_4(bytes20 self, uint8 offset) internal pure returns (bytes4 result) {\n if (offset > 16) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(224, not(0)))\n }\n }\n\n function replace_20_4(bytes20 self, bytes4 value, uint8 offset) internal pure returns (bytes20 result) {\n bytes4 oldValue = extract_20_4(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(224, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_20_6(bytes20 self, uint8 offset) internal pure returns (bytes6 result) {\n if (offset > 14) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(208, not(0)))\n }\n }\n\n function replace_20_6(bytes20 self, bytes6 value, uint8 offset) internal pure returns (bytes20 result) {\n bytes6 oldValue = extract_20_6(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(208, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_20_8(bytes20 self, uint8 offset) internal pure returns (bytes8 result) {\n if (offset > 12) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(192, not(0)))\n }\n }\n\n function replace_20_8(bytes20 self, bytes8 value, uint8 offset) internal pure returns (bytes20 result) {\n bytes8 oldValue = extract_20_8(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(192, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_20_10(bytes20 self, uint8 offset) internal pure returns (bytes10 result) {\n if (offset > 10) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(176, not(0)))\n }\n }\n\n function replace_20_10(bytes20 self, bytes10 value, uint8 offset) internal pure returns (bytes20 result) {\n bytes10 oldValue = extract_20_10(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(176, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_20_12(bytes20 self, uint8 offset) internal pure returns (bytes12 result) {\n if (offset > 8) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(160, not(0)))\n }\n }\n\n function replace_20_12(bytes20 self, bytes12 value, uint8 offset) internal pure returns (bytes20 result) {\n bytes12 oldValue = extract_20_12(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(160, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_20_16(bytes20 self, uint8 offset) internal pure returns (bytes16 result) {\n if (offset > 4) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(128, not(0)))\n }\n }\n\n function replace_20_16(bytes20 self, bytes16 value, uint8 offset) internal pure returns (bytes20 result) {\n bytes16 oldValue = extract_20_16(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(128, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_22_1(bytes22 self, uint8 offset) internal pure returns (bytes1 result) {\n if (offset > 21) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(248, not(0)))\n }\n }\n\n function replace_22_1(bytes22 self, bytes1 value, uint8 offset) internal pure returns (bytes22 result) {\n bytes1 oldValue = extract_22_1(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(248, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_22_2(bytes22 self, uint8 offset) internal pure returns (bytes2 result) {\n if (offset > 20) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(240, not(0)))\n }\n }\n\n function replace_22_2(bytes22 self, bytes2 value, uint8 offset) internal pure returns (bytes22 result) {\n bytes2 oldValue = extract_22_2(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(240, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_22_4(bytes22 self, uint8 offset) internal pure returns (bytes4 result) {\n if (offset > 18) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(224, not(0)))\n }\n }\n\n function replace_22_4(bytes22 self, bytes4 value, uint8 offset) internal pure returns (bytes22 result) {\n bytes4 oldValue = extract_22_4(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(224, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_22_6(bytes22 self, uint8 offset) internal pure returns (bytes6 result) {\n if (offset > 16) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(208, not(0)))\n }\n }\n\n function replace_22_6(bytes22 self, bytes6 value, uint8 offset) internal pure returns (bytes22 result) {\n bytes6 oldValue = extract_22_6(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(208, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_22_8(bytes22 self, uint8 offset) internal pure returns (bytes8 result) {\n if (offset > 14) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(192, not(0)))\n }\n }\n\n function replace_22_8(bytes22 self, bytes8 value, uint8 offset) internal pure returns (bytes22 result) {\n bytes8 oldValue = extract_22_8(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(192, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_22_10(bytes22 self, uint8 offset) internal pure returns (bytes10 result) {\n if (offset > 12) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(176, not(0)))\n }\n }\n\n function replace_22_10(bytes22 self, bytes10 value, uint8 offset) internal pure returns (bytes22 result) {\n bytes10 oldValue = extract_22_10(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(176, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_22_12(bytes22 self, uint8 offset) internal pure returns (bytes12 result) {\n if (offset > 10) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(160, not(0)))\n }\n }\n\n function replace_22_12(bytes22 self, bytes12 value, uint8 offset) internal pure returns (bytes22 result) {\n bytes12 oldValue = extract_22_12(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(160, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_22_16(bytes22 self, uint8 offset) internal pure returns (bytes16 result) {\n if (offset > 6) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(128, not(0)))\n }\n }\n\n function replace_22_16(bytes22 self, bytes16 value, uint8 offset) internal pure returns (bytes22 result) {\n bytes16 oldValue = extract_22_16(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(128, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_22_20(bytes22 self, uint8 offset) internal pure returns (bytes20 result) {\n if (offset > 2) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(96, not(0)))\n }\n }\n\n function replace_22_20(bytes22 self, bytes20 value, uint8 offset) internal pure returns (bytes22 result) {\n bytes20 oldValue = extract_22_20(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(96, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_24_1(bytes24 self, uint8 offset) internal pure returns (bytes1 result) {\n if (offset > 23) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(248, not(0)))\n }\n }\n\n function replace_24_1(bytes24 self, bytes1 value, uint8 offset) internal pure returns (bytes24 result) {\n bytes1 oldValue = extract_24_1(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(248, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_24_2(bytes24 self, uint8 offset) internal pure returns (bytes2 result) {\n if (offset > 22) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(240, not(0)))\n }\n }\n\n function replace_24_2(bytes24 self, bytes2 value, uint8 offset) internal pure returns (bytes24 result) {\n bytes2 oldValue = extract_24_2(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(240, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_24_4(bytes24 self, uint8 offset) internal pure returns (bytes4 result) {\n if (offset > 20) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(224, not(0)))\n }\n }\n\n function replace_24_4(bytes24 self, bytes4 value, uint8 offset) internal pure returns (bytes24 result) {\n bytes4 oldValue = extract_24_4(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(224, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_24_6(bytes24 self, uint8 offset) internal pure returns (bytes6 result) {\n if (offset > 18) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(208, not(0)))\n }\n }\n\n function replace_24_6(bytes24 self, bytes6 value, uint8 offset) internal pure returns (bytes24 result) {\n bytes6 oldValue = extract_24_6(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(208, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_24_8(bytes24 self, uint8 offset) internal pure returns (bytes8 result) {\n if (offset > 16) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(192, not(0)))\n }\n }\n\n function replace_24_8(bytes24 self, bytes8 value, uint8 offset) internal pure returns (bytes24 result) {\n bytes8 oldValue = extract_24_8(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(192, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_24_10(bytes24 self, uint8 offset) internal pure returns (bytes10 result) {\n if (offset > 14) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(176, not(0)))\n }\n }\n\n function replace_24_10(bytes24 self, bytes10 value, uint8 offset) internal pure returns (bytes24 result) {\n bytes10 oldValue = extract_24_10(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(176, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_24_12(bytes24 self, uint8 offset) internal pure returns (bytes12 result) {\n if (offset > 12) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(160, not(0)))\n }\n }\n\n function replace_24_12(bytes24 self, bytes12 value, uint8 offset) internal pure returns (bytes24 result) {\n bytes12 oldValue = extract_24_12(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(160, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_24_16(bytes24 self, uint8 offset) internal pure returns (bytes16 result) {\n if (offset > 8) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(128, not(0)))\n }\n }\n\n function replace_24_16(bytes24 self, bytes16 value, uint8 offset) internal pure returns (bytes24 result) {\n bytes16 oldValue = extract_24_16(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(128, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_24_20(bytes24 self, uint8 offset) internal pure returns (bytes20 result) {\n if (offset > 4) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(96, not(0)))\n }\n }\n\n function replace_24_20(bytes24 self, bytes20 value, uint8 offset) internal pure returns (bytes24 result) {\n bytes20 oldValue = extract_24_20(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(96, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_24_22(bytes24 self, uint8 offset) internal pure returns (bytes22 result) {\n if (offset > 2) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(80, not(0)))\n }\n }\n\n function replace_24_22(bytes24 self, bytes22 value, uint8 offset) internal pure returns (bytes24 result) {\n bytes22 oldValue = extract_24_22(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(80, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_28_1(bytes28 self, uint8 offset) internal pure returns (bytes1 result) {\n if (offset > 27) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(248, not(0)))\n }\n }\n\n function replace_28_1(bytes28 self, bytes1 value, uint8 offset) internal pure returns (bytes28 result) {\n bytes1 oldValue = extract_28_1(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(248, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_28_2(bytes28 self, uint8 offset) internal pure returns (bytes2 result) {\n if (offset > 26) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(240, not(0)))\n }\n }\n\n function replace_28_2(bytes28 self, bytes2 value, uint8 offset) internal pure returns (bytes28 result) {\n bytes2 oldValue = extract_28_2(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(240, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_28_4(bytes28 self, uint8 offset) internal pure returns (bytes4 result) {\n if (offset > 24) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(224, not(0)))\n }\n }\n\n function replace_28_4(bytes28 self, bytes4 value, uint8 offset) internal pure returns (bytes28 result) {\n bytes4 oldValue = extract_28_4(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(224, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_28_6(bytes28 self, uint8 offset) internal pure returns (bytes6 result) {\n if (offset > 22) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(208, not(0)))\n }\n }\n\n function replace_28_6(bytes28 self, bytes6 value, uint8 offset) internal pure returns (bytes28 result) {\n bytes6 oldValue = extract_28_6(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(208, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_28_8(bytes28 self, uint8 offset) internal pure returns (bytes8 result) {\n if (offset > 20) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(192, not(0)))\n }\n }\n\n function replace_28_8(bytes28 self, bytes8 value, uint8 offset) internal pure returns (bytes28 result) {\n bytes8 oldValue = extract_28_8(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(192, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_28_10(bytes28 self, uint8 offset) internal pure returns (bytes10 result) {\n if (offset > 18) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(176, not(0)))\n }\n }\n\n function replace_28_10(bytes28 self, bytes10 value, uint8 offset) internal pure returns (bytes28 result) {\n bytes10 oldValue = extract_28_10(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(176, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_28_12(bytes28 self, uint8 offset) internal pure returns (bytes12 result) {\n if (offset > 16) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(160, not(0)))\n }\n }\n\n function replace_28_12(bytes28 self, bytes12 value, uint8 offset) internal pure returns (bytes28 result) {\n bytes12 oldValue = extract_28_12(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(160, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_28_16(bytes28 self, uint8 offset) internal pure returns (bytes16 result) {\n if (offset > 12) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(128, not(0)))\n }\n }\n\n function replace_28_16(bytes28 self, bytes16 value, uint8 offset) internal pure returns (bytes28 result) {\n bytes16 oldValue = extract_28_16(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(128, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_28_20(bytes28 self, uint8 offset) internal pure returns (bytes20 result) {\n if (offset > 8) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(96, not(0)))\n }\n }\n\n function replace_28_20(bytes28 self, bytes20 value, uint8 offset) internal pure returns (bytes28 result) {\n bytes20 oldValue = extract_28_20(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(96, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_28_22(bytes28 self, uint8 offset) internal pure returns (bytes22 result) {\n if (offset > 6) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(80, not(0)))\n }\n }\n\n function replace_28_22(bytes28 self, bytes22 value, uint8 offset) internal pure returns (bytes28 result) {\n bytes22 oldValue = extract_28_22(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(80, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_28_24(bytes28 self, uint8 offset) internal pure returns (bytes24 result) {\n if (offset > 4) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(64, not(0)))\n }\n }\n\n function replace_28_24(bytes28 self, bytes24 value, uint8 offset) internal pure returns (bytes28 result) {\n bytes24 oldValue = extract_28_24(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(64, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_32_1(bytes32 self, uint8 offset) internal pure returns (bytes1 result) {\n if (offset > 31) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(248, not(0)))\n }\n }\n\n function replace_32_1(bytes32 self, bytes1 value, uint8 offset) internal pure returns (bytes32 result) {\n bytes1 oldValue = extract_32_1(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(248, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_32_2(bytes32 self, uint8 offset) internal pure returns (bytes2 result) {\n if (offset > 30) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(240, not(0)))\n }\n }\n\n function replace_32_2(bytes32 self, bytes2 value, uint8 offset) internal pure returns (bytes32 result) {\n bytes2 oldValue = extract_32_2(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(240, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_32_4(bytes32 self, uint8 offset) internal pure returns (bytes4 result) {\n if (offset > 28) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(224, not(0)))\n }\n }\n\n function replace_32_4(bytes32 self, bytes4 value, uint8 offset) internal pure returns (bytes32 result) {\n bytes4 oldValue = extract_32_4(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(224, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_32_6(bytes32 self, uint8 offset) internal pure returns (bytes6 result) {\n if (offset > 26) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(208, not(0)))\n }\n }\n\n function replace_32_6(bytes32 self, bytes6 value, uint8 offset) internal pure returns (bytes32 result) {\n bytes6 oldValue = extract_32_6(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(208, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_32_8(bytes32 self, uint8 offset) internal pure returns (bytes8 result) {\n if (offset > 24) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(192, not(0)))\n }\n }\n\n function replace_32_8(bytes32 self, bytes8 value, uint8 offset) internal pure returns (bytes32 result) {\n bytes8 oldValue = extract_32_8(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(192, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_32_10(bytes32 self, uint8 offset) internal pure returns (bytes10 result) {\n if (offset > 22) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(176, not(0)))\n }\n }\n\n function replace_32_10(bytes32 self, bytes10 value, uint8 offset) internal pure returns (bytes32 result) {\n bytes10 oldValue = extract_32_10(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(176, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_32_12(bytes32 self, uint8 offset) internal pure returns (bytes12 result) {\n if (offset > 20) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(160, not(0)))\n }\n }\n\n function replace_32_12(bytes32 self, bytes12 value, uint8 offset) internal pure returns (bytes32 result) {\n bytes12 oldValue = extract_32_12(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(160, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_32_16(bytes32 self, uint8 offset) internal pure returns (bytes16 result) {\n if (offset > 16) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(128, not(0)))\n }\n }\n\n function replace_32_16(bytes32 self, bytes16 value, uint8 offset) internal pure returns (bytes32 result) {\n bytes16 oldValue = extract_32_16(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(128, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_32_20(bytes32 self, uint8 offset) internal pure returns (bytes20 result) {\n if (offset > 12) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(96, not(0)))\n }\n }\n\n function replace_32_20(bytes32 self, bytes20 value, uint8 offset) internal pure returns (bytes32 result) {\n bytes20 oldValue = extract_32_20(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(96, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_32_22(bytes32 self, uint8 offset) internal pure returns (bytes22 result) {\n if (offset > 10) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(80, not(0)))\n }\n }\n\n function replace_32_22(bytes32 self, bytes22 value, uint8 offset) internal pure returns (bytes32 result) {\n bytes22 oldValue = extract_32_22(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(80, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_32_24(bytes32 self, uint8 offset) internal pure returns (bytes24 result) {\n if (offset > 8) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(64, not(0)))\n }\n }\n\n function replace_32_24(bytes32 self, bytes24 value, uint8 offset) internal pure returns (bytes32 result) {\n bytes24 oldValue = extract_32_24(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(64, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n\n function extract_32_28(bytes32 self, uint8 offset) internal pure returns (bytes28 result) {\n if (offset > 4) revert OutOfRangeAccess();\n assembly (\"memory-safe\") {\n result := and(shl(mul(8, offset), self), shl(32, not(0)))\n }\n }\n\n function replace_32_28(bytes32 self, bytes28 value, uint8 offset) internal pure returns (bytes32 result) {\n bytes28 oldValue = extract_32_28(self, offset);\n assembly (\"memory-safe\") {\n value := and(value, shl(32, not(0)))\n result := xor(self, shr(mul(8, offset), xor(oldValue, value)))\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Panic.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/Panic.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Helper library for emitting standardized panic codes.\n *\n * ```solidity\n * contract Example {\n * using Panic for uint256;\n *\n * // Use any of the declared internal constants\n * function foo() { Panic.GENERIC.panic(); }\n *\n * // Alternatively\n * function foo() { Panic.panic(Panic.GENERIC); }\n * }\n * ```\n *\n * Follows the list from https://github.com/ethereum/solidity/blob/v0.8.24/libsolutil/ErrorCodes.h[libsolutil].\n *\n * _Available since v5.1._\n */\n// slither-disable-next-line unused-state\nlibrary Panic {\n /// @dev generic / unspecified error\n uint256 internal constant GENERIC = 0x00;\n /// @dev used by the assert() builtin\n uint256 internal constant ASSERT = 0x01;\n /// @dev arithmetic underflow or overflow\n uint256 internal constant UNDER_OVERFLOW = 0x11;\n /// @dev division or modulo by zero\n uint256 internal constant DIVISION_BY_ZERO = 0x12;\n /// @dev enum conversion error\n uint256 internal constant ENUM_CONVERSION_ERROR = 0x21;\n /// @dev invalid encoding in storage\n uint256 internal constant STORAGE_ENCODING_ERROR = 0x22;\n /// @dev empty array pop\n uint256 internal constant EMPTY_ARRAY_POP = 0x31;\n /// @dev array out of bounds access\n uint256 internal constant ARRAY_OUT_OF_BOUNDS = 0x32;\n /// @dev resource error (too large allocation or too large array)\n uint256 internal constant RESOURCE_ERROR = 0x41;\n /// @dev calling invalid internal function\n uint256 internal constant INVALID_INTERNAL_FUNCTION = 0x51;\n\n /// @dev Reverts with a panic code. Recommended to use with\n /// the internal constants with predefined codes.\n function panic(uint256 code) internal pure {\n assembly (\"memory-safe\") {\n mstore(0x00, 0x4e487b71)\n mstore(0x20, code)\n revert(0x1c, 0x24)\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/ReentrancyGuardTransient.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.5.0) (utils/ReentrancyGuardTransient.sol)\n\npragma solidity ^0.8.24;\n\nimport {TransientSlot} from \"./TransientSlot.sol\";\n\n/**\n * @dev Variant of {ReentrancyGuard} that uses transient storage.\n *\n * NOTE: This variant only works on networks where EIP-1153 is available.\n *\n * _Available since v5.1._\n *\n * @custom:stateless\n */\nabstract contract ReentrancyGuardTransient {\n using TransientSlot for *;\n\n // keccak256(abi.encode(uint256(keccak256(\"openzeppelin.storage.ReentrancyGuard\")) - 1)) & ~bytes32(uint256(0xff))\n bytes32 private constant REENTRANCY_GUARD_STORAGE =\n 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;\n\n /**\n * @dev Unauthorized reentrant call.\n */\n error ReentrancyGuardReentrantCall();\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n /**\n * @dev A `view` only version of {nonReentrant}. Use to block view functions\n * from being called, preventing reading from inconsistent contract state.\n *\n * CAUTION: This is a \"view\" modifier and does not change the reentrancy\n * status. Use it only on view functions. For payable or non-payable functions,\n * use the standard {nonReentrant} modifier instead.\n */\n modifier nonReentrantView() {\n _nonReentrantBeforeView();\n _;\n }\n\n function _nonReentrantBeforeView() private view {\n if (_reentrancyGuardEntered()) {\n revert ReentrancyGuardReentrantCall();\n }\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, REENTRANCY_GUARD_STORAGE.asBoolean().tload() will be false\n _nonReentrantBeforeView();\n\n // Any calls to nonReentrant after this point will fail\n _reentrancyGuardStorageSlot().asBoolean().tstore(true);\n }\n\n function _nonReentrantAfter() private {\n _reentrancyGuardStorageSlot().asBoolean().tstore(false);\n }\n\n /**\n * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n * `nonReentrant` function in the call stack.\n */\n function _reentrancyGuardEntered() internal view returns (bool) {\n return _reentrancyGuardStorageSlot().asBoolean().tload();\n }\n\n function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {\n return REENTRANCY_GUARD_STORAGE;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/ShortStrings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.5.0) (utils/ShortStrings.sol)\n\npragma solidity ^0.8.20;\n\nimport {StorageSlot} from \"./StorageSlot.sol\";\n\n// | string | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA |\n// | length | 0x BB |\ntype ShortString is bytes32;\n\n/**\n * @dev This library provides functions to convert short memory strings\n * into a `ShortString` type that can be used as an immutable variable.\n *\n * Strings of arbitrary length can be optimized using this library if\n * they are short enough (up to 31 bytes) by packing them with their\n * length (1 byte) in a single EVM word (32 bytes). Additionally, a\n * fallback mechanism can be used for every other case.\n *\n * Usage example:\n *\n * ```solidity\n * contract Named {\n * using ShortStrings for *;\n *\n * ShortString private immutable _name;\n * string private _nameFallback;\n *\n * constructor(string memory contractName) {\n * _name = contractName.toShortStringWithFallback(_nameFallback);\n * }\n *\n * function name() external view returns (string memory) {\n * return _name.toStringWithFallback(_nameFallback);\n * }\n * }\n * ```\n */\nlibrary ShortStrings {\n // Used as an identifier for strings longer than 31 bytes.\n bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;\n\n error StringTooLong(string str);\n error InvalidShortString();\n\n /**\n * @dev Encode a string of at most 31 chars into a `ShortString`.\n *\n * This will trigger a `StringTooLong` error is the input string is too long.\n */\n function toShortString(string memory str) internal pure returns (ShortString) {\n bytes memory bstr = bytes(str);\n if (bstr.length > 0x1f) {\n revert StringTooLong(str);\n }\n return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));\n }\n\n /**\n * @dev Decode a `ShortString` back to a \"normal\" string.\n */\n function toString(ShortString sstr) internal pure returns (string memory) {\n uint256 len = byteLength(sstr);\n // using `new string(len)` would work locally but is not memory safe.\n string memory str = new string(0x20);\n assembly (\"memory-safe\") {\n mstore(str, len)\n mstore(add(str, 0x20), sstr)\n }\n return str;\n }\n\n /**\n * @dev Return the length of a `ShortString`.\n */\n function byteLength(ShortString sstr) internal pure returns (uint256) {\n uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;\n if (result > 0x1f) {\n revert InvalidShortString();\n }\n return result;\n }\n\n /**\n * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.\n */\n function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {\n if (bytes(value).length < 0x20) {\n return toShortString(value);\n } else {\n StorageSlot.getStringSlot(store).value = value;\n return ShortString.wrap(FALLBACK_SENTINEL);\n }\n }\n\n /**\n * @dev Decode a string that was encoded to `ShortString` or written to storage using {toShortStringWithFallback}.\n */\n function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {\n if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {\n return toString(value);\n } else {\n return store;\n }\n }\n\n /**\n * @dev Return the length of a string that was encoded to `ShortString` or written to storage using\n * {toShortStringWithFallback}.\n *\n * WARNING: This will return the \"byte length\" of the string. This may not reflect the actual length in terms of\n * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.\n */\n function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {\n if (ShortString.unwrap(value) != FALLBACK_SENTINEL) {\n return byteLength(value);\n } else {\n return bytes(store).length;\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/StorageSlot.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Library for reading and writing primitive types to specific storage slots.\n *\n * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.\n *\n * Example usage to set ERC-1967 implementation slot:\n * ```solidity\n * contract ERC1967 {\n * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.\n * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\n *\n * function _getImplementation() internal view returns (address) {\n * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;\n * }\n *\n * function _setImplementation(address newImplementation) internal {\n * require(newImplementation.code.length > 0);\n * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;\n * }\n * }\n * ```\n *\n * TIP: Consider using this library along with {SlotDerivation}.\n */\nlibrary StorageSlot {\n struct AddressSlot {\n address value;\n }\n\n struct BooleanSlot {\n bool value;\n }\n\n struct Bytes32Slot {\n bytes32 value;\n }\n\n struct Uint256Slot {\n uint256 value;\n }\n\n struct Int256Slot {\n int256 value;\n }\n\n struct StringSlot {\n string value;\n }\n\n struct BytesSlot {\n bytes value;\n }\n\n /**\n * @dev Returns an `AddressSlot` with member `value` located at `slot`.\n */\n function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `BooleanSlot` with member `value` located at `slot`.\n */\n function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Bytes32Slot` with member `value` located at `slot`.\n */\n function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Uint256Slot` with member `value` located at `slot`.\n */\n function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `Int256Slot` with member `value` located at `slot`.\n */\n function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns a `StringSlot` with member `value` located at `slot`.\n */\n function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `StringSlot` representation of the string storage pointer `store`.\n */\n function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := store.slot\n }\n }\n\n /**\n * @dev Returns a `BytesSlot` with member `value` located at `slot`.\n */\n function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := slot\n }\n }\n\n /**\n * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.\n */\n function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {\n assembly (\"memory-safe\") {\n r.slot := store.slot\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.6.0) (utils/Strings.sol)\n\npragma solidity ^0.8.24;\n\nimport {Math} from \"./math/Math.sol\";\nimport {SafeCast} from \"./math/SafeCast.sol\";\nimport {SignedMath} from \"./math/SignedMath.sol\";\nimport {Bytes} from \"./Bytes.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n using SafeCast for *;\n\n bytes16 private constant HEX_DIGITS = \"0123456789abcdef\";\n uint8 private constant ADDRESS_LENGTH = 20;\n uint256 private constant SPECIAL_CHARS_LOOKUP =\n 0xffffffff | // first 32 bits corresponding to the control characters (U+0000 to U+001F)\n (1 << 0x22) | // double quote\n (1 << 0x5c); // backslash\n\n /**\n * @dev The `value` string doesn't fit in the specified `length`.\n */\n error StringsInsufficientHexLength(uint256 value, uint256 length);\n\n /**\n * @dev The string being parsed contains characters that are not in scope of the given base.\n */\n error StringsInvalidChar();\n\n /**\n * @dev The string being parsed is not a properly formatted address.\n */\n error StringsInvalidAddressFormat();\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n assembly (\"memory-safe\") {\n ptr := add(add(buffer, 0x20), length)\n }\n while (true) {\n ptr--;\n assembly (\"memory-safe\") {\n mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `int256` to its ASCII `string` decimal representation.\n */\n function toStringSigned(int256 value) internal pure returns (string memory) {\n return string.concat(value < 0 ? \"-\" : \"\", toString(SignedMath.abs(value)));\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n uint256 localValue = value;\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = HEX_DIGITS[localValue & 0xf];\n localValue >>= 4;\n }\n if (localValue != 0) {\n revert StringsInsufficientHexLength(value, length);\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal\n * representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its checksummed ASCII `string` hexadecimal\n * representation, according to EIP-55.\n */\n function toChecksumHexString(address addr) internal pure returns (string memory) {\n bytes memory buffer = bytes(toHexString(addr));\n\n // hash the hex part of buffer (skip length + 2 bytes, length 40)\n uint256 hashValue;\n assembly (\"memory-safe\") {\n hashValue := shr(96, keccak256(add(buffer, 0x22), 40))\n }\n\n for (uint256 i = 41; i > 1; --i) {\n // possible values for buffer[i] are 48 (0) to 57 (9) and 97 (a) to 102 (f)\n if (hashValue & 0xf > 7 && uint8(buffer[i]) > 96) {\n // case shift by xoring with 0x20\n buffer[i] ^= 0x20;\n }\n hashValue >>= 4;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `bytes` buffer to its ASCII `string` hexadecimal representation.\n */\n function toHexString(bytes memory input) internal pure returns (string memory) {\n unchecked {\n bytes memory buffer = new bytes(2 * input.length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 0; i < input.length; ++i) {\n uint8 v = uint8(input[i]);\n buffer[2 * i + 2] = HEX_DIGITS[v >> 4];\n buffer[2 * i + 3] = HEX_DIGITS[v & 0xf];\n }\n return string(buffer);\n }\n }\n\n /**\n * @dev Returns true if the two strings are equal.\n */\n function equal(string memory a, string memory b) internal pure returns (bool) {\n return Bytes.equal(bytes(a), bytes(b));\n }\n\n /**\n * @dev Parse a decimal string and returns the value as a `uint256`.\n *\n * Requirements:\n * - The string must be formatted as `[0-9]*`\n * - The result must fit into an `uint256` type\n */\n function parseUint(string memory input) internal pure returns (uint256) {\n return parseUint(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseUint-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `[0-9]*`\n * - The result must fit into an `uint256` type\n */\n function parseUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {\n (bool success, uint256 value) = tryParseUint(input, begin, end);\n if (!success) revert StringsInvalidChar();\n return value;\n }\n\n /**\n * @dev Variant of {parseUint-string} that returns false if the parsing fails because of an invalid character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseUint(string memory input) internal pure returns (bool success, uint256 value) {\n return _tryParseUintUncheckedBounds(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseUint-string-uint256-uint256} that returns false if the parsing fails because of an invalid\n * character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseUint(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, uint256 value) {\n if (end > bytes(input).length || begin > end) return (false, 0);\n return _tryParseUintUncheckedBounds(input, begin, end);\n }\n\n /**\n * @dev Implementation of {tryParseUint-string-uint256-uint256} that does not check bounds. Caller should make sure that\n * `begin <= end <= input.length`. Other inputs would result in undefined behavior.\n */\n function _tryParseUintUncheckedBounds(\n string memory input,\n uint256 begin,\n uint256 end\n ) private pure returns (bool success, uint256 value) {\n bytes memory buffer = bytes(input);\n\n uint256 result = 0;\n for (uint256 i = begin; i < end; ++i) {\n uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));\n if (chr > 9) return (false, 0);\n result *= 10;\n result += chr;\n }\n return (true, result);\n }\n\n /**\n * @dev Parse a decimal string and returns the value as a `int256`.\n *\n * Requirements:\n * - The string must be formatted as `[-+]?[0-9]*`\n * - The result must fit in an `int256` type.\n */\n function parseInt(string memory input) internal pure returns (int256) {\n return parseInt(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseInt-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `[-+]?[0-9]*`\n * - The result must fit in an `int256` type.\n */\n function parseInt(string memory input, uint256 begin, uint256 end) internal pure returns (int256) {\n (bool success, int256 value) = tryParseInt(input, begin, end);\n if (!success) revert StringsInvalidChar();\n return value;\n }\n\n /**\n * @dev Variant of {parseInt-string} that returns false if the parsing fails because of an invalid character or if\n * the result does not fit in a `int256`.\n *\n * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.\n */\n function tryParseInt(string memory input) internal pure returns (bool success, int256 value) {\n return _tryParseIntUncheckedBounds(input, 0, bytes(input).length);\n }\n\n uint256 private constant ABS_MIN_INT256 = 2 ** 255;\n\n /**\n * @dev Variant of {parseInt-string-uint256-uint256} that returns false if the parsing fails because of an invalid\n * character or if the result does not fit in a `int256`.\n *\n * NOTE: This function will revert if the absolute value of the result does not fit in a `uint256`.\n */\n function tryParseInt(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, int256 value) {\n if (end > bytes(input).length || begin > end) return (false, 0);\n return _tryParseIntUncheckedBounds(input, begin, end);\n }\n\n /**\n * @dev Implementation of {tryParseInt-string-uint256-uint256} that does not check bounds. Caller should make sure that\n * `begin <= end <= input.length`. Other inputs would result in undefined behavior.\n */\n function _tryParseIntUncheckedBounds(\n string memory input,\n uint256 begin,\n uint256 end\n ) private pure returns (bool success, int256 value) {\n bytes memory buffer = bytes(input);\n\n // Check presence of a negative sign.\n bytes1 sign = begin == end ? bytes1(0) : bytes1(_unsafeReadBytesOffset(buffer, begin)); // don't do out-of-bound (possibly unsafe) read if sub-string is empty\n bool positiveSign = sign == bytes1(\"+\");\n bool negativeSign = sign == bytes1(\"-\");\n uint256 offset = (positiveSign || negativeSign).toUint();\n\n (bool absSuccess, uint256 absValue) = tryParseUint(input, begin + offset, end);\n\n if (absSuccess && absValue < ABS_MIN_INT256) {\n return (true, negativeSign ? -int256(absValue) : int256(absValue));\n } else if (absSuccess && negativeSign && absValue == ABS_MIN_INT256) {\n return (true, type(int256).min);\n } else return (false, 0);\n }\n\n /**\n * @dev Parse a hexadecimal string (with or without \"0x\" prefix), and returns the value as a `uint256`.\n *\n * Requirements:\n * - The string must be formatted as `(0x)?[0-9a-fA-F]*`\n * - The result must fit in an `uint256` type.\n */\n function parseHexUint(string memory input) internal pure returns (uint256) {\n return parseHexUint(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseHexUint-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `(0x)?[0-9a-fA-F]*`\n * - The result must fit in an `uint256` type.\n */\n function parseHexUint(string memory input, uint256 begin, uint256 end) internal pure returns (uint256) {\n (bool success, uint256 value) = tryParseHexUint(input, begin, end);\n if (!success) revert StringsInvalidChar();\n return value;\n }\n\n /**\n * @dev Variant of {parseHexUint-string} that returns false if the parsing fails because of an invalid character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseHexUint(string memory input) internal pure returns (bool success, uint256 value) {\n return _tryParseHexUintUncheckedBounds(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseHexUint-string-uint256-uint256} that returns false if the parsing fails because of an\n * invalid character.\n *\n * NOTE: This function will revert if the result does not fit in a `uint256`.\n */\n function tryParseHexUint(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, uint256 value) {\n if (end > bytes(input).length || begin > end) return (false, 0);\n return _tryParseHexUintUncheckedBounds(input, begin, end);\n }\n\n /**\n * @dev Implementation of {tryParseHexUint-string-uint256-uint256} that does not check bounds. Caller should make sure that\n * `begin <= end <= input.length`. Other inputs would result in undefined behavior.\n */\n function _tryParseHexUintUncheckedBounds(\n string memory input,\n uint256 begin,\n uint256 end\n ) private pure returns (bool success, uint256 value) {\n bytes memory buffer = bytes(input);\n\n // skip 0x prefix if present\n bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(buffer, begin)) == bytes2(\"0x\"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty\n uint256 offset = hasPrefix.toUint() * 2;\n\n uint256 result = 0;\n for (uint256 i = begin + offset; i < end; ++i) {\n uint8 chr = _tryParseChr(bytes1(_unsafeReadBytesOffset(buffer, i)));\n if (chr > 15) return (false, 0);\n result *= 16;\n unchecked {\n // Multiplying by 16 is equivalent to a shift of 4 bits (with additional overflow check).\n // This guarantees that adding a value < 16 will not cause an overflow, hence the unchecked.\n result += chr;\n }\n }\n return (true, result);\n }\n\n /**\n * @dev Parse a hexadecimal string (with or without \"0x\" prefix), and returns the value as an `address`.\n *\n * Requirements:\n * - The string must be formatted as `(0x)?[0-9a-fA-F]{40}`\n */\n function parseAddress(string memory input) internal pure returns (address) {\n return parseAddress(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseAddress-string} that parses a substring of `input` located between position `begin` (included) and\n * `end` (excluded).\n *\n * Requirements:\n * - The substring must be formatted as `(0x)?[0-9a-fA-F]{40}`\n */\n function parseAddress(string memory input, uint256 begin, uint256 end) internal pure returns (address) {\n (bool success, address value) = tryParseAddress(input, begin, end);\n if (!success) revert StringsInvalidAddressFormat();\n return value;\n }\n\n /**\n * @dev Variant of {parseAddress-string} that returns false if the parsing fails because the input is not a properly\n * formatted address. See {parseAddress-string} requirements.\n */\n function tryParseAddress(string memory input) internal pure returns (bool success, address value) {\n return tryParseAddress(input, 0, bytes(input).length);\n }\n\n /**\n * @dev Variant of {parseAddress-string-uint256-uint256} that returns false if the parsing fails because input is not a properly\n * formatted address. See {parseAddress-string-uint256-uint256} requirements.\n */\n function tryParseAddress(\n string memory input,\n uint256 begin,\n uint256 end\n ) internal pure returns (bool success, address value) {\n if (end > bytes(input).length || begin > end) return (false, address(0));\n\n bool hasPrefix = (end > begin + 1) && bytes2(_unsafeReadBytesOffset(bytes(input), begin)) == bytes2(\"0x\"); // don't do out-of-bound (possibly unsafe) read if sub-string is empty\n uint256 expectedLength = 40 + hasPrefix.toUint() * 2;\n\n // check that input is the correct length\n if (end - begin == expectedLength) {\n // length guarantees that this does not overflow, and value is at most type(uint160).max\n (bool s, uint256 v) = _tryParseHexUintUncheckedBounds(input, begin, end);\n return (s, address(uint160(v)));\n } else {\n return (false, address(0));\n }\n }\n\n function _tryParseChr(bytes1 chr) private pure returns (uint8) {\n uint8 value = uint8(chr);\n\n // Try to parse `chr`:\n // - Case 1: [0-9]\n // - Case 2: [a-f]\n // - Case 3: [A-F]\n // - otherwise not supported\n unchecked {\n if (value > 47 && value < 58) value -= 48;\n else if (value > 96 && value < 103) value -= 87;\n else if (value > 64 && value < 71) value -= 55;\n else return type(uint8).max;\n }\n\n return value;\n }\n\n /**\n * @dev Escape special characters in JSON strings. This can be useful to prevent JSON injection in NFT metadata.\n *\n * WARNING: This function should only be used in double quoted JSON strings. Single quotes are not escaped.\n *\n * NOTE: This function escapes backslashes (including those in \\uXXXX sequences) and the characters in ranges\n * defined in section 2.5 of RFC-4627 (U+0000 to U+001F, U+0022 and U+005C). All control characters in U+0000\n * to U+001F are escaped (\\b, \\t, \\n, \\f, \\r use short form; others use \\u00XX). ECMAScript's `JSON.parse` does\n * recover escaped unicode characters that are not in this range, but other tooling may provide different results.\n */\n function escapeJSON(string memory input) internal pure returns (string memory) {\n bytes memory buffer = bytes(input);\n\n // Put output at the FMP. Memory will be reserved later when we figure out the actual length of the escaped\n // string. All write are done using _unsafeWriteBytesOffset, which avoid the (expensive) length checks for\n // each character written.\n bytes memory output;\n assembly (\"memory-safe\") {\n output := mload(0x40)\n }\n uint256 outputLength = 0;\n\n for (uint256 i = 0; i < buffer.length; ++i) {\n uint8 char = uint8(bytes1(_unsafeReadBytesOffset(buffer, i)));\n if (((SPECIAL_CHARS_LOOKUP & (1 << char)) != 0)) {\n _unsafeWriteBytesOffset(output, outputLength++, \"\\\\\");\n if (char == 0x08) _unsafeWriteBytesOffset(output, outputLength++, \"b\");\n else if (char == 0x09) _unsafeWriteBytesOffset(output, outputLength++, \"t\");\n else if (char == 0x0a) _unsafeWriteBytesOffset(output, outputLength++, \"n\");\n else if (char == 0x0c) _unsafeWriteBytesOffset(output, outputLength++, \"f\");\n else if (char == 0x0d) _unsafeWriteBytesOffset(output, outputLength++, \"r\");\n else if (char == 0x5c) _unsafeWriteBytesOffset(output, outputLength++, \"\\\\\");\n else if (char == 0x22) {\n // solhint-disable-next-line quotes\n _unsafeWriteBytesOffset(output, outputLength++, '\"');\n } else {\n // U+0000 to U+001F without short form: output \\u00XX\n _unsafeWriteBytesOffset(output, outputLength++, \"u\");\n _unsafeWriteBytesOffset(output, outputLength++, \"0\");\n _unsafeWriteBytesOffset(output, outputLength++, \"0\");\n _unsafeWriteBytesOffset(output, outputLength++, HEX_DIGITS[char >> 4]);\n _unsafeWriteBytesOffset(output, outputLength++, HEX_DIGITS[char & 0x0f]);\n }\n } else {\n _unsafeWriteBytesOffset(output, outputLength++, bytes1(char));\n }\n }\n // write the actual length and reserve memory\n assembly (\"memory-safe\") {\n mstore(output, outputLength)\n mstore(0x40, add(output, add(outputLength, 0x20)))\n }\n\n return string(output);\n }\n\n /**\n * @dev Reads a bytes32 from a bytes array without bounds checking.\n *\n * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the\n * assembly block as such would prevent some optimizations.\n */\n function _unsafeReadBytesOffset(bytes memory buffer, uint256 offset) private pure returns (bytes32 value) {\n // This is not memory safe in the general case, but all calls to this private function are within bounds.\n assembly (\"memory-safe\") {\n value := mload(add(add(buffer, 0x20), offset))\n }\n }\n\n /**\n * @dev Write a bytes1 to a bytes array without bounds checking.\n *\n * NOTE: making this function internal would mean it could be used with memory unsafe offset, and marking the\n * assembly block as such would prevent some optimizations.\n */\n function _unsafeWriteBytesOffset(bytes memory buffer, uint256 offset, bytes1 value) private pure {\n // This is not memory safe in the general case, but all calls to this private function are within bounds.\n assembly (\"memory-safe\") {\n mstore8(add(add(buffer, 0x20), offset), shr(248, value))\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/TransientSlot.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (utils/TransientSlot.sol)\n// This file was procedurally generated from scripts/generate/templates/TransientSlot.js.\n\npragma solidity ^0.8.24;\n\n/**\n * @dev Library for reading and writing value-types to specific transient storage slots.\n *\n * Transient slots are often used to store temporary values that are removed after the current transaction.\n * This library helps with reading and writing to such slots without the need for inline assembly.\n *\n * * Example reading and writing values using transient storage:\n * ```solidity\n * contract Lock {\n * using TransientSlot for *;\n *\n * // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.\n * bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542;\n *\n * modifier locked() {\n * require(!_LOCK_SLOT.asBoolean().tload());\n *\n * _LOCK_SLOT.asBoolean().tstore(true);\n * _;\n * _LOCK_SLOT.asBoolean().tstore(false);\n * }\n * }\n * ```\n *\n * TIP: Consider using this library along with {SlotDerivation}.\n */\nlibrary TransientSlot {\n /**\n * @dev UDVT that represents a slot holding an address.\n */\n type AddressSlot is bytes32;\n\n /**\n * @dev Cast an arbitrary slot to a AddressSlot.\n */\n function asAddress(bytes32 slot) internal pure returns (AddressSlot) {\n return AddressSlot.wrap(slot);\n }\n\n /**\n * @dev UDVT that represents a slot holding a bool.\n */\n type BooleanSlot is bytes32;\n\n /**\n * @dev Cast an arbitrary slot to a BooleanSlot.\n */\n function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) {\n return BooleanSlot.wrap(slot);\n }\n\n /**\n * @dev UDVT that represents a slot holding a bytes32.\n */\n type Bytes32Slot is bytes32;\n\n /**\n * @dev Cast an arbitrary slot to a Bytes32Slot.\n */\n function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) {\n return Bytes32Slot.wrap(slot);\n }\n\n /**\n * @dev UDVT that represents a slot holding a uint256.\n */\n type Uint256Slot is bytes32;\n\n /**\n * @dev Cast an arbitrary slot to a Uint256Slot.\n */\n function asUint256(bytes32 slot) internal pure returns (Uint256Slot) {\n return Uint256Slot.wrap(slot);\n }\n\n /**\n * @dev UDVT that represents a slot holding a int256.\n */\n type Int256Slot is bytes32;\n\n /**\n * @dev Cast an arbitrary slot to a Int256Slot.\n */\n function asInt256(bytes32 slot) internal pure returns (Int256Slot) {\n return Int256Slot.wrap(slot);\n }\n\n /**\n * @dev Load the value held at location `slot` in transient storage.\n */\n function tload(AddressSlot slot) internal view returns (address value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n /**\n * @dev Store `value` at location `slot` in transient storage.\n */\n function tstore(AddressSlot slot, address value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n /**\n * @dev Load the value held at location `slot` in transient storage.\n */\n function tload(BooleanSlot slot) internal view returns (bool value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n /**\n * @dev Store `value` at location `slot` in transient storage.\n */\n function tstore(BooleanSlot slot, bool value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n /**\n * @dev Load the value held at location `slot` in transient storage.\n */\n function tload(Bytes32Slot slot) internal view returns (bytes32 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n /**\n * @dev Store `value` at location `slot` in transient storage.\n */\n function tstore(Bytes32Slot slot, bytes32 value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n /**\n * @dev Load the value held at location `slot` in transient storage.\n */\n function tload(Uint256Slot slot) internal view returns (uint256 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n /**\n * @dev Store `value` at location `slot` in transient storage.\n */\n function tstore(Uint256Slot slot, uint256 value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n\n /**\n * @dev Load the value held at location `slot` in transient storage.\n */\n function tload(Int256Slot slot) internal view returns (int256 value) {\n assembly (\"memory-safe\") {\n value := tload(slot)\n }\n }\n\n /**\n * @dev Store `value` at location `slot` in transient storage.\n */\n function tstore(Int256Slot slot, int256 value) internal {\n assembly (\"memory-safe\") {\n tstore(slot, value)\n }\n }\n}\n" + }, + "contracts/EIP7702Implementation.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport {Account} from \"@openzeppelin/contracts/account/Account.sol\";\nimport {ERC7821} from \"@openzeppelin/contracts/account/extensions/draft-ERC7821.sol\";\nimport {SignerEIP7702} from \"@openzeppelin/contracts/utils/cryptography/signers/SignerEIP7702.sol\";\nimport {EIP7702Utils} from \"@openzeppelin/contracts/account/utils/EIP7702Utils.sol\";\nimport {ERC165} from \"@openzeppelin/contracts/utils/introspection/ERC165.sol\";\nimport {IEntryPoint} from \"@openzeppelin/contracts/interfaces/draft-IERC4337.sol\";\n\n/**\n * EIP-7702 smart account implementation using OpenZeppelin base contracts.\n *\n * Inheritance stack:\n * Account — ERC-4337 validateUserOp, onlyEntryPoint guards, pre-fund payment\n * SignerEIP7702 — _rawSignatureValidation: recovers signer and checks == address(this)\n * ERC7821 — standardized batch execute(bytes32 mode, bytes executionData)\n * ERC165 — supportsInterface\n *\n * EIP-7702 flow: deploy this contract once, then have EOAs sign an authorization\n * pointing to this address. The EOA's code becomes `0xef0100 || address(this)`,\n * giving it full smart-account capabilities while keeping the original private key.\n */\ncontract EIP7702Implementation is Account, SignerEIP7702, ERC7821, ERC165 {\n // Baked into bytecode at deploy time so EIP-7702 delegating EOAs inherit\n // the correct EntryPoint without any storage reads.\n IEntryPoint private immutable _entryPoint;\n\n // Takes address so callers don't need OZ's IEntryPoint type in scope.\n constructor(address entryPoint_) {\n _entryPoint = IEntryPoint(entryPoint_);\n }\n\n function entryPoint() public view virtual override returns (IEntryPoint) {\n return _entryPoint;\n }\n\n // -------------------------------------------------------------------------\n // Execution\n // -------------------------------------------------------------------------\n\n /**\n * @dev Allow the EntryPoint (in addition to address(this)) to call the\n * ERC-7821 batch execute function. Without this override only the account\n * itself can trigger execution.\n */\n function _erc7821AuthorizedExecutor(\n address caller,\n bytes32 mode,\n bytes calldata executionData\n ) internal view virtual override returns (bool) {\n return caller == address(entryPoint()) || super._erc7821AuthorizedExecutor(caller, mode, executionData);\n }\n\n /**\n * @dev Convenience single-call path. Only callable by the EntryPoint or the\n * account itself — prevents arbitrary callers from draining funds.\n *\n * For batch calls use the ERC-7821 `execute(bytes32 mode, bytes executionData)`\n * inherited from ERC7821 with mode = 0x0100000000000000000000000000000000000000000000000000000000000000\n * and executionData = abi.encode(calls) where calls is (address,uint256,bytes)[].\n */\n function execute(\n address to,\n uint256 value,\n bytes calldata data\n ) external onlyEntryPointOrSelf returns (bytes memory) {\n (bool ok, bytes memory result) = to.call{value: value}(data);\n require(ok, \"execution failed\");\n return result;\n }\n\n // -------------------------------------------------------------------------\n // ERC-165\n // -------------------------------------------------------------------------\n\n /**\n * @dev Advertise ERC-7821 (batch executor) and ERC-165 support.\n * The ERC-7821 interface ID 0x4e49c5c7 is the XOR of:\n * execute(bytes32,bytes).selector ^ supportsExecutionMode(bytes32).selector\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == 0x4e49c5c7 // ERC-7821 batch executor\n || super.supportsInterface(interfaceId); // covers 0x01ffc9a7 (ERC-165)\n }\n\n // -------------------------------------------------------------------------\n // Utilities\n // -------------------------------------------------------------------------\n\n /**\n * @dev Returns the implementation address this EOA has delegated to via\n * EIP-7702, or address(0) if no delegation is active.\n */\n function getDelegate() external view returns (address) {\n return EIP7702Utils.fetchDelegate(address(this));\n }\n}\n" + }, + "contracts/Etherspot/BasePaymaster.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.23;\n\n/* solhint-disable reason-string */\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts/utils/introspection/IERC165.sol\";\nimport \"./interfaces/IPaymaster.sol\";\nimport \"./interfaces/IEntryPoint.sol\";\nimport \"./core/UserOperationLib.sol\";\n\n/**\n * Helper class for creating a paymaster.\n * provides helper methods for staking.\n * Validates that the postOp is called only by the entryPoint.\n */\nabstract contract BasePaymaster is IPaymaster, Ownable {\n IEntryPoint public immutable entryPoint;\n\n uint256 internal constant PAYMASTER_VALIDATION_GAS_OFFSET =\n UserOperationLib.PAYMASTER_VALIDATION_GAS_OFFSET;\n uint256 internal constant PAYMASTER_POSTOP_GAS_OFFSET =\n UserOperationLib.PAYMASTER_POSTOP_GAS_OFFSET;\n uint256 internal constant PAYMASTER_DATA_OFFSET =\n UserOperationLib.PAYMASTER_DATA_OFFSET;\n\n constructor(IEntryPoint _entryPoint) Ownable(msg.sender) {\n _validateEntryPointInterface(_entryPoint);\n entryPoint = _entryPoint;\n }\n\n //sanity check: make sure this EntryPoint was compiled against the same\n // IEntryPoint of this paymaster\n function _validateEntryPointInterface(\n IEntryPoint _entryPoint\n ) internal virtual returns (bool) {\n require(\n IERC165(address(_entryPoint)).supportsInterface(\n type(IEntryPoint).interfaceId\n ),\n \"IEntryPoint interface mismatch\"\n );\n }\n\n /// @inheritdoc IPaymaster\n function validatePaymasterUserOp(\n PackedUserOperation calldata userOp,\n bytes32 userOpHash,\n uint256 maxCost\n ) external override returns (bytes memory context, uint256 validationData) {\n _requireFromEntryPoint();\n return _validatePaymasterUserOp(userOp, userOpHash, maxCost);\n }\n\n /**\n * Validate a user operation.\n * @param userOp - The user operation.\n * @param userOpHash - The hash of the user operation.\n * @param maxCost - The maximum cost of the user operation.\n */\n function _validatePaymasterUserOp(\n PackedUserOperation calldata userOp,\n bytes32 userOpHash,\n uint256 maxCost\n ) internal virtual returns (bytes memory context, uint256 validationData);\n\n /// @inheritdoc IPaymaster\n function postOp(\n PostOpMode mode,\n bytes calldata context,\n uint256 actualGasCost,\n uint256 actualUserOpFeePerGas\n ) external override {\n _requireFromEntryPoint();\n _postOp(mode, context, actualGasCost, actualUserOpFeePerGas);\n }\n\n /**\n * Post-operation handler.\n * (verified to be called only through the entryPoint)\n * @dev If subclass returns a non-empty context from validatePaymasterUserOp,\n * it must also implement this method.\n * @param mode - Enum with the following options:\n * opSucceeded - User operation succeeded.\n * opReverted - User op reverted. The paymaster still has to pay for gas.\n * postOpReverted - never passed in a call to postOp().\n * @param context - The context value returned by validatePaymasterUserOp\n * @param actualGasCost - Actual gas used so far (without this postOp call).\n * @param actualUserOpFeePerGas - the gas price this UserOp pays. This value is based on the UserOp's maxFeePerGas\n * and maxPriorityFee (and basefee)\n * It is not the same as tx.gasprice, which is what the bundler pays.\n */\n function _postOp(\n PostOpMode mode,\n bytes calldata context,\n uint256 actualGasCost,\n uint256 actualUserOpFeePerGas\n ) internal virtual {\n (mode, context, actualGasCost, actualUserOpFeePerGas); // unused params\n // subclass must override this method if validatePaymasterUserOp returns a context\n revert(\"must override\");\n }\n\n // /**\n // * Add a deposit for this paymaster, used for paying for transaction fees.\n // */\n // function deposit() public payable {\n // entryPoint.depositTo{value: msg.value}(address(this));\n // }\n\n // /**\n // * Withdraw value from the deposit.\n // * @param withdrawAddress - Target to send to.\n // * @param amount - Amount to withdraw.\n // */\n // function withdrawTo(\n // address payable withdrawAddress,\n // uint256 amount\n // ) public onlyOwner {\n // entryPoint.withdrawTo(withdrawAddress, amount);\n // }\n\n /**\n * Add stake for this paymaster.\n * This method can also carry eth value to add to the current stake.\n * @param unstakeDelaySec - The unstake delay for this paymaster. Can only be increased.\n */\n function addStake(uint32 unstakeDelaySec) external payable onlyOwner {\n entryPoint.addStake{value: msg.value}(unstakeDelaySec);\n }\n\n /**\n * Return current paymaster's deposit on the entryPoint.\n */\n function getDeposit() public view returns (uint256) {\n return entryPoint.balanceOf(address(this));\n }\n\n /**\n * Unlock the stake, in order to withdraw it.\n * The paymaster can't serve requests once unlocked, until it calls addStake again\n */\n function unlockStake() external onlyOwner {\n entryPoint.unlockStake();\n }\n\n /**\n * Withdraw the entire paymaster's stake.\n * stake must be unlocked first (and then wait for the unstakeDelay to be over)\n * @param withdrawAddress - The address to send withdrawn value.\n */\n function withdrawStake(address payable withdrawAddress) external onlyOwner {\n entryPoint.withdrawStake(withdrawAddress);\n }\n\n /**\n * Validate the call is made from a valid entrypoint\n */\n function _requireFromEntryPoint() internal virtual {\n require(msg.sender == address(entryPoint), \"Sender not EntryPoint\");\n }\n}\n" + }, + "contracts/Etherspot/core/Helpers.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.23;\n\n/* solhint-disable no-inline-assembly */\n\n/*\n * For simulation purposes, validateUserOp (and validatePaymasterUserOp)\n * must return this value in case of signature failure, instead of revert.\n */\nuint256 constant SIG_VALIDATION_FAILED = 1;\n\n/*\n * For simulation purposes, validateUserOp (and validatePaymasterUserOp)\n * return this value on success.\n */\nuint256 constant SIG_VALIDATION_SUCCESS = 0;\n\n/**\n * Returned data from validateUserOp.\n * validateUserOp returns a uint256, which is created by `_packedValidationData` and\n * parsed by `_parseValidationData`.\n * @param aggregator - address(0) - The account validated the signature by itself.\n * address(1) - The account failed to validate the signature.\n * otherwise - This is an address of a signature aggregator that must\n * be used to validate the signature.\n * @param validAfter - This UserOp is valid only after this timestamp.\n * @param validaUntil - This UserOp is valid only up to this timestamp.\n */\nstruct ValidationData {\n address aggregator;\n uint48 validAfter;\n uint48 validUntil;\n}\n\n/**\n * Extract sigFailed, validAfter, validUntil.\n * Also convert zero validUntil to type(uint48).max.\n * @param validationData - The packed validation data.\n */\nfunction _parseValidationData(\n uint256 validationData\n) pure returns (ValidationData memory data) {\n address aggregator = address(uint160(validationData));\n uint48 validUntil = uint48(validationData >> 160);\n if (validUntil == 0) {\n validUntil = type(uint48).max;\n }\n uint48 validAfter = uint48(validationData >> (48 + 160));\n return ValidationData(aggregator, validAfter, validUntil);\n}\n\n/**\n * Helper to pack the return value for validateUserOp.\n * @param data - The ValidationData to pack.\n */\nfunction _packValidationData(\n ValidationData memory data\n) pure returns (uint256) {\n return\n uint160(data.aggregator) |\n (uint256(data.validUntil) << 160) |\n (uint256(data.validAfter) << (160 + 48));\n}\n\n/**\n * Helper to pack the return value for validateUserOp, when not using an aggregator.\n * @param sigFailed - True for signature failure, false for success.\n * @param validUntil - Last timestamp this UserOperation is valid (or zero for infinite).\n * @param validAfter - First timestamp this UserOperation is valid.\n */\nfunction _packValidationData(\n bool sigFailed,\n uint48 validUntil,\n uint48 validAfter\n) pure returns (uint256) {\n return\n (sigFailed ? 1 : 0) |\n (uint256(validUntil) << 160) |\n (uint256(validAfter) << (160 + 48));\n}\n\n/**\n * keccak function over calldata.\n * @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it.\n */\nfunction calldataKeccak(bytes calldata data) pure returns (bytes32 ret) {\n assembly (\"memory-safe\") {\n let mem := mload(0x40)\n let len := data.length\n calldatacopy(mem, data.offset, len)\n ret := keccak256(mem, len)\n }\n}\n\n/**\n * The minimum of two numbers.\n * @param a - First number.\n * @param b - Second number.\n */\nfunction min(uint256 a, uint256 b) pure returns (uint256) {\n return a < b ? a : b;\n}\n" + }, + "contracts/Etherspot/core/UserOperationLib.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.23;\n\n/* solhint-disable no-inline-assembly */\n\nimport \"../interfaces/PackedUserOperation.sol\";\nimport {calldataKeccak, min} from \"./Helpers.sol\";\n\n/**\n * Utility functions helpful when working with UserOperation structs.\n */\nlibrary UserOperationLib {\n uint256 public constant PAYMASTER_VALIDATION_GAS_OFFSET = 20;\n uint256 public constant PAYMASTER_POSTOP_GAS_OFFSET = 36;\n uint256 public constant PAYMASTER_DATA_OFFSET = 52;\n /**\n * Get sender from user operation data.\n * @param userOp - The user operation data.\n */\n function getSender(\n PackedUserOperation calldata userOp\n ) internal pure returns (address) {\n address data;\n //read sender from userOp, which is first userOp member (saves 800 gas...)\n assembly {\n data := calldataload(userOp)\n }\n return address(uint160(data));\n }\n\n /**\n * Relayer/block builder might submit the TX with higher priorityFee,\n * but the user should not pay above what he signed for.\n * @param userOp - The user operation data.\n */\n function gasPrice(\n PackedUserOperation calldata userOp\n ) internal view returns (uint256) {\n unchecked {\n (uint256 maxPriorityFeePerGas, uint256 maxFeePerGas) = unpackUints(\n userOp.gasFees\n );\n if (maxFeePerGas == maxPriorityFeePerGas) {\n //legacy mode (for networks that don't support basefee opcode)\n return maxFeePerGas;\n }\n return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee);\n }\n }\n\n /**\n * Pack the user operation data into bytes for hashing.\n * @param userOp - The user operation data.\n */\n function encode(\n PackedUserOperation calldata userOp\n ) internal pure returns (bytes memory ret) {\n address sender = getSender(userOp);\n uint256 nonce = userOp.nonce;\n bytes32 hashInitCode = calldataKeccak(userOp.initCode);\n bytes32 hashCallData = calldataKeccak(userOp.callData);\n bytes32 accountGasLimits = userOp.accountGasLimits;\n uint256 preVerificationGas = userOp.preVerificationGas;\n bytes32 gasFees = userOp.gasFees;\n bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData);\n\n return\n abi.encode(\n sender,\n nonce,\n hashInitCode,\n hashCallData,\n accountGasLimits,\n preVerificationGas,\n gasFees,\n hashPaymasterAndData\n );\n }\n\n function unpackUints(\n bytes32 packed\n ) internal pure returns (uint256 high128, uint256 low128) {\n return (uint128(bytes16(packed)), uint128(uint256(packed)));\n }\n\n //unpack just the high 128-bits from a packed value\n function unpackHigh128(bytes32 packed) internal pure returns (uint256) {\n return uint256(packed) >> 128;\n }\n\n // unpack just the low 128-bits from a packed value\n function unpackLow128(bytes32 packed) internal pure returns (uint256) {\n return uint128(uint256(packed));\n }\n\n function unpackMaxPriorityFeePerGas(\n PackedUserOperation calldata userOp\n ) internal pure returns (uint256) {\n return unpackHigh128(userOp.gasFees);\n }\n\n function unpackMaxFeePerGas(\n PackedUserOperation calldata userOp\n ) internal pure returns (uint256) {\n return unpackLow128(userOp.gasFees);\n }\n\n function unpackVerificationGasLimit(\n PackedUserOperation calldata userOp\n ) internal pure returns (uint256) {\n return unpackHigh128(userOp.accountGasLimits);\n }\n\n function unpackCallGasLimit(\n PackedUserOperation calldata userOp\n ) internal pure returns (uint256) {\n return unpackLow128(userOp.accountGasLimits);\n }\n\n function unpackPaymasterVerificationGasLimit(\n PackedUserOperation calldata userOp\n ) internal pure returns (uint256) {\n return\n uint128(\n bytes16(\n userOp.paymasterAndData[\n PAYMASTER_VALIDATION_GAS_OFFSET:PAYMASTER_POSTOP_GAS_OFFSET\n ]\n )\n );\n }\n\n function unpackPostOpGasLimit(\n PackedUserOperation calldata userOp\n ) internal pure returns (uint256) {\n return\n uint128(\n bytes16(\n userOp.paymasterAndData[\n PAYMASTER_POSTOP_GAS_OFFSET:PAYMASTER_DATA_OFFSET\n ]\n )\n );\n }\n\n function unpackPaymasterStaticFields(\n bytes calldata paymasterAndData\n )\n internal\n pure\n returns (\n address paymaster,\n uint256 validationGasLimit,\n uint256 postOpGasLimit\n )\n {\n return (\n address(\n bytes20(paymasterAndData[:PAYMASTER_VALIDATION_GAS_OFFSET])\n ),\n uint128(\n bytes16(\n paymasterAndData[\n PAYMASTER_VALIDATION_GAS_OFFSET:PAYMASTER_POSTOP_GAS_OFFSET\n ]\n )\n ),\n uint128(\n bytes16(\n paymasterAndData[\n PAYMASTER_POSTOP_GAS_OFFSET:PAYMASTER_DATA_OFFSET\n ]\n )\n )\n );\n }\n\n /**\n * Hash the user operation data.\n * @param userOp - The user operation data.\n */\n function hash(\n PackedUserOperation calldata userOp\n ) internal pure returns (bytes32) {\n return keccak256(encode(userOp));\n }\n}\n" + }, + "contracts/Etherspot/EtherspotPaymaster.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.23;\n\nimport \"./BasePaymaster.sol\";\nimport \"./interfaces/IEntryPoint.sol\";\n\n/**\n * A single-owner whitelist paymaster.\n * Owner adds/removes addresses that are allowed to have their gas sponsored.\n * No signature required — whitelist is checked purely on-chain.\n */\ncontract SimpleWhitelistPaymaster is BasePaymaster {\n using UserOperationLib for PackedUserOperation;\n mapping(address => bool) public whitelist;\n\n event AddedToWhitelist(address indexed account);\n event RemovedFromWhitelist(address indexed account);\n\n constructor(IEntryPoint _entryPoint) BasePaymaster(_entryPoint) {}\n\n // -------------------------------------------------------------------------\n // Owner whitelist management\n // -------------------------------------------------------------------------\n\n function addToWhitelist(address account) external onlyOwner {\n require(account != address(0), \"Zero address\");\n whitelist[account] = true;\n emit AddedToWhitelist(account);\n }\n\n function addBatchToWhitelist(\n address[] calldata accounts\n ) external onlyOwner {\n for (uint256 i; i < accounts.length; ++i) {\n require(accounts[i] != address(0), \"Zero address\");\n whitelist[accounts[i]] = true;\n emit AddedToWhitelist(accounts[i]);\n }\n }\n\n function removeFromWhitelist(address account) external onlyOwner {\n whitelist[account] = false;\n emit RemovedFromWhitelist(account);\n }\n\n // -------------------------------------------------------------------------\n // Deposit management\n // -------------------------------------------------------------------------\n\n function deposit() external payable onlyOwner {\n entryPoint.depositTo{value: msg.value}(address(this));\n }\n\n function withdrawTo(address payable to, uint256 amount) external onlyOwner {\n entryPoint.withdrawTo(to, amount);\n }\n\n // -------------------------------------------------------------------------\n // ERC-4337 paymaster logic\n // -------------------------------------------------------------------------\n\n function _validatePaymasterUserOp(\n PackedUserOperation calldata userOp,\n bytes32 /*userOpHash*/,\n uint256 /*maxCost*/\n )\n internal\n view\n override\n returns (bytes memory context, uint256 validationData)\n {\n require(\n whitelist[userOp.getSender()],\n \"SimpleWhitelistPaymaster: sender not whitelisted\"\n );\n return (\"\", 0); // 0 = validation success, no expiry\n }\n\n // No context returned above so postOp is never called — default impl is fine.\n\n // Etherspot EP9 reports a different interfaceId than what the local IEntryPoint\n // computes — skip the interface check so deployment doesn't revert.\n function _validateEntryPointInterface(\n IEntryPoint\n ) internal pure override returns (bool) {}\n}\n" + }, + "contracts/Etherspot/interfaces/IAggregator.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.7.5;\n\nimport \"./PackedUserOperation.sol\";\n\n/**\n * Aggregated Signatures validator.\n */\ninterface IAggregator {\n /**\n * Validate aggregated signature.\n * Revert if the aggregated signature does not match the given list of operations.\n * @param userOps - Array of UserOperations to validate the signature for.\n * @param signature - The aggregated signature.\n */\n function validateSignatures(\n PackedUserOperation[] calldata userOps,\n bytes calldata signature\n ) external view;\n\n /**\n * Validate signature of a single userOp.\n * This method should be called by bundler after EntryPointSimulation.simulateValidation() returns\n * the aggregator this account uses.\n * First it validates the signature over the userOp. Then it returns data to be used when creating the handleOps.\n * @param userOp - The userOperation received from the user.\n * @return sigForUserOp - The value to put into the signature field of the userOp when calling handleOps.\n * (usually empty, unless account and aggregator support some kind of \"multisig\".\n */\n function validateUserOpSignature(\n PackedUserOperation calldata userOp\n ) external view returns (bytes memory sigForUserOp);\n\n /**\n * Aggregate multiple signatures into a single value.\n * This method is called off-chain to calculate the signature to pass with handleOps()\n * bundler MAY use optimized custom code perform this aggregation.\n * @param userOps - Array of UserOperations to collect the signatures from.\n * @return aggregatedSignature - The aggregated signature.\n */\n function aggregateSignatures(\n PackedUserOperation[] calldata userOps\n ) external view returns (bytes memory aggregatedSignature);\n}\n" + }, + "contracts/Etherspot/interfaces/IEntryPoint.sol": { + "content": "/**\n ** Account-Abstraction (EIP-4337) singleton EntryPoint implementation.\n ** Only one instance required on each chain.\n **/\n// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.7.5;\n\n/* solhint-disable avoid-low-level-calls */\n/* solhint-disable no-inline-assembly */\n/* solhint-disable reason-string */\n\nimport \"./PackedUserOperation.sol\";\nimport \"./IStakeManager.sol\";\nimport \"./IAggregator.sol\";\nimport \"./INonceManager.sol\";\n\ninterface IEntryPoint is IStakeManager, INonceManager {\n /***\n * An event emitted after each successful request.\n * @param userOpHash - Unique identifier for the request (hash its entire content, except signature).\n * @param sender - The account that generates this request.\n * @param paymaster - If non-null, the paymaster that pays for this request.\n * @param nonce - The nonce value from the request.\n * @param success - True if the sender transaction succeeded, false if reverted.\n * @param actualGasCost - Actual amount paid (by account or paymaster) for this UserOperation.\n * @param actualGasUsed - Total gas used by this UserOperation (including preVerification, creation,\n * validation and execution).\n */\n event UserOperationEvent(\n bytes32 indexed userOpHash,\n address indexed sender,\n address indexed paymaster,\n uint256 nonce,\n bool success,\n uint256 actualGasCost,\n uint256 actualGasUsed\n );\n\n /**\n * Account \"sender\" was deployed.\n * @param userOpHash - The userOp that deployed this account. UserOperationEvent will follow.\n * @param sender - The account that is deployed\n * @param factory - The factory used to deploy this account (in the initCode)\n * @param paymaster - The paymaster used by this UserOp\n */\n event AccountDeployed(\n bytes32 indexed userOpHash,\n address indexed sender,\n address factory,\n address paymaster\n );\n\n /**\n * An event emitted if the UserOperation \"callData\" reverted with non-zero length.\n * @param userOpHash - The request unique identifier.\n * @param sender - The sender of this request.\n * @param nonce - The nonce used in the request.\n * @param revertReason - The return bytes from the (reverted) call to \"callData\".\n */\n event UserOperationRevertReason(\n bytes32 indexed userOpHash,\n address indexed sender,\n uint256 nonce,\n bytes revertReason\n );\n\n /**\n * An event emitted if the UserOperation Paymaster's \"postOp\" call reverted with non-zero length.\n * @param userOpHash - The request unique identifier.\n * @param sender - The sender of this request.\n * @param nonce - The nonce used in the request.\n * @param revertReason - The return bytes from the (reverted) call to \"callData\".\n */\n event PostOpRevertReason(\n bytes32 indexed userOpHash,\n address indexed sender,\n uint256 nonce,\n bytes revertReason\n );\n\n /**\n * UserOp consumed more than prefund. The UserOperation is reverted, and no refund is made.\n * @param userOpHash - The request unique identifier.\n * @param sender - The sender of this request.\n * @param nonce - The nonce used in the request.\n */\n event UserOperationPrefundTooLow(\n bytes32 indexed userOpHash,\n address indexed sender,\n uint256 nonce\n );\n\n /**\n * An event emitted by handleOps(), before starting the execution loop.\n * Any event emitted before this event, is part of the validation.\n */\n event BeforeExecution();\n\n /**\n * Signature aggregator used by the following UserOperationEvents within this bundle.\n * @param aggregator - The aggregator used for the following UserOperationEvents.\n */\n event SignatureAggregatorChanged(address indexed aggregator);\n\n /**\n * A custom revert error of handleOps, to identify the offending op.\n * Should be caught in off-chain handleOps simulation and not happen on-chain.\n * Useful for mitigating DoS attempts against batchers or for troubleshooting of factory/account/paymaster reverts.\n * NOTE: If simulateValidation passes successfully, there should be no reason for handleOps to fail on it.\n * @param opIndex - Index into the array of ops to the failed one (in simulateValidation, this is always zero).\n * @param reason - Revert reason. The string starts with a unique code \"AAmn\",\n * where \"m\" is \"1\" for factory, \"2\" for account and \"3\" for paymaster issues,\n * so a failure can be attributed to the correct entity.\n */\n error FailedOp(uint256 opIndex, string reason);\n\n /**\n * A custom revert error of handleOps, to report a revert by account or paymaster.\n * @param opIndex - Index into the array of ops to the failed one (in simulateValidation, this is always zero).\n * @param reason - Revert reason. see FailedOp(uint256,string), above\n * @param inner - data from inner cought revert reason\n * @dev note that inner is truncated to 2048 bytes\n */\n error FailedOpWithRevert(uint256 opIndex, string reason, bytes inner);\n\n error PostOpReverted(bytes returnData);\n\n /**\n * Error case when a signature aggregator fails to verify the aggregated signature it had created.\n * @param aggregator The aggregator that failed to verify the signature\n */\n error SignatureValidationFailed(address aggregator);\n\n // Return value of getSenderAddress.\n error SenderAddressResult(address sender);\n\n // UserOps handled, per aggregator.\n struct UserOpsPerAggregator {\n PackedUserOperation[] userOps;\n // Aggregator address\n IAggregator aggregator;\n // Aggregated signature\n bytes signature;\n }\n\n /**\n * Execute a batch of UserOperations.\n * No signature aggregator is used.\n * If any account requires an aggregator (that is, it returned an aggregator when\n * performing simulateValidation), then handleAggregatedOps() must be used instead.\n * @param ops - The operations to execute.\n * @param beneficiary - The address to receive the fees.\n */\n function handleOps(\n PackedUserOperation[] calldata ops,\n address payable beneficiary\n ) external;\n\n /**\n * Execute a batch of UserOperation with Aggregators\n * @param opsPerAggregator - The operations to execute, grouped by aggregator (or address(0) for no-aggregator accounts).\n * @param beneficiary - The address to receive the fees.\n */\n function handleAggregatedOps(\n UserOpsPerAggregator[] calldata opsPerAggregator,\n address payable beneficiary\n ) external;\n\n /**\n * Generate a request Id - unique identifier for this request.\n * The request ID is a hash over the content of the userOp (except the signature), the entrypoint and the chainid.\n * @param userOp - The user operation to generate the request ID for.\n * @return hash the hash of this UserOperation\n */\n function getUserOpHash(\n PackedUserOperation calldata userOp\n ) external view returns (bytes32);\n\n /**\n * Gas and return values during simulation.\n * @param preOpGas - The gas used for validation (including preValidationGas)\n * @param prefund - The required prefund for this operation\n * @param accountValidationData - returned validationData from account.\n * @param paymasterValidationData - return validationData from paymaster.\n * @param paymasterContext - Returned by validatePaymasterUserOp (to be passed into postOp)\n */\n struct ReturnInfo {\n uint256 preOpGas;\n uint256 prefund;\n uint256 accountValidationData;\n uint256 paymasterValidationData;\n bytes paymasterContext;\n }\n\n /**\n * Returned aggregated signature info:\n * The aggregator returned by the account, and its current stake.\n */\n struct AggregatorStakeInfo {\n address aggregator;\n StakeInfo stakeInfo;\n }\n\n /**\n * Get counterfactual sender address.\n * Calculate the sender contract address that will be generated by the initCode and salt in the UserOperation.\n * This method always revert, and returns the address in SenderAddressResult error\n * @param initCode - The constructor code to be passed into the UserOperation.\n */\n function getSenderAddress(bytes memory initCode) external;\n\n error DelegateAndRevert(bool success, bytes ret);\n\n /**\n * Helper method for dry-run testing.\n * @dev calling this method, the EntryPoint will make a delegatecall to the given data, and report (via revert) the result.\n * The method always revert, so is only useful off-chain for dry run calls, in cases where state-override to replace\n * actual EntryPoint code is less convenient.\n * @param target a target contract to make a delegatecall from entrypoint\n * @param data data to pass to target in a delegatecall\n */\n function delegateAndRevert(address target, bytes calldata data) external;\n}\n" + }, + "contracts/Etherspot/interfaces/INonceManager.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.7.5;\n\ninterface INonceManager {\n /**\n * Return the next nonce for this sender.\n * Within a given key, the nonce values are sequenced (starting with zero, and incremented by one on each userop)\n * But UserOp with different keys can come with arbitrary order.\n *\n * @param sender the account address\n * @param key the high 192 bit of the nonce\n * @return nonce a full nonce to pass for next UserOp with this sender.\n */\n function getNonce(\n address sender,\n uint192 key\n ) external view returns (uint256 nonce);\n\n /**\n * Manually increment the nonce of the sender.\n * This method is exposed just for completeness..\n * Account does NOT need to call it, neither during validation, nor elsewhere,\n * as the EntryPoint will update the nonce regardless.\n * Possible use-case is call it with various keys to \"initialize\" their nonces to one, so that future\n * UserOperations will not pay extra for the first transaction with a given key.\n */\n function incrementNonce(uint192 key) external;\n}\n" + }, + "contracts/Etherspot/interfaces/IPaymaster.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.7.5;\n\nimport \"./PackedUserOperation.sol\";\n\n/**\n * The interface exposed by a paymaster contract, who agrees to pay the gas for user's operations.\n * A paymaster must hold a stake to cover the required entrypoint stake and also the gas for the transaction.\n */\ninterface IPaymaster {\n enum PostOpMode {\n // User op succeeded.\n opSucceeded,\n // User op reverted. Still has to pay for gas.\n opReverted,\n // Only used internally in the EntryPoint (cleanup after postOp reverts). Never calling paymaster with this value\n postOpReverted\n }\n\n /**\n * Payment validation: check if paymaster agrees to pay.\n * Must verify sender is the entryPoint.\n * Revert to reject this request.\n * Note that bundlers will reject this method if it changes the state, unless the paymaster is trusted (whitelisted).\n * The paymaster pre-pays using its deposit, and receive back a refund after the postOp method returns.\n * @param userOp - The user operation.\n * @param userOpHash - Hash of the user's request data.\n * @param maxCost - The maximum cost of this transaction (based on maximum gas and gas price from userOp).\n * @return context - Value to send to a postOp. Zero length to signify postOp is not required.\n * @return validationData - Signature and time-range of this operation, encoded the same as the return\n * value of validateUserOperation.\n * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure,\n * other values are invalid for paymaster.\n * <6-byte> validUntil - last timestamp this operation is valid. 0 for \"indefinite\"\n * <6-byte> validAfter - first timestamp this operation is valid\n * Note that the validation code cannot use block.timestamp (or block.number) directly.\n */\n function validatePaymasterUserOp(\n PackedUserOperation calldata userOp,\n bytes32 userOpHash,\n uint256 maxCost\n ) external returns (bytes memory context, uint256 validationData);\n\n /**\n * Post-operation handler.\n * Must verify sender is the entryPoint.\n * @param mode - Enum with the following options:\n * opSucceeded - User operation succeeded.\n * opReverted - User op reverted. The paymaster still has to pay for gas.\n * postOpReverted - never passed in a call to postOp().\n * @param context - The context value returned by validatePaymasterUserOp\n * @param actualGasCost - Actual gas used so far (without this postOp call).\n * @param actualUserOpFeePerGas - the gas price this UserOp pays. This value is based on the UserOp's maxFeePerGas\n * and maxPriorityFee (and basefee)\n * It is not the same as tx.gasprice, which is what the bundler pays.\n */\n function postOp(\n PostOpMode mode,\n bytes calldata context,\n uint256 actualGasCost,\n uint256 actualUserOpFeePerGas\n ) external;\n}\n" + }, + "contracts/Etherspot/interfaces/IStakeManager.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity >=0.7.5;\n\n/**\n * Manage deposits and stakes.\n * Deposit is just a balance used to pay for UserOperations (either by a paymaster or an account).\n * Stake is value locked for at least \"unstakeDelay\" by the staked entity.\n */\ninterface IStakeManager {\n event Deposited(address indexed account, uint256 totalDeposit);\n\n event Withdrawn(\n address indexed account,\n address withdrawAddress,\n uint256 amount\n );\n\n // Emitted when stake or unstake delay are modified.\n event StakeLocked(\n address indexed account,\n uint256 totalStaked,\n uint256 unstakeDelaySec\n );\n\n // Emitted once a stake is scheduled for withdrawal.\n event StakeUnlocked(address indexed account, uint256 withdrawTime);\n\n event StakeWithdrawn(\n address indexed account,\n address withdrawAddress,\n uint256 amount\n );\n\n /**\n * @param deposit - The entity's deposit.\n * @param staked - True if this entity is staked.\n * @param stake - Actual amount of ether staked for this entity.\n * @param unstakeDelaySec - Minimum delay to withdraw the stake.\n * @param withdrawTime - First block timestamp where 'withdrawStake' will be callable, or zero if already locked.\n * @dev Sizes were chosen so that deposit fits into one cell (used during handleOp)\n * and the rest fit into a 2nd cell (used during stake/unstake)\n * - 112 bit allows for 10^15 eth\n * - 48 bit for full timestamp\n * - 32 bit allows 150 years for unstake delay\n */\n struct DepositInfo {\n uint256 deposit;\n bool staked;\n uint112 stake;\n uint32 unstakeDelaySec;\n uint48 withdrawTime;\n }\n\n // API struct used by getStakeInfo and simulateValidation.\n struct StakeInfo {\n uint256 stake;\n uint256 unstakeDelaySec;\n }\n\n /**\n * Get deposit info.\n * @param account - The account to query.\n * @return info - Full deposit information of given account.\n */\n function getDepositInfo(\n address account\n ) external view returns (DepositInfo memory info);\n\n /**\n * Get account balance.\n * @param account - The account to query.\n * @return - The deposit (for gas payment) of the account.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * Add to the deposit of the given account.\n * @param account - The account to add to.\n */\n function depositTo(address account) external payable;\n\n /**\n * Add to the account's stake - amount and delay\n * any pending unstake is first cancelled.\n * @param _unstakeDelaySec - The new lock duration before the deposit can be withdrawn.\n */\n function addStake(uint32 _unstakeDelaySec) external payable;\n\n /**\n * Attempt to unlock the stake.\n * The value can be withdrawn (using withdrawStake) after the unstake delay.\n */\n function unlockStake() external;\n\n /**\n * Withdraw from the (unlocked) stake.\n * Must first call unlockStake and wait for the unstakeDelay to pass.\n * @param withdrawAddress - The address to send withdrawn value.\n */\n function withdrawStake(address payable withdrawAddress) external;\n\n /**\n * Withdraw from the deposit.\n * @param withdrawAddress - The address to send withdrawn value.\n * @param withdrawAmount - The amount to withdraw.\n */\n function withdrawTo(\n address payable withdrawAddress,\n uint256 withdrawAmount\n ) external;\n}\n" + }, + "contracts/Etherspot/interfaces/PackedUserOperation.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.7.5;\n\n/**\n * User Operation struct\n * @param sender - The sender account of this request.\n * @param nonce - Unique value the sender uses to verify it is not a replay.\n * @param initCode - If set, the account contract will be created by this constructor/\n * @param callData - The method call to execute on this account.\n * @param accountGasLimits - Packed gas limits for validateUserOp and gas limit passed to the callData method call.\n * @param preVerificationGas - Gas not calculated by the handleOps method, but added to the gas paid.\n * Covers batch overhead.\n * @param gasFees - packed gas fields maxPriorityFeePerGas and maxFeePerGas - Same as EIP-1559 gas parameters.\n * @param paymasterAndData - If set, this field holds the paymaster address, verification gas limit, postOp gas limit and paymaster-specific extra data\n * The paymaster will pay for the transaction instead of the sender.\n * @param signature - Sender-verified signature over the entire request, the EntryPoint address and the chain ID.\n */\nstruct 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" + }, "contracts/Factory.sol": { - "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport {PlatformPaymaster} from \"./PlatformPaymaster.sol\";\nimport {Ownable} from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport {Clones} from \"@openzeppelin/contracts/proxy/Clones.sol\";\n\ncontract PlatformAccountFactory is Ownable {\n address public tdocDeployer;\n address public paymasterImplementation;\n\n event PlatformOnboarded(address indexed platformAddress, address indexed paymaster);\n event TdocDeployerUpdated(address indexed newDeployer);\n event ImplementationUpdated(address indexed newImplementation);\n\n constructor(\n address _tdocDeployer,\n address _paymasterImplementation\n ) Ownable(msg.sender) {\n tdocDeployer = _tdocDeployer;\n paymasterImplementation = _paymasterImplementation;\n }\n\n function updateTdocDeployer(address _tdocDeployer) external onlyOwner {\n require(_tdocDeployer != address(0), \"Zero address\");\n tdocDeployer = _tdocDeployer;\n emit TdocDeployerUpdated(_tdocDeployer);\n }\n\n function updatePaymasterImplementation(address _impl) external onlyOwner {\n require(_impl != address(0), \"Zero address\");\n paymasterImplementation = _impl;\n emit ImplementationUpdated(_impl);\n }\n\n function deployPlatformPaymaster(\n address platformAddress,\n uint256 dailyLimit,\n bytes32 salt\n ) external returns (address paymaster) {\n paymaster = Clones.cloneDeterministic(paymasterImplementation, salt);\n PlatformPaymaster(payable(paymaster)).initialize(platformAddress, dailyLimit, tdocDeployer);\n emit PlatformOnboarded(platformAddress, paymaster);\n }\n\n // Address is determined solely by implementation + salt (not by constructor args).\n function computePaymasterAddress(bytes32 salt) external view returns (address) {\n return Clones.predictDeterministicAddress(paymasterImplementation, salt, address(this));\n }\n}\n" + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport {PlatformPaymaster} from \"./PlatformPaymaster.sol\";\nimport {\n IEntryPoint\n} from \"@account-abstraction/contracts/interfaces/IEntryPoint.sol\";\n\ncontract PlatformAccountFactory {\n IEntryPoint public immutable entryPoint;\n\n event PlatformOnboarded(\n address indexed platformAddress,\n address indexed paymaster\n );\n\n constructor(IEntryPoint _entryPoint) {\n entryPoint = _entryPoint;\n }\n\n // ── Deploy paymaster for a platform ───────────────────────────────\n // platformAddress = platform's EOA → paymaster owner\n // dailyLimit = wei per user per day (0 = unlimited)\n // salt = for CREATE2\n // Registries are added after deployment via PlatformPaymaster.addRegistry()\n function deployPlatformPaymaster(\n address platformAddress,\n uint256 dailyLimit,\n bytes32 salt\n ) external returns (address paymaster) {\n paymaster = address(\n new PlatformPaymaster{salt: salt}(\n entryPoint,\n platformAddress,\n dailyLimit\n )\n );\n\n emit PlatformOnboarded(platformAddress, paymaster);\n }\n\n // ── Predict address before deploying ─────────────────────────────\n\n function computePaymasterAddress(\n address platformAddress,\n uint256 dailyLimit,\n bytes32 salt\n ) external view returns (address) {\n bytes32 initHash = keccak256(\n abi.encodePacked(\n type(PlatformPaymaster).creationCode,\n abi.encode(entryPoint, platformAddress, dailyLimit)\n )\n );\n return\n address(\n uint160(\n uint256(\n keccak256(\n abi.encodePacked(\n bytes1(0xff),\n address(this),\n salt,\n initHash\n )\n )\n )\n )\n );\n }\n}\n" + }, + "contracts/IClientRegistry.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\n// Matches the existing deployed registry contract\ninterface IClientRegistry {\n function beneficiary() external view returns (address);\n function holder() external view returns (address);\n}\n" + }, + "contracts/Lock.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.28;\n\n// Uncomment this line to use console.log\n// import \"hardhat/console.sol\";\n\ncontract Lock {\n uint public unlockTime;\n address payable public owner;\n\n event Withdrawal(uint amount, uint when);\n\n constructor(uint _unlockTime) payable {\n require(\n block.timestamp < _unlockTime,\n \"Unlock time should be in the future\"\n );\n\n unlockTime = _unlockTime;\n owner = payable(msg.sender);\n }\n\n function withdraw() public {\n // Uncomment this line, and the import of \"hardhat/console.sol\", to print a log in your terminal\n // console.log(\"Unlock time is %o and block timestamp is %o\", unlockTime, block.timestamp);\n\n require(block.timestamp >= unlockTime, \"You can't withdraw yet\");\n require(msg.sender == owner, \"You aren't the owner\");\n\n emit Withdrawal(address(this).balance, block.timestamp);\n\n owner.transfer(address(this).balance);\n }\n}\n" }, "contracts/PlatformPaymaster.sol": { - "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport \"@account-abstraction/contracts/core/BasePaymaster.sol\";\nimport \"@account-abstraction/contracts/core/Helpers.sol\";\n\ninterface ITDocDeployer {\n function deploy(\n address implementation,\n bytes memory params\n ) external returns (address);\n}\n\ninterface ITradeTrustToken {\n function mint(\n address beneficiary,\n address holder,\n uint256 tokenId,\n bytes calldata remark\n ) external returns (address);\n}\n\ninterface IAccessControl {\n function grantRole(bytes32 role, address account) external;\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n/**\n * PlatformPaymaster — validates by inspecting the target contract in callData.\n *\n * Validation strategy (no third-party storage reads → bundler compliant):\n * 1. Decode userOp.callData → must be execute(address to, uint256, bytes)\n * 2. Check `to` is in authorizedRegistries (paymaster's own storage)\n * 3. Check daily spend (paymaster's own storage — always allowed)\n *\n * Access control is enforced by the Storage contract itself:\n * require(msg.sender == beneficiary || msg.sender == holder)\n * so non-beneficiary/holder callers are rejected at execution time.\n * If the call reverts, _postOp skips the spend update.\n */\ncontract PlatformPaymaster is BasePaymaster {\n bytes4 private constant EXECUTE_SEL =\n bytes4(keccak256(\"execute(address,uint256,bytes)\"));\n bytes4 private constant DEPLOY_REGISTRY_SEL =\n bytes4(keccak256(\"deployRegistry(address,string,string)\"));\n bytes4 private constant MINT_DOCUMENT_SEL =\n bytes4(\n keccak256(\"mintDocument(address,address,address,uint256,bytes)\")\n );\n\n bytes32 private constant DEFAULT_ADMIN_ROLE = bytes32(0);\n\n ITDocDeployer public tdocDeployer;\n\n // Paymaster's own storage — always allowed under ERC-7562\n mapping(address => bool) public authorizedRegistries;\n mapping(address => bool) public authorizedTitleEscrows;\n // remaining deployment credits per user; max 3 per user\n mapping(address => uint256) public userWhitelist;\n // Addresses permitted to call title escrow functions via this paymaster\n mapping(address => bool) public authorizedCallers;\n // Count of documents minted per user\n mapping(address => uint256) public documentsMinted;\n\n // Daily spend tracking — paymaster's own storage, always allowed\n mapping(address => uint256) public dailySpend;\n mapping(address => uint256) public lastReset;\n uint256 public dailyLimit;\n\n event RegistryAdded(address indexed registry);\n event RegistryRemoved(address indexed registry);\n event TitleEscrowLinked(\n address indexed titleEscrow,\n address indexed registry\n );\n event TitleEscrowAdded(address indexed titleEscrow);\n event TitleEscrowRemoved(address indexed titleEscrow);\n event UserWhitelistUpdated(address indexed user, uint256 credits);\n event RegistryDeployed(\n address indexed user,\n address indexed deployed,\n uint256 creditsLeft\n );\n event AuthorizedCallerUpdated(address indexed caller, bool authorized);\n event UserOpSponsored(address indexed user, uint256 gasCost);\n event UserOpRejected(address indexed user, string reason);\n event DailyLimitUpdated(uint256 newLimit);\n\n // Deployed once as the shared implementation; BasePaymaster sets owner = msg.sender.\n // That non-zero owner prevents initialize() from running on the implementation itself.\n constructor(IEntryPoint _entryPoint) BasePaymaster(_entryPoint) {}\n\n // Called by the factory immediately after cloneDeterministic().\n // A fresh clone has all-zero storage, so owner() == address(0) exactly once.\n function initialize(\n address _owner,\n uint256 _dailyLimit,\n address _tdocDeployer\n ) external {\n require(owner() == address(0), \"Already initialized\");\n require(_owner != address(0), \"Zero owner\");\n _transferOwnership(_owner);\n dailyLimit = _dailyLimit;\n tdocDeployer = ITDocDeployer(_tdocDeployer);\n }\n\n // Grant/update deployment credits for a user; credits cannot exceed 3\n function setUserWhitelist(\n address user,\n uint256 credits\n ) external onlyOwner {\n require(user != address(0), \"Zero address\");\n require(credits <= 3, \"Exceeds max credits of 3\");\n userWhitelist[user] = credits;\n emit UserWhitelistUpdated(user, credits);\n }\n\n // add function to remove user from whitelist\n function removeUserFromWhitelist(address user) external onlyOwner {\n require(user != address(0), \"Zero address\");\n userWhitelist[user] = 0;\n emit UserWhitelistUpdated(user, 0);\n }\n\n // Deploys a TDoc clone on behalf of a whitelisted user; consumes one credit.\n // Role setup (atomic, no follow-up txs needed):\n // - msg.sender (EOA) gets DEFAULT_ADMIN_ROLE\n // - paymaster gets MINTER_ROLE + RESTORER_ROLE + ACCEPTER_ROLE\n function deployRegistry(\n address implementation,\n string memory name,\n string memory symbol\n ) external returns (address deployed) {\n require(address(tdocDeployer) != address(0), \"TdocDeployer not set\");\n uint256 credits = userWhitelist[msg.sender];\n require(credits > 0, \"No deployment credits\");\n\n userWhitelist[msg.sender] = credits - 1;\n\n // Paymaster is temporary admin so it can configure roles after deploy\n bytes memory params = abi.encode(name, symbol, address(this));\n deployed = tdocDeployer.deploy(implementation, params);\n\n // Hand admin to the calling EOA\n IAccessControl(deployed).grantRole(DEFAULT_ADMIN_ROLE, msg.sender);\n\n // Paymaster keeps only the operational roles it needs\n // (MINTER_ROLE, RESTORER_ROLE, ACCEPTER_ROLE were granted to address(this) via initialize)\n\n // Relinquish admin — EOA is now sole admin\n IAccessControl(deployed).renounceRole(\n DEFAULT_ADMIN_ROLE,\n address(this)\n );\n\n authorizedRegistries[deployed] = true;\n emit RegistryAdded(deployed);\n emit RegistryDeployed(msg.sender, deployed, credits - 1);\n }\n\n // Mints a TradeTrust document, captures the TitleEscrow, and auto-authorizes it.\n // Paymaster must hold MINTER_ROLE on the registry.\n // Callable gaslessly by userWhitelist users (credits not consumed — only deployRegistry uses credits).\n function mintDocument(\n address registry,\n address beneficiary,\n address holder,\n uint256 tokenId,\n bytes calldata remark\n ) external returns (address titleEscrow) {\n require(authorizedRegistries[registry], \"registry not authorized\");\n\n titleEscrow = ITradeTrustToken(registry).mint(\n beneficiary,\n holder,\n tokenId,\n remark\n );\n\n // Auto-authorize beneficiary and holder to call title escrow functions\n authorizedCallers[beneficiary] = true;\n authorizedCallers[holder] = true;\n\n authorizedTitleEscrows[titleEscrow] = true;\n documentsMinted[msg.sender]++;\n emit TitleEscrowLinked(titleEscrow, registry);\n }\n\n function addRegistry(address registry) external onlyOwner {\n require(registry != address(0), \"Zero address\");\n authorizedRegistries[registry] = true;\n emit RegistryAdded(registry);\n }\n\n function removeRegistry(address registry) external onlyOwner {\n authorizedRegistries[registry] = false;\n emit RegistryRemoved(registry);\n }\n\n function addTitleEscrow(address titleEscrow) external onlyOwner {\n require(titleEscrow != address(0), \"Zero address\");\n authorizedTitleEscrows[titleEscrow] = true;\n emit TitleEscrowAdded(titleEscrow);\n }\n\n function removeTitleEscrow(address titleEscrow) external onlyOwner {\n authorizedTitleEscrows[titleEscrow] = false;\n emit TitleEscrowRemoved(titleEscrow);\n }\n\n function addAuthorizedCaller(address caller) external onlyOwner {\n require(caller != address(0), \"Zero address\");\n authorizedCallers[caller] = true;\n emit AuthorizedCallerUpdated(caller, true);\n }\n\n function removeAuthorizedCaller(address caller) external onlyOwner {\n authorizedCallers[caller] = false;\n emit AuthorizedCallerUpdated(caller, false);\n }\n\n function setDailyLimit(uint256 _dailyLimit) external onlyOwner {\n dailyLimit = _dailyLimit;\n emit DailyLimitUpdated(_dailyLimit);\n }\n\n function _validatePaymasterUserOp(\n PackedUserOperation calldata userOp,\n bytes32, // userOpHash — not needed\n uint256 maxCost\n ) internal override returns (bytes memory context, uint256 validationData) {\n address sender = userOp.sender;\n\n // 1. callData must be long enough for selector + one address arg\n if (userOp.callData.length < 36) {\n emit UserOpRejected(sender, \"callData too short\");\n return (\"\", _packValidationData(true, 0, 0));\n }\n\n // 2. Must call execute(address,uint256,bytes)\n bytes4 sel = bytes4(userOp.callData[:4]);\n if (sel != EXECUTE_SEL) {\n emit UserOpRejected(sender, \"wrong selector\");\n return (\"\", _packValidationData(true, 0, 0));\n }\n\n // 3. Decode target and inner calldata\n (address target, , bytes memory innerData) = abi.decode(\n userOp.callData[4:],\n (address, uint256, bytes)\n );\n\n // Path A — calling an authorized registry or title escrow (regular sponsored op)\n // Only authorizedCallers or the platform owner may be sponsored here.\n if (authorizedRegistries[target] || authorizedTitleEscrows[target]) {\n if (!authorizedCallers[sender] && sender != owner()) {\n emit UserOpRejected(sender, \"caller not authorized\");\n return (\"\", _packValidationData(true, 0, 0));\n }\n if (dailyLimit > 0 && dailySpend[sender] + maxCost > dailyLimit) {\n emit UserOpRejected(sender, \"daily limit exceeded\");\n return (\"\", _packValidationData(true, 0, 0));\n }\n return (\n abi.encode(sender, maxCost, false),\n _packValidationData(false, 0, 0)\n );\n }\n\n // Path B — gasless paymaster call (deployRegistry or mintDocument)\n // Double-spend safe: EntryPoint sequential nonces allow only one\n // pending UserOp per sender in the mempool at a time.\n if (target == address(this)) {\n bytes4 innerSel;\n assembly {\n innerSel := mload(add(innerData, 32))\n }\n\n if (innerSel == DEPLOY_REGISTRY_SEL) {\n // deployRegistry requires whitelist credits — platform-level gate\n if (userWhitelist[sender] == 0) {\n emit UserOpRejected(sender, \"not whitelisted\");\n return (\"\", _packValidationData(true, 0, 0));\n }\n // credits consumed inside deployRegistry; flag as deployment to skip daily spend\n return (\n abi.encode(sender, maxCost, true),\n _packValidationData(false, 0, 0)\n );\n }\n\n if (innerSel == MINT_DOCUMENT_SEL) {\n // mintDocument: registry enforces MINTER_ROLE — no extra whitelist needed\n return (\n abi.encode(sender, maxCost, false),\n _packValidationData(false, 0, 0)\n );\n }\n\n emit UserOpRejected(sender, \"unauthorized paymaster call\");\n return (\"\", _packValidationData(true, 0, 0));\n }\n\n emit UserOpRejected(sender, \"unauthorized target\");\n return (\"\", _packValidationData(true, 0, 0));\n }\n\n function _postOp(\n PostOpMode mode,\n bytes calldata context,\n uint256 actualGasCost,\n uint256 /*actualUserOpFeePerGas*/\n ) internal override {\n if (mode == PostOpMode.postOpReverted) return;\n\n (address sender, , bool isDeployment) = abi.decode(\n context,\n (address, uint256, bool)\n );\n\n // Deployment ops are credit-gated; skip daily spend tracking for them\n if (!isDeployment) {\n if (block.timestamp > lastReset[sender] + 1 days) {\n dailySpend[sender] = 0;\n lastReset[sender] = block.timestamp;\n }\n dailySpend[sender] += actualGasCost;\n }\n\n emit UserOpSponsored(sender, actualGasCost);\n }\n\n // v0.8 contracts on Etherspot EntryPoint — skip interface mismatch check\n function _validateEntryPointInterface(IEntryPoint) internal pure override {}\n\n receive() external payable {\n deposit();\n }\n\n function getUserDailySpend(\n address user\n ) external view returns (uint256 spent, uint256 limit, uint256 resetsAt) {\n spent = dailySpend[user];\n limit = dailyLimit;\n resetsAt = lastReset[user] + 1 days;\n }\n}\n" + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.28;\n\nimport \"@account-abstraction/contracts/core/BasePaymaster.sol\";\nimport \"@account-abstraction/contracts/core/Helpers.sol\";\n\ninterface ITDocDeployer {\n function deploy(\n address implementation,\n bytes memory params\n ) external returns (address);\n}\n\ninterface ITradeTrustToken {\n function mint(\n address beneficiary,\n address holder,\n uint256 tokenId,\n bytes calldata remark\n ) external returns (address);\n}\n\ninterface IAccessControl {\n function grantRole(bytes32 role, address account) external;\n function renounceRole(bytes32 role, address callerConfirmation) external;\n}\n\n/**\n * PlatformPaymaster — validates by inspecting the target contract in callData.\n *\n * Validation strategy (no third-party storage reads → bundler compliant):\n * 1. Decode userOp.callData → must be execute(address to, uint256, bytes)\n * 2. Check `to` is in authorizedRegistries (paymaster's own storage)\n * 3. Check daily spend (paymaster's own storage — always allowed)\n *\n * Access control is enforced by the Storage contract itself:\n * require(msg.sender == beneficiary || msg.sender == holder)\n * so non-beneficiary/holder callers are rejected at execution time.\n * If the call reverts, _postOp skips the spend update.\n */\ncontract PlatformPaymaster is BasePaymaster {\n bytes4 private constant EXECUTE_SEL =\n bytes4(keccak256(\"execute(address,uint256,bytes)\"));\n bytes4 private constant DEPLOY_REGISTRY_SEL =\n bytes4(keccak256(\"deployRegistry(address,string,string)\"));\n bytes4 private constant MINT_DOCUMENT_SEL =\n bytes4(keccak256(\"mintDocument(address,address,address,uint256,bytes)\"));\n\n bytes32 private constant DEFAULT_ADMIN_ROLE = bytes32(0);\n\n ITDocDeployer public tdocDeployer;\n\n // Paymaster's own storage — always allowed under ERC-7562\n mapping(address => bool) public authorizedRegistries;\n mapping(address => bool) public authorizedTitleEscrows;\n // remaining deployment credits per user; max 3 per user\n mapping(address => uint256) public userWhitelist;\n\n // Daily spend tracking — paymaster's own storage, always allowed\n mapping(address => uint256) public dailySpend;\n mapping(address => uint256) public lastReset;\n uint256 public dailyLimit;\n\n event RegistryAdded(address indexed registry);\n event RegistryRemoved(address indexed registry);\n event TitleEscrowLinked(address indexed titleEscrow, address indexed registry);\n event UserWhitelistUpdated(address indexed user, uint256 credits);\n event RegistryDeployed(\n address indexed user,\n address indexed deployed,\n uint256 creditsLeft\n );\n event UserOpSponsored(address indexed user, uint256 gasCost);\n event UserOpRejected(address indexed user, string reason);\n event DailyLimitUpdated(uint256 newLimit);\n\n constructor(\n IEntryPoint _entryPoint,\n address _owner,\n uint256 _dailyLimit\n ) BasePaymaster(_entryPoint) {\n _transferOwnership(_owner);\n dailyLimit = _dailyLimit;\n }\n\n function setTdocDeployer(address _tdocDeployer) external onlyOwner {\n require(_tdocDeployer != address(0), \"Zero address\");\n tdocDeployer = ITDocDeployer(_tdocDeployer);\n }\n\n // Grant/update deployment credits for a user; credits cannot exceed 3\n function setUserWhitelist(\n address user,\n uint256 credits\n ) external onlyOwner {\n require(user != address(0), \"Zero address\");\n require(credits <= 3, \"Exceeds max credits of 3\");\n userWhitelist[user] = credits;\n emit UserWhitelistUpdated(user, credits);\n }\n\n // Deploys a TDoc clone on behalf of a whitelisted user; consumes one credit.\n // Role setup (atomic, no follow-up txs needed):\n // - msg.sender (EOA) gets DEFAULT_ADMIN_ROLE\n // - paymaster gets MINTER_ROLE + RESTORER_ROLE + ACCEPTER_ROLE\n function deployRegistry(\n address implementation,\n string memory name,\n string memory symbol\n ) external returns (address deployed) {\n require(address(tdocDeployer) != address(0), \"TdocDeployer not set\");\n uint256 credits = userWhitelist[msg.sender];\n require(credits > 0, \"No deployment credits\");\n\n userWhitelist[msg.sender] = credits - 1;\n\n // Paymaster is temporary admin so it can configure roles after deploy\n bytes memory params = abi.encode(name, symbol, address(this));\n deployed = tdocDeployer.deploy(implementation, params);\n\n // Hand admin to the calling EOA\n IAccessControl(deployed).grantRole(DEFAULT_ADMIN_ROLE, msg.sender);\n\n // Paymaster keeps only the operational roles it needs\n // (MINTER_ROLE, RESTORER_ROLE, ACCEPTER_ROLE were granted to address(this) via initialize)\n\n // Relinquish admin — EOA is now sole admin\n IAccessControl(deployed).renounceRole(DEFAULT_ADMIN_ROLE, address(this));\n\n authorizedRegistries[deployed] = true;\n emit RegistryAdded(deployed);\n emit RegistryDeployed(msg.sender, deployed, credits - 1);\n }\n\n // Mints a TradeTrust document, captures the TitleEscrow, and auto-authorizes it.\n // Paymaster must hold MINTER_ROLE on the registry.\n // Callable gaslessly by userWhitelist users (credits not consumed — only deployRegistry uses credits).\n function mintDocument(\n address registry,\n address beneficiary,\n address holder,\n uint256 tokenId,\n bytes calldata remark\n ) external returns (address titleEscrow) {\n require(authorizedRegistries[registry], \"registry not authorized\");\n require(userWhitelist[msg.sender] > 0, \"not whitelisted\");\n\n titleEscrow = ITradeTrustToken(registry).mint(beneficiary, holder, tokenId, remark);\n\n authorizedTitleEscrows[titleEscrow] = true;\n emit TitleEscrowLinked(titleEscrow, registry);\n }\n\n function addRegistry(address registry) external onlyOwner {\n require(registry != address(0), \"Zero address\");\n authorizedRegistries[registry] = true;\n emit RegistryAdded(registry);\n }\n\n function removeRegistry(address registry) external onlyOwner {\n authorizedRegistries[registry] = false;\n emit RegistryRemoved(registry);\n }\n\n function setDailyLimit(uint256 _dailyLimit) external onlyOwner {\n dailyLimit = _dailyLimit;\n emit DailyLimitUpdated(_dailyLimit);\n }\n\n function _validatePaymasterUserOp(\n PackedUserOperation calldata userOp,\n bytes32, // userOpHash — not needed\n uint256 maxCost\n ) internal override returns (bytes memory context, uint256 validationData) {\n address sender = userOp.sender;\n\n // 1. callData must be long enough for selector + one address arg\n if (userOp.callData.length < 36) {\n emit UserOpRejected(sender, \"callData too short\");\n return (\"\", _packValidationData(true, 0, 0));\n }\n\n // 2. Must call execute(address,uint256,bytes)\n bytes4 sel = bytes4(userOp.callData[:4]);\n if (sel != EXECUTE_SEL) {\n emit UserOpRejected(sender, \"wrong selector\");\n return (\"\", _packValidationData(true, 0, 0));\n }\n\n // 3. Decode target and inner calldata\n (address target, , bytes memory innerData) = abi.decode(\n userOp.callData[4:],\n (address, uint256, bytes)\n );\n\n // Path A — calling an authorized registry or title escrow (regular sponsored op)\n if (authorizedRegistries[target] || authorizedTitleEscrows[target]) {\n if (dailyLimit > 0 && dailySpend[sender] + maxCost > dailyLimit) {\n emit UserOpRejected(sender, \"daily limit exceeded\");\n return (\"\", _packValidationData(true, 0, 0));\n }\n return (abi.encode(sender, maxCost, false), _packValidationData(false, 0, 0));\n }\n\n // Path B — gasless paymaster call (deployRegistry or mintDocument)\n // Double-spend safe: EntryPoint sequential nonces allow only one\n // pending UserOp per sender in the mempool at a time.\n if (target == address(this)) {\n if (userWhitelist[sender] == 0) {\n emit UserOpRejected(sender, \"not whitelisted\");\n return (\"\", _packValidationData(true, 0, 0));\n }\n bytes4 innerSel;\n assembly { innerSel := mload(add(innerData, 32)) }\n\n if (innerSel == DEPLOY_REGISTRY_SEL) {\n // credits consumed inside deployRegistry; flag as deployment to skip daily spend\n return (abi.encode(sender, maxCost, true), _packValidationData(false, 0, 0));\n }\n if (innerSel == MINT_DOCUMENT_SEL) {\n // credits NOT consumed; track daily spend normally\n return (abi.encode(sender, maxCost, false), _packValidationData(false, 0, 0));\n }\n\n emit UserOpRejected(sender, \"unauthorized paymaster call\");\n return (\"\", _packValidationData(true, 0, 0));\n }\n\n emit UserOpRejected(sender, \"unauthorized target\");\n return (\"\", _packValidationData(true, 0, 0));\n }\n\n function _postOp(\n PostOpMode mode,\n bytes calldata context,\n uint256 actualGasCost,\n uint256 /*actualUserOpFeePerGas*/\n ) internal override {\n if (mode == PostOpMode.postOpReverted) return;\n\n (address sender, , bool isDeployment) = abi.decode(context, (address, uint256, bool));\n\n // Deployment ops are credit-gated; skip daily spend tracking for them\n if (!isDeployment) {\n if (block.timestamp > lastReset[sender] + 1 days) {\n dailySpend[sender] = 0;\n lastReset[sender] = block.timestamp;\n }\n dailySpend[sender] += actualGasCost;\n }\n\n emit UserOpSponsored(sender, actualGasCost);\n }\n\n // v0.8 contracts on Etherspot EntryPoint — skip interface mismatch check\n function _validateEntryPointInterface(IEntryPoint) internal pure override {}\n\n receive() external payable {\n deposit();\n }\n\n function getUserDailySpend(\n address user\n ) external view returns (uint256 spent, uint256 limit, uint256 resetsAt) {\n spent = dailySpend[user];\n limit = dailyLimit;\n resetsAt = lastReset[user] + 1 days;\n }\n}\n" + }, + "contracts/Storage.sol": { + "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.28;\n\ncontract Storage {\n struct Item {\n uint id;\n string data;\n uint256 timestamp;\n bool exists;\n }\n\n address public beneficiary;\n address public holder;\n\n mapping(uint => Item) private items;\n uint private itemCount = 0;\n\n event ItemCreated(uint indexed id, string data, uint256 timestamp);\n event ItemUpdated(uint indexed id, string data, uint256 timestamp);\n event ItemDeleted(uint indexed id);\n event ItemRead(uint indexed id, string data, uint256 timestamp);\n\n constructor(address _beneficiary, address _holder) {\n beneficiary = _beneficiary;\n holder = _holder;\n }\n\n // CREATE\n function create(string memory _data) public returns (uint) {\n require(\n msg.sender == beneficiary || msg.sender == holder,\n \"Storage: only beneficiary or holder can create items\"\n );\n require(bytes(_data).length > 0, \"Storage: data cannot be empty\");\n\n itemCount++;\n items[itemCount] = Item({\n id: itemCount,\n data: _data,\n timestamp: block.timestamp,\n exists: true\n });\n\n emit ItemCreated(itemCount, _data, block.timestamp);\n return itemCount;\n }\n\n // READ\n function read(uint _id) public returns (string memory) {\n require(\n msg.sender == beneficiary || msg.sender == holder,\n \"Storage: only beneficiary or holder can create items\"\n );\n require(_id > 0 && _id <= itemCount, \"Storage: item does not exist\");\n require(items[_id].exists, \"Storage: item has been deleted\");\n\n Item memory item = items[_id];\n emit ItemRead(_id, item.data, item.timestamp);\n return item.data;\n }\n\n // UPDATE\n function update(uint _id, string memory _newData) public {\n require(\n msg.sender == beneficiary || msg.sender == holder,\n \"Storage: only beneficiary or holder can create items\"\n );\n require(_id > 0 && _id <= itemCount, \"Storage: item does not exist\");\n require(items[_id].exists, \"Storage: item has been deleted\");\n require(bytes(_newData).length > 0, \"Storage: data cannot be empty\");\n\n items[_id].data = _newData;\n items[_id].timestamp = block.timestamp;\n\n emit ItemUpdated(_id, _newData, block.timestamp);\n }\n\n // DELETE\n function remove(uint _id) public {\n require(\n msg.sender == beneficiary || msg.sender == holder,\n \"Storage: only beneficiary or holder can create items\"\n );\n require(_id > 0 && _id <= itemCount, \"Storage: item does not exist\");\n require(items[_id].exists, \"Storage: item already deleted\");\n\n items[_id].exists = false;\n emit ItemDeleted(_id);\n }\n\n // Helper function to check if item exists\n function exists(uint _id) public view returns (bool) {\n return _id > 0 && _id <= itemCount && items[_id].exists;\n }\n\n // Get total item count\n function getItemCount() public view returns (uint) {\n return itemCount;\n }\n}\n" + }, + "contracts/TestEntryPoint.sol": { + "content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity ^0.8.28;\n\n// Imported here so Hardhat compiles the EntryPoint and makes it available\n// as a deployable artifact in tests. Not used in production.\nimport \"@account-abstraction/contracts/core/EntryPoint.sol\";\n" } }, "settings": { From d4e93428710377422efe3b05019ec46bceaf05fe Mon Sep 17 00:00:00 2001 From: Rishabh Singh Date: Wed, 12 Aug 2026 11:28:18 +0530 Subject: [PATCH 3/5] fix: update zero add restriction --- contracts/Factory.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/Factory.sol b/contracts/Factory.sol index 2d47870..e89e617 100644 --- a/contracts/Factory.sol +++ b/contracts/Factory.sol @@ -21,6 +21,8 @@ contract PlatformAccountFactory is Ownable { address _tdocDeployer, address _paymasterImplementation ) Ownable(msg.sender) { + require(_tdocDeployer != address(0), "Zero address"); + require(_paymasterImplementation != address(0), "Zero address"); tdocDeployer = _tdocDeployer; paymasterImplementation = _paymasterImplementation; } From 9e067ef3f3912405d65bd25f3d43f3393b1fadb1 Mon Sep 17 00:00:00 2001 From: RishabhS7 <59636880+RishabhS7@users.noreply.github.com> Date: Wed, 12 Aug 2026 11:30:41 +0530 Subject: [PATCH 4/5] fix: role-access Fix/role access --- .env.example | 70 + .eslintignore | 6 + .eslintrc.json | 43 + .github/workflows/linters.yml | 28 + .github/workflows/pull_requests.yml | 30 + .github/workflows/release.yml | 53 + .github/workflows/tests.yml | 31 + .gitignore | 2 + 7702Frontend/.env.example | 11 - 7702Frontend/index.html | 12 - 7702Frontend/package-lock.json | 3068 ---- 7702Frontend/package.json | 28 - 7702Frontend/postcss.config.js | 6 - 7702Frontend/src/App.tsx | 84 - .../src/components/DelegationPanel.tsx | 110 - .../src/components/PaymasterAdminPanel.tsx | 314 - .../src/components/PaymasterPanel.tsx | 270 - 7702Frontend/src/components/RegistryPanel.tsx | 336 - 7702Frontend/src/components/SignerPanel.tsx | 2 - 7702Frontend/src/components/StoragePanel.tsx | 276 - .../src/components/TitleEscrowPanel.tsx | 246 - 7702Frontend/src/components/TrustVCPanel.tsx | 379 - 7702Frontend/src/components/WalletConnect.tsx | 91 - 7702Frontend/src/index.css | 42 - 7702Frontend/src/lib/abis.ts | 224 - 7702Frontend/src/lib/constants.ts | 23 - 7702Frontend/src/lib/pimlico.ts | 106 - 7702Frontend/src/main.tsx | 10 - 7702Frontend/src/vite-env.d.ts | 8 - 7702Frontend/tailwind.config.js | 12 - 7702Frontend/tsconfig.json | 20 - 7702Frontend/vite.config.ts | 9 - EIP7702_METAMASK_ARCHITECTURE.md | 120 - PIMLICO_EIP7702_DOCS.md | 315 - README.md | 161 +- commitlint.config.js | 4 + contracts/Etherspot/BasePaymaster.sol | 162 - contracts/Etherspot/EtherspotPaymaster.sol | 86 - contracts/Etherspot/core/Helpers.sol | 102 - contracts/Etherspot/core/UserOperationLib.sol | 187 - .../Etherspot/interfaces/IAggregator.sol | 44 - .../Etherspot/interfaces/IEntryPoint.sol | 223 - .../Etherspot/interfaces/INonceManager.sol | 28 - contracts/Etherspot/interfaces/IPaymaster.sol | 63 - .../Etherspot/interfaces/IStakeManager.sol | 111 - .../interfaces/PackedUserOperation.sol | 28 - contracts/Factory.sol | 85 +- contracts/Lock.sol | 34 - contracts/PlatformPaymaster.sol | 135 +- contracts/mocks/MockEntryPoint.sol | 25 + contracts/mocks/MockRegistry.sol | 59 + contracts/mocks/MockTdocDeployer.sol | 17 + hardhat.config.ts | 6 + ignition/modules/Lock.ts | 21 - interactionContrats/TitleEscrow.sol | 378 - interactionContrats/TitleEscrowFactory.sol | 45 - interactionContrats/TradeTrustToken.sol | 47 - interactionContrats/base/RegistryAccess.sol | 43 - interactionContrats/base/SBTUpgradeable.sol | 341 - interactionContrats/base/TradeTrustSBT.sol | 76 - .../base/TradeTrustTokenBase.sol | 101 - .../base/TradeTrustTokenBaseURI.sol | 45 - .../base/TradeTrustTokenBurnable.sol | 58 - .../base/TradeTrustTokenMintable.sol | 56 - .../base/TradeTrustTokenRestorable.sol | 41 - interactionContrats/utils/SigHelper.sol | 47 - interactionContrats/utils/TDocDeployer.sol | 67 - package-lock.json | 15241 ++++++++++++---- package.json | 66 +- scripts/deployEIP7702.ts | 70 + scripts/deployFactory.ts | 69 + scripts/deployImplementation.ts | 69 + scripts/deployPlatformPaymaster.ts | 83 +- scripts/deployRegistryGasless.ts | 97 +- scripts/generate-abis.ts | 76 + scripts/lib/network.ts | 43 + scripts/mintDocumentGasless.ts | 123 +- scripts/stakeOwnerOnEP9.ts | 151 - scripts/stakePlatformPaymaster.ts | 62 +- scripts/trFunctions/_setup.ts | 97 +- scripts/trFunctions/nominate.ts | 6 +- .../trFunctions/rejectTransferBeneficiary.ts | 6 +- scripts/trFunctions/rejectTransferHolder.ts | 6 +- scripts/trFunctions/rejectTransferOwners.ts | 6 +- scripts/trFunctions/returnToIssuer.ts | 6 +- scripts/trFunctions/shred.ts | 6 +- scripts/trFunctions/transferBeneficiary.ts | 6 +- scripts/trFunctions/transferOwners.ts | 6 +- src/abis/eip7702-implementation.ts | 301 + src/abis/index.ts | 5 + src/abis/platform-account-factory.ts | 262 + src/abis/platform-paymaster.ts | 913 + src/constants/index.ts | 10 + src/index.ts | 2 + test/Factory.ts | 268 + test/Lock.ts | 134 - test/PlatformPaymaster.ts | 381 + tsconfig.build.json | 12 + tsup.config.ts | 12 + upload.json | 98 +- 100 files changed, 15417 insertions(+), 12587 deletions(-) create mode 100644 .env.example create mode 100644 .eslintignore create mode 100644 .eslintrc.json create mode 100644 .github/workflows/linters.yml create mode 100644 .github/workflows/pull_requests.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/tests.yml delete mode 100644 7702Frontend/.env.example delete mode 100644 7702Frontend/index.html delete mode 100644 7702Frontend/package-lock.json delete mode 100644 7702Frontend/package.json delete mode 100644 7702Frontend/postcss.config.js delete mode 100644 7702Frontend/src/App.tsx delete mode 100644 7702Frontend/src/components/DelegationPanel.tsx delete mode 100644 7702Frontend/src/components/PaymasterAdminPanel.tsx delete mode 100644 7702Frontend/src/components/PaymasterPanel.tsx delete mode 100644 7702Frontend/src/components/RegistryPanel.tsx delete mode 100644 7702Frontend/src/components/SignerPanel.tsx delete mode 100644 7702Frontend/src/components/StoragePanel.tsx delete mode 100644 7702Frontend/src/components/TitleEscrowPanel.tsx delete mode 100644 7702Frontend/src/components/TrustVCPanel.tsx delete mode 100644 7702Frontend/src/components/WalletConnect.tsx delete mode 100644 7702Frontend/src/index.css delete mode 100644 7702Frontend/src/lib/abis.ts delete mode 100644 7702Frontend/src/lib/constants.ts delete mode 100644 7702Frontend/src/lib/pimlico.ts delete mode 100644 7702Frontend/src/main.tsx delete mode 100644 7702Frontend/src/vite-env.d.ts delete mode 100644 7702Frontend/tailwind.config.js delete mode 100644 7702Frontend/tsconfig.json delete mode 100644 7702Frontend/vite.config.ts delete mode 100644 EIP7702_METAMASK_ARCHITECTURE.md delete mode 100644 PIMLICO_EIP7702_DOCS.md create mode 100644 commitlint.config.js delete mode 100644 contracts/Etherspot/BasePaymaster.sol delete mode 100644 contracts/Etherspot/EtherspotPaymaster.sol delete mode 100644 contracts/Etherspot/core/Helpers.sol delete mode 100644 contracts/Etherspot/core/UserOperationLib.sol delete mode 100644 contracts/Etherspot/interfaces/IAggregator.sol delete mode 100644 contracts/Etherspot/interfaces/IEntryPoint.sol delete mode 100644 contracts/Etherspot/interfaces/INonceManager.sol delete mode 100644 contracts/Etherspot/interfaces/IPaymaster.sol delete mode 100644 contracts/Etherspot/interfaces/IStakeManager.sol delete mode 100644 contracts/Etherspot/interfaces/PackedUserOperation.sol delete mode 100644 contracts/Lock.sol create mode 100644 contracts/mocks/MockEntryPoint.sol create mode 100644 contracts/mocks/MockRegistry.sol create mode 100644 contracts/mocks/MockTdocDeployer.sol delete mode 100644 ignition/modules/Lock.ts delete mode 100644 interactionContrats/TitleEscrow.sol delete mode 100644 interactionContrats/TitleEscrowFactory.sol delete mode 100644 interactionContrats/TradeTrustToken.sol delete mode 100644 interactionContrats/base/RegistryAccess.sol delete mode 100644 interactionContrats/base/SBTUpgradeable.sol delete mode 100644 interactionContrats/base/TradeTrustSBT.sol delete mode 100644 interactionContrats/base/TradeTrustTokenBase.sol delete mode 100644 interactionContrats/base/TradeTrustTokenBaseURI.sol delete mode 100644 interactionContrats/base/TradeTrustTokenBurnable.sol delete mode 100644 interactionContrats/base/TradeTrustTokenMintable.sol delete mode 100644 interactionContrats/base/TradeTrustTokenRestorable.sol delete mode 100644 interactionContrats/utils/SigHelper.sol delete mode 100644 interactionContrats/utils/TDocDeployer.sol create mode 100644 scripts/deployEIP7702.ts create mode 100644 scripts/deployFactory.ts create mode 100644 scripts/deployImplementation.ts create mode 100644 scripts/generate-abis.ts create mode 100644 scripts/lib/network.ts delete mode 100644 scripts/stakeOwnerOnEP9.ts create mode 100644 src/abis/eip7702-implementation.ts create mode 100644 src/abis/index.ts create mode 100644 src/abis/platform-account-factory.ts create mode 100644 src/abis/platform-paymaster.ts create mode 100644 src/constants/index.ts create mode 100644 src/index.ts create mode 100644 test/Factory.ts delete mode 100644 test/Lock.ts create mode 100644 test/PlatformPaymaster.ts create mode 100644 tsconfig.build.json create mode 100644 tsup.config.ts diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..2e2ba52 --- /dev/null +++ b/.env.example @@ -0,0 +1,70 @@ +# ─── Wallets ────────────────────────────────────────────────────────────────── +# Deployer wallet — pays gas for contract deployments and delegation txs +PRIVATE_KEY=0xyour_deployer_private_key + +# Secondary wallet (optional — used for testing with a second account) +PRIVATE_KEY2=0xyour_second_private_key + +# Platform owner / whitelisted user — signs UserOps (needs no ETH for gasless ops) +OWNER_PRIVATE_KEY=0xyour_owner_private_key + +# ─── RPC Endpoints ──────────────────────────────────────────────────────────── +# Get free endpoints at https://infura.io or https://alchemy.com +SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/your_infura_project_id +AMOY_RPC_URL=https://polygon-amoy.infura.io/v3/your_infura_project_id + +# ─── Bundler ────────────────────────────────────────────────────────────────── +# Get a free Pimlico API key at https://dashboard.pimlico.io +PIMLICO_API_KEY=pim_your_pimlico_api_key + +# ─── EntryPoint ─────────────────────────────────────────────────────────────── +# Canonical EntryPoint v0.8 — same address on all supported chains +ENTRY_POINT=0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108 + +# ─── Document / Token Config ────────────────────────────────────────────────── +# Used by mintDocumentGasless.ts +TOKEN_ID=0xyour_document_hash_as_uint256 +TOKEN_NAME=MyRegistry +TOKEN_SYMBOL=MYR +REMARK=optional remark text +BENEFICIARY_ADDRESS=0xbeneficiary_wallet_address +HOLDER_ADDRESS=0xholder_wallet_address +NOMINEE_ADDR=0xnominee_wallet_address +NEW_HOLDER_ADDR=0xnew_holder_wallet_address + +# ─── Sepolia Deployments ────────────────────────────────────────────────────── +# Filled in automatically by deploy scripts — run in order: +# 1. npx hardhat run scripts/deployEIP7702.ts --network sepolia +# 2. npx hardhat run scripts/deployImplementation.ts --network sepolia +# 3. npx hardhat run scripts/deployFactory.ts --network sepolia +# 4. npx hardhat run scripts/deployPlatformPaymaster.ts --network sepolia +# 5. npx hardhat run scripts/stakePlatformPaymaster.ts --network sepolia + +EIP7702_IMPL_ADDRESS_SEPOLIA=0x_filled_by_deployEIP7702 +PAYMASTER_IMPLEMENTATION_SEPOLIA=0x_filled_by_deployImplementation +FACTORY_ADDRESS_SEPOLIA=0x_filled_by_deployFactory +PAYMASTER_ADDRESS_SEPOLIA=0x_filled_by_deployPlatformPaymaster + +# TrustVC infrastructure on Sepolia (pre-deployed — do not change) +TDOC_DEPLOYER_ADDRESS_SEPOLIA=0x64bc665056DC8bE4092e569ED13a7F273Be28cD2 +TDOC_IMPLEMENTATION_SEPOLIA=0x45c382574bb1B9C432a2e100Ab2086A4EAcB73Fd + +# Filled in after running deployRegistryGasless.ts / mintDocumentGasless.ts +REGISTRY_ADDRESS_SEPOLIA=0x_filled_after_deployRegistry +TITLE_ESCROW_ADDRESS_SEPOLIA=0x_filled_after_mintDocument + +# ─── Polygon Amoy Deployments ───────────────────────────────────────────────── +# Same deploy order as above but with --network amoy and NETWORK=amoy + +EIP7702_IMPL_ADDRESS_AMOY=0x_filled_by_deployEIP7702 +PAYMASTER_IMPLEMENTATION_AMOY=0x_filled_by_deployImplementation +FACTORY_ADDRESS_AMOY=0x_filled_by_deployFactory +PAYMASTER_ADDRESS_AMOY=0x_filled_by_deployPlatformPaymaster + +# TrustVC infrastructure on Amoy (pre-deployed — do not change) +TDOC_DEPLOYER_ADDRESS_AMOY=0xfcafea839e576967b96ad1FBFB52b5CA26cd1D25 +TDOC_IMPLEMENTATION_AMOY=0x_tdoc_implementation_on_amoy + +# Filled in after running gasless scripts with NETWORK=amoy +REGISTRY_ADDRESS_AMOY=0x_filled_after_deployRegistry +TITLE_ESCROW_ADDRESS_AMOY=0x_filled_after_mintDocument diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..ba46a50 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +dist +artifacts +cache +src/abis +node_modules +7702Frontend diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..ad7eecd --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,43 @@ +{ + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "./tsconfig.json", + "ecmaVersion": 2020, + "sourceType": "module" + }, + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "env": { + "node": true, + "mocha": true + }, + "rules": { + "no-console": "off", + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], + "import/no-extraneous-dependencies": "off" + }, + "overrides": [ + { + "files": ["test/**/*.ts"], + "env": { "mocha": true }, + "rules": { + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-unused-expressions": "off", + "no-unused-expressions": "off" + } + }, + { + "files": ["scripts/**/*.ts"], + "rules": { + "@typescript-eslint/no-explicit-any": "off" + } + } + ], + "ignorePatterns": ["dist", "artifacts", "cache", "src/abis", "7702Frontend", "node_modules"] +} diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml new file mode 100644 index 0000000..9c9a7ca --- /dev/null +++ b/.github/workflows/linters.yml @@ -0,0 +1,28 @@ +on: + workflow_call: + +env: + NODE_ENV: ci + +name: "Linters" + +jobs: + lint: + name: Code Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24.x + - run: npm ci --ignore-scripts + - run: npm run lint + + commit-lint: + name: Commit Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Commit Lint Dependencies + run: npm install @commitlint/config-conventional + - uses: JulienKode/pull-request-name-linter-action@v0.5.0 diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml new file mode 100644 index 0000000..deb9e9e --- /dev/null +++ b/.github/workflows/pull_requests.yml @@ -0,0 +1,30 @@ +on: + pull_request: + types: [opened, reopened, synchronize] + +env: + NODE_ENV: ci + +name: "Pull Requests" + +jobs: + tests: + name: Tests + uses: ./.github/workflows/tests.yml + + linters: + name: Linters + uses: ./.github/workflows/linters.yml + + eslint-review: + name: ESLint Review + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - uses: actions/checkout@v4 + - uses: reviewdog/action-eslint@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + eslint_flags: "src scripts test --ext .ts" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1f351d1 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,53 @@ +name: Release + +on: + push: + branches: + - main + - dev + +env: + NODE_ENV: ci + +jobs: + tests: + name: Tests + uses: ./.github/workflows/tests.yml + + linters: + name: Linters + uses: ./.github/workflows/linters.yml + + release: + name: Publish Release + runs-on: ubuntu-latest + needs: [tests, linters] + permissions: + contents: write + packages: write + id-token: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Cache node modules + uses: actions/cache@v4 + with: + path: ~/node_modules + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + + - uses: actions/setup-node@v4 + with: + node-version: 24 + registry-url: https://registry.npmjs.org/ + + - run: npm ci + - run: npm run build + - run: npm run semantic-release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.npm_token }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..e4eb331 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,31 @@ +on: + workflow_call: + +env: + NODE_ENV: ci + +name: "Tests" + +jobs: + run-tests: + name: Run Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24.x + - run: npm ci --ignore-scripts + - run: npm run build:sol + - run: npm test + + test-build: + name: Test Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24.x + - run: npm ci --ignore-scripts + - run: npm run build diff --git a/.gitignore b/.gitignore index e8c12ff..5ad699b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,11 @@ node_modules .env +/dist # Hardhat files /cache /artifacts +/7702Frontend # TypeChain files /typechain diff --git a/7702Frontend/.env.example b/7702Frontend/.env.example deleted file mode 100644 index d90c84e..0000000 --- a/7702Frontend/.env.example +++ /dev/null @@ -1,11 +0,0 @@ -# Copy this to .env and fill in values from the root .env - -VITE_PIMLICO_API_KEY=your_pimlico_api_key -VITE_SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/your_key - -# From root .env -VITE_EIP7702_IMPL_ADDRESS=0xa46EC3920Ac5fc54F4bA33185A91ae250aDF59B8 -VITE_PAYMASTER_ADDRESS=0xB6977A2942A775A3C62a25912867700ECEb7F9Cc -VITE_REGISTRY_ADDRESS=0x22B8eB51f834e48a61874015C872C19FF16A7E44 -VITE_TITLE_ESCROW_ADDRESS=0x3aa575D729FaF5Aad7DB6192b317F2D0cD39789D -VITE_STORAGE_ADDRESS=0xeF71781776Bd5F7E3C301EA16378D880B5E52115 diff --git a/7702Frontend/index.html b/7702Frontend/index.html deleted file mode 100644 index b181f8c..0000000 --- a/7702Frontend/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - TrustVC 7702 Demo - - -
- - - diff --git a/7702Frontend/package-lock.json b/7702Frontend/package-lock.json deleted file mode 100644 index d197986..0000000 --- a/7702Frontend/package-lock.json +++ /dev/null @@ -1,3068 +0,0 @@ -{ - "name": "7702-frontend", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "7702-frontend", - "version": "0.1.0", - "dependencies": { - "ethers": "^6.13.5", - "permissionless": "^0.2.37", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "viem": "^2.21.54" - }, - "devDependencies": { - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@vitejs/plugin-react": "^4.3.4", - "autoprefixer": "^10.4.20", - "postcss": "^8.4.47", - "tailwindcss": "^3.4.15", - "typescript": "^5.6.3", - "vite": "^5.4.11" - } - }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", - "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", - "license": "MIT" - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", - "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", - "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helpers": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", - "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", - "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", - "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", - "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", - "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", - "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", - "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", - "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", - "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", - "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", - "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", - "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@noble/ciphers": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", - "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.0.tgz", - "integrity": "sha512-IPIQ55ythEHkfEd9jMEi32OQ7SxURsGA43JI22lj01OLZNt2NUbJX8YUHxkVWyQ6daHPNn0truF5nSj3DQp6YQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.0.tgz", - "integrity": "sha512-M6s9cr10MibETyo8JsOkq+Lo1+lU6hcvb1MApnUql5qte/5hMEgzlN8/ReIKNfRV8rrqX50W1BX9zoUhC192RA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.0.tgz", - "integrity": "sha512-BqCoMoIbn0keKys+dEAdBa70EtOwV1bEsQCUgU9FdiZmmMge/Zk7LlkYGqbrdHR+Frnt0E1FOanly+rlwvvQzw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.0.tgz", - "integrity": "sha512-SIMzST3VFNXDAbeIWDWiFCNM5qncUBDWaEV7NfE7oZbDt2mgfW4MvbKdbYiGOLoM32gbTv608UMd0XktEYSD7w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.0.tgz", - "integrity": "sha512-ezjfSQMP7ArdUsbBwbQIfwAlhE84I2iVnzQNCFSveqV42q+BmKlzVpf7mxv5EchLcoWU4y6/heFzVg1F+hodUQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.0.tgz", - "integrity": "sha512-9+qTWGW9AZRhnUgwtTwzNwcPlL87ngkeN0LA+q1bADvmY9aNvWaF2TFW8BZgnQPYxpDI7+rMVLivcd4V737TAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.0.tgz", - "integrity": "sha512-T1dMEQhXA/jkJ/jyMIw9IovK8bSUq7A8kLIlvZTb/6YIVsp2zLavr4F3oyllHWo7eIVJRyE5n3tUjQJEbE1IuQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.0.tgz", - "integrity": "sha512-2as0LgT7qQpyceQq6VUJYnumUMUrgGQCWIiDIN9DE0/tglsk6o66uCB4f3djRawAltvfCNLyZZrsqbPA6inCsA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.0.tgz", - "integrity": "sha512-bVURMg+6eNN9C/yc0aVjooZcwTTtYF4YW3xta5pP0//r3o1V8gXEHXWCndj47w/HhwsFroZrFhR+6uQP5T0n0g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.0.tgz", - "integrity": "sha512-Ful8pM/2yYI83PViWdFdpZhdI8HJ5qsXANe5atypbHDf+KIBBDsZsbyy8hbXnULVvW9NsTh5DHwbcBftyLTfiw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.0.tgz", - "integrity": "sha512-9Gp/DgrkzfUBmNPVTyPTvay+4xEP7M/clXpj3efXBcm6uTIVIgDg4rqUpqKXvLEuFRVuEpSAOkhgNeecvaZ4Cg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.0.tgz", - "integrity": "sha512-m9tsJz54LUXkSYM8+8PG81B9IKK5r+2T0clMq4QrS16xFosufU7firBDAZEsDheDs7wTlP7h3++S7lMsU955HA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.0.tgz", - "integrity": "sha512-3UvJ5PNVU16aJf6M3tFI24pWzAl2/ynfbyRN3ICyQajK1lSkrnVYNnLz3v04J32qKa0FczJc22zeToc0lr2A3w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.0.tgz", - "integrity": "sha512-vRWUAbYLGHBZS6Q8Msb2sfnf1fvJf+47t8l/TwOerM2qArzy+IeNMTHrYLHXh95h8MoatPHI5hhSZNs+mGXKPg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.0.tgz", - "integrity": "sha512-c00T5SYENHAt86cfW47URaP3Us5vLC/4QO7GYud1G5VNRffCwwCuBspwqYrriuJB+5m0WFzClCn9wed0FBjKvg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.0.tgz", - "integrity": "sha512-krrCDilhXOwFkSkO3Wm9I/f9H0L92XHHwy2fwxjukxIbh0dem8gZqOW5Y8BsHrpJv5qwlRBV+Wl4ZFyRWhUpwg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.0.tgz", - "integrity": "sha512-7pfYFSTc4/rUC/FtAI0Qp6QthDBCIi6/AuP1xYqFk5vanI6KnL5dWKP60OM/05LOsbwTmIcvr6eXC4CJuJ75IA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.0.tgz", - "integrity": "sha512-7SDIalKeIpG0Ifogbbdn58HmSotYMlf23K3dCJEmiVd9Fg36Vmni82iPQec27N3wY4Bvbxftkxz6vSx9OcouTg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.0.tgz", - "integrity": "sha512-eRZevouTH2i1HeAVLqJuLnt256krQkGY0TN6WsTmsIhuzbh457HuWDMakKwmi0Cjadux983CoSr8Lim2QhUIFw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.0.tgz", - "integrity": "sha512-3oVS7FLGa4U1qcvao9ylGxrjXZyUQqR8UwxEcnUEyPX53O/C/mKDZegNXTdHCP+h3e6ta/f1EN38Yif1mmZHYg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.0.tgz", - "integrity": "sha512-yTB9TgfWj5wHe5QgktAgXTLLot1gvEjl1NiPPAUiCs4oPrIWFl5V4nC3GrkNdj9LaAU4s94nVrGbGOCqUpyWsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.0.tgz", - "integrity": "sha512-5LOhoaesY3doG1c+ac/2JtgREpKoJr5bUHH8tKY0V8di7+uSV6BwLs2PlR0/yzefGOkR+wE7ZolZphHCsyG5Rw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.0.tgz", - "integrity": "sha512-yYkWHhmbhRTWTnWos5HC4GcPQfjlzzCNbM9e/+GXrLuaBXYA3qSDR9f0Vgufd5S8yX81U8jPKp7ZnAjZFMtRnw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.0.tgz", - "integrity": "sha512-SoTb6lPg25xZlA2ibwQ++ahCCnH+FP0qmEuafMJ4gznZKOlXioKEAeJLgCrqjM98ACziXM9V1amFjICVL4IFoA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.0.tgz", - "integrity": "sha512-5L+T1fMX4RIEBoZzT0+sQ0PhTS36NULFmMXtl1TZo44TMAROIMHbZufSOjVWt/Y622BtxgxtaNOokbTDvfsrZA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@scure/base": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", - "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", - "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.9.0", - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32/node_modules/@noble/curves": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", - "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.8.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32/node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", - "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.8.0", - "@scure/base": "~1.2.5" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39/node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "22.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "18.3.31", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", - "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^18.0.0" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "node_modules/abitype": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.2.3.tgz", - "integrity": "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/wevm" - }, - "peerDependencies": { - "typescript": ">=5.0.4", - "zod": "^3.22.0 || ^4.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/aes-js": { - "version": "4.0.0-beta.5", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", - "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", - "license": "MIT" - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "license": "MIT" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true, - "license": "MIT" - }, - "node_modules/autoprefixer": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", - "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.2", - "caniuse-lite": "^1.0.30001787", - "fraction.js": "^5.3.4", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.38", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.38.tgz", - "integrity": "sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", - "update-browserslist-db": "^1.2.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001799", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", - "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true, - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.375", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.375.tgz", - "integrity": "sha512-ZWP5eB4BVPW/ZYo9252hQZHZ5XavtsTgpbhcmMmRwymavC5AsLWQWBPaKMeNd2LW0KGby5HPXvj7+sr4ta5j/Q==", - "dev": true, - "license": "ISC" - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ethers": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.17.0.tgz", - "integrity": "sha512-BpyrpIPJ3ydEVow8zGaz1DuPS7YU8DcWxuBnY9a0UA/lvAPwrMr+EPXsfrul628SRaekPNeIM4UFh/91GWZang==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "1.11.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "22.7.5", - "aes-js": "4.0.0-beta.5", - "tslib": "2.7.0", - "ws": "8.21.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", - "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/isows": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", - "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "peerDependencies": { - "ws": "*" - } - }, - "node_modules/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", - "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/node-releases": { - "version": "2.0.48", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.48.tgz", - "integrity": "sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/ox": { - "version": "0.14.29", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.14.29.tgz", - "integrity": "sha512-M5j87Ec4V99MQdRct/g09eWXW60g6zhHTUs1lr4deUtrPDnezBdCJTgKd7pxqTpSZBFveV0ALi9jMMuT1qKyNg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "^1.11.0", - "@noble/ciphers": "^1.3.0", - "@noble/curves": "1.9.1", - "@noble/hashes": "^1.8.0", - "@scure/bip32": "^1.7.0", - "@scure/bip39": "^1.6.0", - "abitype": "^1.2.3", - "eventemitter3": "5.0.1" - }, - "peerDependencies": { - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/ox/node_modules/@noble/curves": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", - "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.8.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ox/node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/permissionless": { - "version": "0.2.57", - "resolved": "https://registry.npmjs.org/permissionless/-/permissionless-0.2.57.tgz", - "integrity": "sha512-QrzAoQGYPV/NJ2x5Sj18h7qed6f+kCyQAojrncN091UPiGqHjFNjgdsgreiv8pxlQgF4UcpuJUvsHLpOEBd6cQ==", - "license": "MIT", - "peerDependencies": { - "ox": "^0.8.0", - "viem": "^2.28.1" - }, - "peerDependenciesMeta": { - "ox": { - "optional": true - } - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.12", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", - "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", - "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.12", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", - "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rollup": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.0.tgz", - "integrity": "sha512-nc72Wgq62I7rtDV4izT5/aaS0zxy3kttkinf9586ApknY3jZO9NYsmtc24fUckA0X7Q2v+ML4a15pdUlV5V/jA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.9" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.62.0", - "@rollup/rollup-android-arm64": "4.62.0", - "@rollup/rollup-darwin-arm64": "4.62.0", - "@rollup/rollup-darwin-x64": "4.62.0", - "@rollup/rollup-freebsd-arm64": "4.62.0", - "@rollup/rollup-freebsd-x64": "4.62.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.62.0", - "@rollup/rollup-linux-arm-musleabihf": "4.62.0", - "@rollup/rollup-linux-arm64-gnu": "4.62.0", - "@rollup/rollup-linux-arm64-musl": "4.62.0", - "@rollup/rollup-linux-loong64-gnu": "4.62.0", - "@rollup/rollup-linux-loong64-musl": "4.62.0", - "@rollup/rollup-linux-ppc64-gnu": "4.62.0", - "@rollup/rollup-linux-ppc64-musl": "4.62.0", - "@rollup/rollup-linux-riscv64-gnu": "4.62.0", - "@rollup/rollup-linux-riscv64-musl": "4.62.0", - "@rollup/rollup-linux-s390x-gnu": "4.62.0", - "@rollup/rollup-linux-x64-gnu": "4.62.0", - "@rollup/rollup-linux-x64-musl": "4.62.0", - "@rollup/rollup-openbsd-x64": "4.62.0", - "@rollup/rollup-openharmony-arm64": "4.62.0", - "@rollup/rollup-win32-arm64-msvc": "4.62.0", - "@rollup/rollup-win32-ia32-msvc": "4.62.0", - "@rollup/rollup-win32-x64-gnu": "4.62.0", - "@rollup/rollup-win32-x64-msvc": "4.62.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tailwindcss": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", - "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.6.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.2", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.7", - "lilconfig": "^3.1.3", - "micromatch": "^4.0.8", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.47", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "license": "0BSD" - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "license": "MIT" - }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/viem": { - "version": "2.52.2", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.52.2.tgz", - "integrity": "sha512-HSU12p5aD/kAPZfrlbCUqdiP4P/c6hQ9AhfTS51VbLUQIjkWd1d5EjrCx/SCxZ0zhZVRn4Iv5X5WDqXPG8Ubew==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@noble/curves": "1.9.1", - "@noble/hashes": "1.8.0", - "@scure/bip32": "1.7.0", - "@scure/bip39": "1.6.0", - "abitype": "1.2.3", - "isows": "1.0.7", - "ox": "0.14.29", - "ws": "8.20.1" - }, - "peerDependencies": { - "typescript": ">=5.0.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/viem/node_modules/@noble/curves": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", - "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.8.0" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/@noble/hashes": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", - "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", - "license": "MIT", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/viem/node_modules/ws": { - "version": "8.20.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", - "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/vite": { - "version": "5.4.21", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", - "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/ws": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", - "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - } - } -} diff --git a/7702Frontend/package.json b/7702Frontend/package.json deleted file mode 100644 index 2d7275e..0000000 --- a/7702Frontend/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "7702-frontend", - "private": true, - "version": "0.1.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "dependencies": { - "ethers": "^6.13.5", - "permissionless": "^0.2.37", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "viem": "^2.21.54" - }, - "devDependencies": { - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@vitejs/plugin-react": "^4.3.4", - "autoprefixer": "^10.4.20", - "postcss": "^8.4.47", - "tailwindcss": "^3.4.15", - "typescript": "^5.6.3", - "vite": "^5.4.11" - } -} diff --git a/7702Frontend/postcss.config.js b/7702Frontend/postcss.config.js deleted file mode 100644 index 2aa7205..0000000 --- a/7702Frontend/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -}; diff --git a/7702Frontend/src/App.tsx b/7702Frontend/src/App.tsx deleted file mode 100644 index 9dc67a5..0000000 --- a/7702Frontend/src/App.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { useState } from "react"; -import { WalletConnect } from "./components/WalletConnect"; -import { PaymasterPanel } from "./components/PaymasterPanel"; -import { PaymasterAdminPanel } from "./components/PaymasterAdminPanel"; -import { RegistryPanel } from "./components/RegistryPanel"; -import { TitleEscrowPanel } from "./components/TitleEscrowPanel"; -import { DelegationPanel } from "./components/DelegationPanel"; -import { TrustVCPanel } from "./components/TrustVCPanel"; -import { PAYMASTER_ADDRESS } from "./lib/constants"; - -export default function App() { - const [address, setAddress] = useState(null); - const [isDelegated, setIsDelegated] = useState(false); - const [paymasterAddress, setPaymasterAddress] = useState<`0x${string}` | null>( - PAYMASTER_ADDRESS && PAYMASTER_ADDRESS !== "0x" ? PAYMASTER_ADDRESS : null - ); - const [registryAddress, setRegistryAddress] = useState<`0x${string}` | null>(null); - const [titleEscrowAddress, setTitleEscrowAddress] = useState<`0x${string}` | null>(null); - - function handleDisconnect() { - setAddress(null); - setIsDelegated(false); - setRegistryAddress(null); - setTitleEscrowAddress(null); - } - - return ( -
-
-

- TrustVC EIP-7702 -

-

- Gasless trade document operations via Account Abstraction · Sepolia -

-
- - - - - - - - - - - - - - - -

- EIP-7702 · ERC-4337 · Pimlico Bundler · Sepolia Testnet -

-
- ); -} diff --git a/7702Frontend/src/components/DelegationPanel.tsx b/7702Frontend/src/components/DelegationPanel.tsx deleted file mode 100644 index 580d06f..0000000 --- a/7702Frontend/src/components/DelegationPanel.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { useState, useEffect, useCallback } from "react"; -import { checkDelegation, PERMISSIONLESS_IMPL } from "../lib/pimlico"; - -interface Props { - address: string | null; - onDelegated: (delegated: boolean) => void; -} - -export function DelegationPanel({ address, onDelegated }: Props) { - const [currentDelegate, setCurrentDelegate] = useState< - string | null | undefined - >(undefined); - const [checking, setChecking] = useState(false); - - const isDelegated = - currentDelegate?.toLowerCase() === PERMISSIONLESS_IMPL.toLowerCase(); - - const refresh = useCallback(async () => { - if (!address) return; - setChecking(true); - try { - const delegate = await checkDelegation(address as `0x${string}`); - setCurrentDelegate(delegate); - onDelegated( - delegate?.toLowerCase() === PERMISSIONLESS_IMPL.toLowerCase(), - ); - } finally { - setChecking(false); - } - }, [address, onDelegated]); - - useEffect(() => { - refresh(); - }, [refresh]); - - if (!address) { - return ( -
-

EIP-7702 Delegation

-

Connect wallet first

-
- ); - } - - return ( -
-
-

EIP-7702 Delegation

- {checking ? ( - - checking... - - ) : currentDelegate === undefined ? null : isDelegated ? ( - - - Active - - ) : ( - - - Pending - - )} -
- -
-
- Target impl: - - {PERMISSIONLESS_IMPL} - -
-
- Current delegate: - - {currentDelegate === undefined ? "—" : (currentDelegate ?? "none")} - -
-
- - {isDelegated ? ( -

- Your EOA is delegated to the implementation contract above. All - transactions are sent as smart account UserOps. -

- ) : ( -
-

Not delegated

-

- Your EOA has not been delegated yet. To delegate, run the following - command in the CLI: -

-
-            npx ts-node scripts/trFunctions/delegate.ts
-          
-
- )} - - -
- ); -} diff --git a/7702Frontend/src/components/PaymasterAdminPanel.tsx b/7702Frontend/src/components/PaymasterAdminPanel.tsx deleted file mode 100644 index 073b8c1..0000000 --- a/7702Frontend/src/components/PaymasterAdminPanel.tsx +++ /dev/null @@ -1,314 +0,0 @@ -import { useState, useEffect, useCallback } from "react"; -import { createWalletClient, createPublicClient, custom, http, parseAbi, parseEther, formatEther, isAddress } from "viem"; -import { sepolia } from "viem/chains"; -import { SEPOLIA_RPC_URL } from "../lib/constants"; - -const ENTRY_POINT = "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108" as const; - -const paymasterAbi = parseAbi([ - "function setTdocDeployer(address _tdocDeployer) external", - "function setUserWhitelist(address user, uint256 credits) external", - "function addStake(uint32 unstakeDelaySec) external payable", - "function deposit() external payable", -]); - -const entryPointAbi = parseAbi([ - "function getDepositInfo(address account) external view returns (uint256 deposit, bool staked, uint112 stake, uint32 unstakeDelaySec, uint48 withdrawTime)", -]); - -interface DepositInfo { - deposit: bigint; - staked: boolean; - stake: bigint; - unstakeDelaySec: number; -} - -interface Props { - address: string | null; - paymasterAddress: string | null; -} - -export function PaymasterAdminPanel({ address, paymasterAddress }: Props) { - const [depositInfo, setDepositInfo] = useState(null); - - const [deployerInput, setDeployerInput] = useState(""); - const [deployerLoading, setDeployerLoading] = useState(false); - const [deployerError, setDeployerError] = useState(null); - const [deployerSuccess, setDeployerSuccess] = useState(false); - - const [whitelistInput, setWhitelistInput] = useState(""); - const [credits, setCredits] = useState("3"); - const [whitelistLoading, setWhitelistLoading] = useState(false); - const [whitelistError, setWhitelistError] = useState(null); - const [whitelistSuccess, setWhitelistSuccess] = useState(null); - - const [fundAmount, setFundAmount] = useState("0.05"); - const [fundLoading, setFundLoading] = useState(false); - const [fundError, setFundError] = useState(null); - const [fundSuccess, setFundSuccess] = useState(false); - - const [stakeAmount, setStakeAmount] = useState("0.01"); - const [unstakeDelay, setUnstakeDelay] = useState("86400"); - const [stakeLoading, setStakeLoading] = useState(false); - const [stakeError, setStakeError] = useState(null); - const [stakeSuccess, setStakeSuccess] = useState(false); - - const disabled = !address || !paymasterAddress; - - const fetchDepositInfo = useCallback(async () => { - if (!paymasterAddress) return; - try { - const publicClient = createPublicClient({ chain: sepolia, transport: http(SEPOLIA_RPC_URL) }); - const raw = await publicClient.readContract({ - address: ENTRY_POINT, - abi: entryPointAbi, - functionName: "getDepositInfo", - args: [paymasterAddress as `0x${string}`], - }) as [bigint, boolean, bigint, number, number]; - setDepositInfo({ deposit: raw[0], staked: raw[1], stake: raw[2], unstakeDelaySec: raw[3] }); - } catch { /* ignore */ } - }, [paymasterAddress]); - - useEffect(() => { fetchDepositInfo(); }, [fetchDepositInfo]); - - const publicClient = () => createPublicClient({ chain: sepolia, transport: http(SEPOLIA_RPC_URL) }); - - function walletClient() { - return createWalletClient({ - account: address as `0x${string}`, - chain: sepolia, - transport: custom(window.ethereum), - }); - } - - async function sendAndWait(fn: () => Promise<`0x${string}`>) { - const hash = await fn(); - await publicClient().waitForTransactionReceipt({ hash }); - return hash; - } - - async function handleSetDeployer() { - if (!address || !paymasterAddress) return; - setDeployerError(null); setDeployerSuccess(false); - const addr = deployerInput.trim(); - if (!isAddress(addr)) { setDeployerError("Invalid address."); return; } - setDeployerLoading(true); - try { - await sendAndWait(() => walletClient().writeContract({ - address: paymasterAddress as `0x${string}`, - abi: paymasterAbi, - functionName: "setTdocDeployer", - args: [addr as `0x${string}`], - })); - setDeployerSuccess(true); - setDeployerInput(""); - } catch (e: unknown) { - setDeployerError(e instanceof Error ? e.message : String(e)); - } finally { setDeployerLoading(false); } - } - - async function handleWhitelist() { - if (!address || !paymasterAddress) return; - setWhitelistError(null); setWhitelistSuccess(null); - const addr = whitelistInput.trim(); - if (!isAddress(addr)) { setWhitelistError("Invalid address."); return; } - const c = parseInt(credits); - if (isNaN(c) || c < 0 || c > 3) { setWhitelistError("Credits must be 0–3."); return; } - setWhitelistLoading(true); - try { - await sendAndWait(() => walletClient().writeContract({ - address: paymasterAddress as `0x${string}`, - abi: paymasterAbi, - functionName: "setUserWhitelist", - args: [addr as `0x${string}`, BigInt(c)], - })); - setWhitelistSuccess(`${addr} whitelisted with ${c} credit${c !== 1 ? "s" : ""}.`); - setWhitelistInput(""); - } catch (e: unknown) { - setWhitelistError(e instanceof Error ? e.message : String(e)); - } finally { setWhitelistLoading(false); } - } - - async function handleFund() { - if (!address || !paymasterAddress) return; - setFundError(null); setFundSuccess(false); - const eth = parseFloat(fundAmount); - if (isNaN(eth) || eth <= 0) { setFundError("Enter a valid ETH amount."); return; } - setFundLoading(true); - try { - await sendAndWait(() => walletClient().writeContract({ - address: paymasterAddress as `0x${string}`, - abi: paymasterAbi, - functionName: "deposit", - value: parseEther(fundAmount), - })); - setFundSuccess(true); - await fetchDepositInfo(); - } catch (e: unknown) { - setFundError(e instanceof Error ? e.message : String(e)); - } finally { setFundLoading(false); } - } - - async function handleStake() { - if (!address || !paymasterAddress) return; - setStakeError(null); setStakeSuccess(false); - const eth = parseFloat(stakeAmount); - const delay = parseInt(unstakeDelay); - if (isNaN(eth) || eth <= 0) { setStakeError("Enter a valid ETH amount."); return; } - if (isNaN(delay) || delay < 1) { setStakeError("Enter a valid unstake delay (seconds)."); return; } - setStakeLoading(true); - try { - await sendAndWait(() => walletClient().writeContract({ - address: paymasterAddress as `0x${string}`, - abi: paymasterAbi, - functionName: "addStake", - args: [delay], - value: parseEther(stakeAmount), - })); - setStakeSuccess(true); - await fetchDepositInfo(); - } catch (e: unknown) { - setStakeError(e instanceof Error ? e.message : String(e)); - } finally { setStakeLoading(false); } - } - - return ( -
-

Paymaster Admin

- - {!paymasterAddress && ( -

Set up a paymaster first.

- )} - - {/* EntryPoint status */} - {depositInfo && ( -
-

EntryPoint Status

-
- Gas deposit: - 0n ? "text-emerald-400" : "text-yellow-400"}`}> - {formatEther(depositInfo.deposit)} ETH - -
-
- Stake: - - {depositInfo.staked ? `${formatEther(depositInfo.stake)} ETH (locked ${depositInfo.unstakeDelaySec}s)` : "Not staked"} - -
- -
- )} - - {/* Fund gas pool */} -
-

Fund Gas Pool

-

- Deposit ETH into the EntryPoint gas pool. This is what pays for sponsored UserOps. -

-
- { setFundAmount(e.target.value); setFundError(null); setFundSuccess(false); }} - disabled={disabled || fundLoading} - /> - -
- {fundSuccess &&

Gas pool funded ✓

} - {fundError &&

{fundError}

} -
- - {/* Add stake */} -
-

Add Stake

-

- Lock ETH as a bundler-compliance bond. Required for the paymaster to be accepted by bundlers. -

-
- { setStakeAmount(e.target.value); setStakeError(null); setStakeSuccess(false); }} - disabled={disabled || stakeLoading} - /> - setUnstakeDelay(e.target.value)} - disabled={disabled || stakeLoading} - /> - -
-

Unstake delay: 86400 = 1 day (cannot be reduced once set)

- {stakeSuccess &&

Stake added ✓

} - {stakeError &&

{stakeError}

} -
- - {/* Set TDoc Deployer */} -
-

TDoc Deployer

-

- The factory contract that deploys TDoc registries. Required for deployRegistry. -

-
- { setDeployerInput(e.target.value); setDeployerError(null); setDeployerSuccess(false); }} - disabled={disabled || deployerLoading} - /> - -
- {deployerSuccess &&

TDoc deployer updated ✓

} - {deployerError &&

{deployerError}

} -
- - {/* Whitelist User */} -
-

Whitelist User

-

- Grant deployment credits (max 3) for gasless deployRegistry and mintDocument. -

-
- { setWhitelistInput(e.target.value); setWhitelistError(null); setWhitelistSuccess(null); }} - disabled={disabled || whitelistLoading} - /> - - -
-

Credits: 1 = deployRegistry only · 2 = + mintDocument · 3 = max

- {whitelistSuccess &&

{whitelistSuccess} ✓

} - {whitelistError &&

{whitelistError}

} -
-
- ); -} diff --git a/7702Frontend/src/components/PaymasterPanel.tsx b/7702Frontend/src/components/PaymasterPanel.tsx deleted file mode 100644 index 86168a6..0000000 --- a/7702Frontend/src/components/PaymasterPanel.tsx +++ /dev/null @@ -1,270 +0,0 @@ -import { useState, useEffect } from "react"; -import { createWalletClient, createPublicClient, custom, http, parseAbi, parseEventLogs, parseEther, isAddress } from "viem"; -import { sepolia } from "viem/chains"; -import { PAYMASTER_ADDRESS, FACTORY_ADDRESS, SEPOLIA_RPC_URL } from "../lib/constants"; -const PERMANENT_OWNER = "0x433097a1C1b8a3e9188d8C54eCC057B1D69f1638".toLowerCase(); -const LS_KEY = "trustvc_paymaster"; - -const factoryAbi = parseAbi([ - "function deployPlatformPaymaster(address platformAddress, uint256 dailyLimit, bytes32 salt) external returns (address paymaster)", - "event PlatformOnboarded(address indexed platformAddress, address indexed paymaster)", -]); - -interface Props { - address: string | null; - onPaymasterDeployed: (address: `0x${string}`) => void; -} - -type Mode = "deploy" | "load"; - -export function PaymasterPanel({ address, onPaymasterDeployed }: Props) { - const envPaymaster = PAYMASTER_ADDRESS && PAYMASTER_ADDRESS !== "0x" ? PAYMASTER_ADDRESS : null; - - const [mode, setMode] = useState("deploy"); - const [activePaymaster, setActivePaymaster] = useState(null); - const [deploying, setDeploying] = useState(false); - const [dailyLimitEth, setDailyLimitEth] = useState("0"); - const [loadInput, setLoadInput] = useState(""); - const [loadError, setLoadError] = useState(null); - const [deployError, setDeployError] = useState(null); - const [justDeployed, setJustDeployed] = useState(false); - const [justLoaded, setJustLoaded] = useState(false); - - // When address changes, resolve which paymaster to use - useEffect(() => { - if (!address) { - setActivePaymaster(null); - return; - } - - // Permanent owner → always use env paymaster - if (address.toLowerCase() === PERMANENT_OWNER && envPaymaster) { - setActivePaymaster(envPaymaster); - onPaymasterDeployed(envPaymaster); - return; - } - - // Anyone else → check localStorage - const saved = localStorage.getItem(LS_KEY); - if (saved) { - setActivePaymaster(saved); - onPaymasterDeployed(saved as `0x${string}`); - } else { - setActivePaymaster(null); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [address]); - - const isPermanentOwner = address?.toLowerCase() === PERMANENT_OWNER; - const disabled = !address; - - function handleLoad() { - setLoadError(null); - const trimmed = loadInput.trim(); - if (!isAddress(trimmed)) { - setLoadError("Invalid address."); - return; - } - localStorage.setItem(LS_KEY, trimmed); - setActivePaymaster(trimmed); - setJustLoaded(true); - onPaymasterDeployed(trimmed as `0x${string}`); - } - - async function handleDeploy() { - if (!address) return; - setDeployError(null); - setDeploying(true); - try { - const transport = http(SEPOLIA_RPC_URL); - const publicClient = createPublicClient({ chain: sepolia, transport }); - const walletClient = createWalletClient({ - account: address as `0x${string}`, - chain: sepolia, - transport: custom(window.ethereum), - }); - - const salt = ("0x" + Array.from(crypto.getRandomValues(new Uint8Array(32))) - .map((b) => b.toString(16).padStart(2, "0")) - .join("")) as `0x${string}`; - - const dailyLimit = dailyLimitEth && parseFloat(dailyLimitEth) > 0 - ? parseEther(dailyLimitEth) - : 0n; - - const txHash = await walletClient.writeContract({ - address: FACTORY_ADDRESS, - abi: factoryAbi, - functionName: "deployPlatformPaymaster", - args: [address as `0x${string}`, dailyLimit, salt], - }); - - const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash }); - const logs = parseEventLogs({ abi: factoryAbi, logs: receipt.logs, eventName: "PlatformOnboarded" }); - const paymasterAddr = logs[0]?.args?.paymaster; - if (!paymasterAddr) throw new Error("Deploy succeeded but paymaster address not found in logs"); - - localStorage.setItem(LS_KEY, paymasterAddr); - setActivePaymaster(paymasterAddr); - setJustDeployed(true); - onPaymasterDeployed(paymasterAddr); - } catch (e: unknown) { - setDeployError(e instanceof Error ? e.message : String(e)); - } finally { - setDeploying(false); - } - } - - // Active state - if (activePaymaster) { - return ( -
-
-

Platform Paymaster

- - - {justDeployed ? "Deployed" : "Active"} - -
- -
-
- Paymaster: - - {activePaymaster} - -
- {isPermanentOwner && ( -

Loaded from environment (permanent owner).

- )} - {justDeployed && ( -

Deployed and saved to local storage.

- )} - {justLoaded && ( -

Paymaster loaded and saved for this browser.

- )} -
- - {!isPermanentOwner && ( - - )} -
- ); - } - - return ( -
-
-

Platform Paymaster

- - - Not set - -
- - {/* Mode toggle */} -
- - -
- - {mode === "deploy" ? ( -
-

- Deploy a PlatformPaymaster via the factory. Your connected wallet becomes the paymaster owner. -

- -
- - setDailyLimitEth(e.target.value)} - disabled={disabled || deploying} - /> -
- -
-
- Platform owner: - {address ?? "—"} -
-
- Factory: - {FACTORY_ADDRESS} -
-
- - - - {deployError && ( -

{deployError}

- )} -
- ) : ( -
-

- Already have a deployed paymaster? Paste the address below — it will be saved in your browser. -

- - { setLoadInput(e.target.value); setLoadError(null); }} - disabled={disabled} - /> - - - - {loadError && ( -

{loadError}

- )} -
- )} -
- ); -} diff --git a/7702Frontend/src/components/RegistryPanel.tsx b/7702Frontend/src/components/RegistryPanel.tsx deleted file mode 100644 index dab4bef..0000000 --- a/7702Frontend/src/components/RegistryPanel.tsx +++ /dev/null @@ -1,336 +0,0 @@ -import { useState, useEffect } from "react"; -import { - createPublicClient, - http, - parseAbi, - parseEventLogs, - isAddress, - encodeFunctionData, -} from "viem"; -import { sepolia } from "viem/chains"; -import { - REGISTRY_ADDRESS, - SEPOLIA_RPC_URL, - TDOC_IMPLEMENTATION, -} from "../lib/constants"; -import { buildSmartAccountClient } from "../lib/pimlico"; - -const PERMANENT_OWNER = - "0x433097a1C1b8a3e9188d8C54eCC057B1D69f1638".toLowerCase(); -const LS_KEY = "trustvc_registry"; - -const paymasterAbi = parseAbi([ - "function deployRegistry(address implementation, string name, string symbol) external returns (address deployed)", - "event RegistryDeployed(address indexed user, address indexed deployed, uint256 creditsLeft)", -]); - -interface Props { - address: string | null; - paymasterAddress: string | null; - isDelegated: boolean; - onRegistryReady: (address: `0x${string}`) => void; -} - -type Mode = "deploy" | "load"; - -export function RegistryPanel({ - address, - paymasterAddress, - isDelegated, - onRegistryReady, -}: Props) { - const envRegistry = - REGISTRY_ADDRESS && REGISTRY_ADDRESS !== "0x" ? REGISTRY_ADDRESS : null; - - const [mode, setMode] = useState("deploy"); - const [activeRegistry, setActiveRegistry] = useState(null); - const [deploying, setDeploying] = useState(false); - const [implAddress, setImplAddress] = useState( - TDOC_IMPLEMENTATION ?? "", - ); - const [tokenName, setTokenName] = useState(""); - const [tokenSymbol, setTokenSymbol] = useState(""); - const [loadInput, setLoadInput] = useState(""); - const [loadError, setLoadError] = useState(null); - const [deployError, setDeployError] = useState(null); - const [justDeployed, setJustDeployed] = useState(false); - const [justLoaded, setJustLoaded] = useState(false); - - useEffect(() => { - if (!address) { - setActiveRegistry(null); - return; - } - if (address.toLowerCase() === PERMANENT_OWNER && envRegistry) { - setActiveRegistry(envRegistry); - onRegistryReady(envRegistry); - return; - } - const saved = localStorage.getItem(LS_KEY); - if (saved) { - setActiveRegistry(saved); - onRegistryReady(saved as `0x${string}`); - } else setActiveRegistry(null); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [address]); - - const isPermanentOwner = address?.toLowerCase() === PERMANENT_OWNER; - const disabled = !address || !paymasterAddress; - - function handleLoad() { - setLoadError(null); - const trimmed = loadInput.trim(); - if (!isAddress(trimmed)) { - setLoadError("Invalid address."); - return; - } - localStorage.setItem(LS_KEY, trimmed); - setActiveRegistry(trimmed); - setJustLoaded(true); - onRegistryReady(trimmed as `0x${string}`); - } - - async function handleDeploy() { - if (!address || !paymasterAddress) return; - if (!isAddress(implAddress)) { - setDeployError("Invalid implementation address."); - return; - } - if (!tokenName.trim()) { - setDeployError("Token name is required."); - return; - } - if (!tokenSymbol.trim()) { - setDeployError("Token symbol is required."); - return; - } - setDeployError(null); - setDeploying(true); - try { - const publicClient = createPublicClient({ - chain: sepolia, - transport: http(SEPOLIA_RPC_URL), - }); - const calldata = encodeFunctionData({ - abi: paymasterAbi, - functionName: "deployRegistry", - args: [ - implAddress as `0x${string}`, - tokenName.trim(), - tokenSymbol.trim(), - ], - }); - - let txHash: `0x${string}`; - if (isDelegated) { - const { smartAccountClient } = await buildSmartAccountClient( - address as `0x${string}`, - paymasterAddress as `0x${string}`, - ); - txHash = (await smartAccountClient.sendTransaction({ - to: paymasterAddress as `0x${string}`, - value: 0n, - data: calldata, - })) as `0x${string}`; - } else { - throw new Error( - "Delegation required for gasless registry deploy. Run the delegate script first or delegate via DelegationPanel.", - ); - } - - const receipt = await publicClient.waitForTransactionReceipt({ - hash: txHash, - }); - const logs = parseEventLogs({ - abi: paymasterAbi, - logs: receipt.logs, - eventName: "RegistryDeployed", - }); - const registryAddr = logs[0]?.args?.deployed; - if (!registryAddr) - throw new Error( - "Deploy succeeded but registry address not found in logs", - ); - - localStorage.setItem(LS_KEY, registryAddr); - setActiveRegistry(registryAddr); - setJustDeployed(true); - onRegistryReady(registryAddr); - } catch (e: unknown) { - setDeployError(e instanceof Error ? e.message : String(e)); - } finally { - setDeploying(false); - } - } - - if (activeRegistry) { - return ( -
-
-

Token Registry

- - - {justDeployed ? "Deployed" : "Active"} - -
-
-
- Registry: - - {activeRegistry} - -
- {isPermanentOwner && ( -

- Loaded from environment (permanent owner). -

- )} - {justDeployed && ( -

- Deployed and saved to local storage. -

- )} - {justLoaded && ( -

Registry loaded.

- )} -
- {!isPermanentOwner && ( - - )} -
- ); - } - - return ( -
-
-

Token Registry

- - - Not set - -
- - {!paymasterAddress && ( -

- Set up a paymaster first. -

- )} - -
- - -
- - {mode === "deploy" ? ( -
-

- Deploy a new TDoc registry via the paymaster. Requires whitelist - credits on the paymaster. -

- setImplAddress(e.target.value)} - disabled={disabled || deploying} - /> - setTokenName(e.target.value)} - disabled={disabled || deploying} - /> - setTokenSymbol(e.target.value)} - disabled={disabled || deploying} - /> - - {!isDelegated && !disabled && ( -

- Delegation required — run{" "} - - npx ts-node scripts/trFunctions/delegate.ts - {" "} - first. -

- )} - {deployError && ( -

{deployError}

- )} -
- ) : ( -
-

- Already have a registry? Paste the address — it will be saved in - your browser. -

- { - setLoadInput(e.target.value); - setLoadError(null); - }} - disabled={disabled} - /> - - {loadError &&

{loadError}

} -
- )} -
- ); -} diff --git a/7702Frontend/src/components/SignerPanel.tsx b/7702Frontend/src/components/SignerPanel.tsx deleted file mode 100644 index b38edc8..0000000 --- a/7702Frontend/src/components/SignerPanel.tsx +++ /dev/null @@ -1,2 +0,0 @@ -// Unused — MetaMask signs UserOps via signTypedData (EIP-712) with to7702SimpleSmartAccount. -export {}; diff --git a/7702Frontend/src/components/StoragePanel.tsx b/7702Frontend/src/components/StoragePanel.tsx deleted file mode 100644 index 06ec31b..0000000 --- a/7702Frontend/src/components/StoragePanel.tsx +++ /dev/null @@ -1,276 +0,0 @@ -import { useState, useEffect, useCallback } from "react"; -import { encodeFunctionData, parseAbiItem, createPublicClient, http } from "viem"; -import { sepolia } from "viem/chains"; -import { buildSmartAccountClient } from "../lib/pimlico"; -import { STORAGE_ADDRESS, SEPOLIA_RPC_URL } from "../lib/constants"; -import { STORAGE_ABI } from "../lib/abis"; - -interface Item { - id: number; - data: string; - deleted: boolean; -} - -interface Props { - address: string | null; - isDelegated: boolean; -} - -// Typed event definitions — getLogs returns decoded args when using these -const CREATED_EVENT = parseAbiItem( - "event ItemCreated(uint256 indexed id, string data, uint256 timestamp)" -); -const UPDATED_EVENT = parseAbiItem( - "event ItemUpdated(uint256 indexed id, string data, uint256 timestamp)" -); -const DELETED_EVENT = parseAbiItem("event ItemDeleted(uint256 indexed id)"); - -export function StoragePanel({ address, isDelegated }: Props) { - const [items, setItems] = useState([]); - const [newData, setNewData] = useState(""); - const [updateId, setUpdateId] = useState(""); - const [updateData, setUpdateData] = useState(""); - const [removeId, setRemoveId] = useState(""); - const [loading, setLoading] = useState(null); - const [lastTx, setLastTx] = useState(null); - const [error, setError] = useState(null); - - const fetchItems = useCallback(async () => { - try { - const publicClient = createPublicClient({ - chain: sepolia, - transport: http(SEPOLIA_RPC_URL), - }); - - // getLogs with a typed parseAbiItem event returns fully-typed args - const [created, updated, deleted] = await Promise.all([ - publicClient.getLogs({ address: STORAGE_ADDRESS, event: CREATED_EVENT, fromBlock: 0n }), - publicClient.getLogs({ address: STORAGE_ADDRESS, event: UPDATED_EVENT, fromBlock: 0n }), - publicClient.getLogs({ address: STORAGE_ADDRESS, event: DELETED_EVENT, fromBlock: 0n }), - ]); - - const map: Record = {}; - - for (const log of created) { - const id = Number(log.args.id); - map[id] = { id, data: log.args.data ?? "", deleted: false }; - } - for (const log of updated) { - const id = Number(log.args.id); - if (map[id]) map[id].data = log.args.data ?? ""; - } - for (const log of deleted) { - const id = Number(log.args.id); - if (map[id]) map[id].deleted = true; - } - - setItems(Object.values(map).sort((a, b) => a.id - b.id)); - } catch (e) { - console.error("fetchItems error:", e); - } - }, []); - - useEffect(() => { - fetchItems(); - }, [fetchItems]); - - async function sendUserOp(calldata: `0x${string}`, label: string) { - if (!address) return; - setError(null); - setLastTx(null); - setLoading(label); - try { - const { smartAccountClient } = await buildSmartAccountClient( - address as `0x${string}` - ); - const txHash = await smartAccountClient.sendTransaction({ - to: STORAGE_ADDRESS, - value: 0n, - data: calldata, - }); - setLastTx(txHash); - await fetchItems(); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : String(e)); - } finally { - setLoading(null); - } - } - - async function handleCreate() { - if (!newData.trim()) return; - const data = encodeFunctionData({ - abi: STORAGE_ABI, - functionName: "create", - args: [newData.trim()], - }); - await sendUserOp(data, "create"); - setNewData(""); - } - - async function handleUpdate() { - if (!updateId || !updateData.trim()) return; - const data = encodeFunctionData({ - abi: STORAGE_ABI, - functionName: "update", - args: [BigInt(updateId), updateData.trim()], - }); - await sendUserOp(data, "update"); - setUpdateId(""); - setUpdateData(""); - } - - async function handleRemove() { - if (!removeId) return; - const data = encodeFunctionData({ - abi: STORAGE_ABI, - functionName: "remove", - args: [BigInt(removeId)], - }); - await sendUserOp(data, "remove"); - setRemoveId(""); - } - - const disabled = !address || !isDelegated; - - return ( -
-
-

Storage CRUD

- gasless via UserOp -
- - {disabled && ( -

- {!address ? "Connect wallet first." : "Delegate your EOA first."} -

- )} - - {/* Item list */} -
-

- Items on-chain -

- {items.length === 0 ? ( -

No items yet.

- ) : ( -
- {items.map((item) => ( -
- #{item.id} - {item.data} -
- ))} -
- )} - -
- - {/* Create */} -
-

- Create -

-
- setNewData(e.target.value)} - disabled={disabled} - /> - -
-
- - {/* Update */} -
-

- Update -

-
- setUpdateId(e.target.value)} - disabled={disabled} - /> - setUpdateData(e.target.value)} - disabled={disabled} - /> - -
-
- - {/* Remove */} -
-

- Remove -

-
- setRemoveId(e.target.value)} - disabled={disabled} - /> - -
-
- - {lastTx && ( -

- Tx: {lastTx} -

- )} - {error && ( -

{error}

- )} -
- ); -} diff --git a/7702Frontend/src/components/TitleEscrowPanel.tsx b/7702Frontend/src/components/TitleEscrowPanel.tsx deleted file mode 100644 index 97d2de0..0000000 --- a/7702Frontend/src/components/TitleEscrowPanel.tsx +++ /dev/null @@ -1,246 +0,0 @@ -import { useState, useEffect } from "react"; -import { createWalletClient, createPublicClient, custom, http, parseAbi, parseEventLogs, isAddress, toHex, encodeFunctionData } from "viem"; -import { sepolia } from "viem/chains"; -import { TITLE_ESCROW_ADDRESS, SEPOLIA_RPC_URL } from "../lib/constants"; -import { buildSmartAccountClient } from "../lib/pimlico"; - -const PERMANENT_OWNER = "0x433097a1C1b8a3e9188d8C54eCC057B1D69f1638".toLowerCase(); -const LS_KEY = "trustvc_title_escrow"; - -const paymasterAbi = parseAbi([ - "function mintDocument(address registry, address beneficiary, address holder, uint256 tokenId, bytes remark) external returns (address titleEscrow)", - "event TitleEscrowLinked(address indexed titleEscrow, address indexed registry)", -]); - -interface Props { - address: string | null; - isDelegated: boolean; - paymasterAddress: string | null; - registryAddress: string | null; - onTitleEscrowReady: (address: `0x${string}`) => void; -} - -type Mode = "mint" | "load"; - -export function TitleEscrowPanel({ address, isDelegated, paymasterAddress, registryAddress, onTitleEscrowReady }: Props) { - const envEscrow = TITLE_ESCROW_ADDRESS && TITLE_ESCROW_ADDRESS !== "0x" ? TITLE_ESCROW_ADDRESS : null; - - const [mode, setMode] = useState("mint"); - const [activeTitleEscrow, setActiveTitleEscrow] = useState(null); - const [minting, setMinting] = useState(false); - const [beneficiary, setBeneficiary] = useState(""); - const [holder, setHolder] = useState(""); - const [tokenId, setTokenId] = useState(""); - const [remark, setRemark] = useState(""); - const [loadInput, setLoadInput] = useState(""); - const [loadError, setLoadError] = useState(null); - const [mintError, setMintError] = useState(null); - const [justMinted, setJustMinted] = useState(false); - const [justLoaded, setJustLoaded] = useState(false); - - useEffect(() => { - if (!address) { setActiveTitleEscrow(null); return; } - if (address.toLowerCase() === PERMANENT_OWNER && envEscrow) { - setActiveTitleEscrow(envEscrow); - onTitleEscrowReady(envEscrow); - return; - } - const saved = localStorage.getItem(LS_KEY); - if (saved) { setActiveTitleEscrow(saved); onTitleEscrowReady(saved as `0x${string}`); } - else setActiveTitleEscrow(null); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [address]); - - const isPermanentOwner = address?.toLowerCase() === PERMANENT_OWNER; - const disabled = !address || !paymasterAddress || !registryAddress; - - function randomTokenId(): string { - const bytes = crypto.getRandomValues(new Uint8Array(32)); - return BigInt("0x" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("")).toString(); - } - - function handleLoad() { - setLoadError(null); - const trimmed = loadInput.trim(); - if (!isAddress(trimmed)) { setLoadError("Invalid address."); return; } - localStorage.setItem(LS_KEY, trimmed); - setActiveTitleEscrow(trimmed); - setJustLoaded(true); - onTitleEscrowReady(trimmed as `0x${string}`); - } - - async function handleMint() { - if (!address || !paymasterAddress || !registryAddress) return; - if (!isAddress(beneficiary)) { setMintError("Invalid beneficiary address."); return; } - if (!isAddress(holder)) { setMintError("Invalid holder address."); return; } - setMintError(null); - setMinting(true); - try { - const publicClient = createPublicClient({ chain: sepolia, transport: http(SEPOLIA_RPC_URL) }); - const tid = tokenId.trim() ? BigInt(tokenId.trim()) : BigInt("0x" + - Array.from(crypto.getRandomValues(new Uint8Array(32))).map((b) => b.toString(16).padStart(2, "0")).join("")); - const remarkBytes: `0x${string}` = remark.trim() ? toHex(remark.trim()) : "0x"; - - const calldata = encodeFunctionData({ - abi: paymasterAbi, - functionName: "mintDocument", - args: [registryAddress as `0x${string}`, beneficiary as `0x${string}`, holder as `0x${string}`, tid, remarkBytes], - }); - - let txHash: `0x${string}`; - if (isDelegated) { - const { smartAccountClient } = await buildSmartAccountClient( - address as `0x${string}`, - paymasterAddress as `0x${string}`, - ); - txHash = await smartAccountClient.sendTransaction({ - to: paymasterAddress as `0x${string}`, - value: 0n, - data: calldata, - }) as `0x${string}`; - } else { - const walletClient = createWalletClient({ - account: address as `0x${string}`, - chain: sepolia, - transport: custom(window.ethereum), - }); - txHash = await walletClient.sendTransaction({ - to: paymasterAddress as `0x${string}`, - value: 0n, - data: calldata, - }); - await publicClient.waitForTransactionReceipt({ hash: txHash }); - } - - const receipt = await publicClient.getTransactionReceipt({ hash: txHash }); - const logs = parseEventLogs({ abi: paymasterAbi, logs: receipt.logs, eventName: "TitleEscrowLinked" }); - const escrowAddr = logs[0]?.args?.titleEscrow; - if (!escrowAddr) throw new Error("Mint succeeded but TitleEscrow address not found in logs"); - - localStorage.setItem(LS_KEY, escrowAddr); - setActiveTitleEscrow(escrowAddr); - setJustMinted(true); - onTitleEscrowReady(escrowAddr); - } catch (e: unknown) { - setMintError(e instanceof Error ? e.message : String(e)); - } finally { - setMinting(false); - } - } - - if (activeTitleEscrow) { - return ( -
-
-

Title Escrow

- - - {justMinted ? "Minted" : "Active"} - -
-
-
- Title Escrow: - - {activeTitleEscrow} - -
- {isPermanentOwner && ( -

Loaded from environment (permanent owner).

- )} - {justMinted && ( -

- Minted and saved to local storage. -

- )} - {justLoaded &&

Title escrow loaded.

} -
- {!isPermanentOwner && ( - - )} -
- ); - } - - return ( -
-
-

Title Escrow

- - - Not set - -
- - {!registryAddress && ( -

Set up a registry first.

- )} - -
- - -
- - {mode === "mint" ? ( -
-

- Mint a new trade document. This deploys a TitleEscrow and assigns the initial beneficiary and holder. -

- setBeneficiary(e.target.value)} disabled={disabled || minting} /> - setHolder(e.target.value)} disabled={disabled || minting} /> -
- setTokenId(e.target.value)} disabled={disabled || minting} /> - -
- setRemark(e.target.value)} disabled={disabled || minting} /> - -
-
- Registry: - {registryAddress ?? "—"} -
-
- - - {mintError &&

{mintError}

} -
- ) : ( -
-

Already have a title escrow? Paste the address — it will be saved in your browser.

- { setLoadInput(e.target.value); setLoadError(null); }} disabled={disabled} /> - - {loadError &&

{loadError}

} -
- )} -
- ); -} diff --git a/7702Frontend/src/components/TrustVCPanel.tsx b/7702Frontend/src/components/TrustVCPanel.tsx deleted file mode 100644 index feeff90..0000000 --- a/7702Frontend/src/components/TrustVCPanel.tsx +++ /dev/null @@ -1,379 +0,0 @@ -import { useState, useEffect, useCallback } from "react"; -import { encodeFunctionData, createPublicClient, createWalletClient, custom, http, keccak256, toBytes } from "viem"; -import { sepolia } from "viem/chains"; -import { buildSmartAccountClient, toRemarkBytes, getPublicClient } from "../lib/pimlico"; -import { SEPOLIA_RPC_URL } from "../lib/constants"; -import { TITLE_ESCROW_ABI, REGISTRY_ABI } from "../lib/abis"; - -const ZERO_ADDR = "0x0000000000000000000000000000000000000000"; -const MINTER_ROLE = keccak256(toBytes("MINTER_ROLE")); - -type Action = - | "nominate" - | "transferBeneficiary" - | "transferHolder" - | "transferOwners" - | "rejectBeneficiary" - | "rejectHolder" - | "rejectOwners" - | "returnToIssuer" - | "shred"; - -interface EscrowState { - beneficiary: string; - holder: string; - nominee: string; - prevBeneficiary: string; - prevHolder: string; - isHoldingToken: boolean; - isAcceptor: boolean; -} - -interface Props { - address: string | null; - isDelegated: boolean; - paymasterAddress: string | null; - titleEscrowAddress: string | null; - registryAddress: string | null; -} - -const ACTION_LABELS: Record = { - nominate: "Nominate", - transferBeneficiary: "Transfer Beneficiary", - transferHolder: "Transfer Holder", - transferOwners: "Transfer Owners", - rejectBeneficiary: "Reject (Beneficiary)", - rejectHolder: "Reject (Holder)", - rejectOwners: "Reject (Owners)", - returnToIssuer: "Return to Issuer", - shred: "Shred Document", -}; - -const ADDRESS_ACTIONS: Action[] = ["nominate", "transferBeneficiary", "transferHolder"]; -const DUAL_ADDRESS_ACTIONS: Action[] = ["transferOwners"]; -const REMARK_ONLY_ACTIONS: Action[] = ["rejectBeneficiary", "rejectHolder", "rejectOwners", "returnToIssuer", "shred"]; - -function computeAvailableActions( - escrow: EscrowState | null, - account: string | null, -): Action[] { - if (!escrow || !account) return []; - - const addr = account.toLowerCase(); - const isReturnedToIssuer = !escrow.isHoldingToken; - const isActiveTitleEscrow = !isReturnedToIssuer; - const isHolder = addr === escrow.holder.toLowerCase(); - const isBeneficiary = addr === escrow.beneficiary.toLowerCase(); - const isHolderAndBeneficiary = isHolder && isBeneficiary; - const hasNominee = !!escrow.nominee && escrow.nominee !== ZERO_ADDR; - const hasPrevBeneficiary = !!escrow.prevBeneficiary && escrow.prevBeneficiary !== ZERO_ADDR; - const hasPrevHolder = !!escrow.prevHolder && escrow.prevHolder !== ZERO_ADDR; - - const available: Action[] = []; - - // nominate: beneficiary-only (not holder+beneficiary) nominates a new beneficiary - if (isActiveTitleEscrow && isBeneficiary && !isHolder) - available.push("nominate"); - - // transferBeneficiary: holder+beneficiary direct transfer, OR holder endorsing a nominee - if (isActiveTitleEscrow && (isHolderAndBeneficiary || (isHolder && hasNominee))) - available.push("transferBeneficiary"); - - // transferHolder - if (isActiveTitleEscrow && isHolder) - available.push("transferHolder"); - - // transferOwners - if (isActiveTitleEscrow && isHolder && isBeneficiary) - available.push("transferOwners"); - - // rejectBeneficiary: beneficiary-only, has a previous beneficiary to revert to - if (!isHolderAndBeneficiary && isActiveTitleEscrow && isBeneficiary && hasPrevBeneficiary && !(isHolder && hasPrevHolder)) - available.push("rejectBeneficiary"); - - // rejectHolder: holder-only, has a previous holder to revert to - if (!isHolderAndBeneficiary && isActiveTitleEscrow && isHolder && hasPrevHolder && !(isBeneficiary && hasPrevBeneficiary)) - available.push("rejectHolder"); - - // rejectOwners: both holder+beneficiary, both have previous values - if (isActiveTitleEscrow && isHolderAndBeneficiary && hasPrevHolder && hasPrevBeneficiary) - available.push("rejectOwners"); - - // returnToIssuer: holder+beneficiary surrenders - if (isActiveTitleEscrow && isHolder && isBeneficiary) - available.push("returnToIssuer"); - - // shred: only acceptor (minter role on registry) after surrender - if (!isActiveTitleEscrow && isReturnedToIssuer && escrow.isAcceptor) - available.push("shred"); - - return available; -} - -export function TrustVCPanel({ address, isDelegated, paymasterAddress, titleEscrowAddress, registryAddress }: Props) { - const TITLE_ESCROW_ADDRESS = (titleEscrowAddress ?? "") as `0x${string}`; - const [escrowState, setEscrowState] = useState(null); - const [activeAction, setActiveAction] = useState(null); - const [targetAddress, setTargetAddress] = useState(""); - const [secondAddress, setSecondAddress] = useState(""); - const [remark, setRemark] = useState(""); - const [loading, setLoading] = useState(false); - const [lastTx, setLastTx] = useState<{ hash: string; gasless: boolean } | null>(null); - const [error, setError] = useState(null); - - const fetchEscrowState = useCallback(async () => { - if (!titleEscrowAddress) return; - try { - const publicClient = createPublicClient({ chain: sepolia, transport: http(SEPOLIA_RPC_URL) }); - const [beneficiary, holder, nominee, isHoldingToken, prevBeneficiary, prevHolder] = await Promise.all([ - publicClient.readContract({ address: TITLE_ESCROW_ADDRESS, abi: TITLE_ESCROW_ABI, functionName: "beneficiary" }), - publicClient.readContract({ address: TITLE_ESCROW_ADDRESS, abi: TITLE_ESCROW_ABI, functionName: "holder" }), - publicClient.readContract({ address: TITLE_ESCROW_ADDRESS, abi: TITLE_ESCROW_ABI, functionName: "nominee" }), - publicClient.readContract({ address: TITLE_ESCROW_ADDRESS, abi: TITLE_ESCROW_ABI, functionName: "isHoldingToken" }), - publicClient.readContract({ address: TITLE_ESCROW_ADDRESS, abi: TITLE_ESCROW_ABI, functionName: "prevBeneficiary" }), - publicClient.readContract({ address: TITLE_ESCROW_ADDRESS, abi: TITLE_ESCROW_ABI, functionName: "prevHolder" }), - ]); - - // Check if connected address has MINTER_ROLE on the registry (for shred/restore) - let isAcceptor = false; - if (address && registryAddress) { - try { - isAcceptor = await publicClient.readContract({ - address: registryAddress as `0x${string}`, - abi: REGISTRY_ABI, - functionName: "hasRole", - args: [MINTER_ROLE, address as `0x${string}`], - }) as boolean; - } catch { /* registry may not support hasRole */ } - } - - setEscrowState({ - beneficiary: beneficiary as string, - holder: holder as string, - nominee: nominee as string, - prevBeneficiary: prevBeneficiary as string, - prevHolder: prevHolder as string, - isHoldingToken: isHoldingToken as boolean, - isAcceptor, - }); - } catch (e) { - console.error("fetchEscrowState error:", e); - } - }, [TITLE_ESCROW_ADDRESS, address, registryAddress, titleEscrowAddress]); - - useEffect(() => { fetchEscrowState(); }, [fetchEscrowState]); - - // Auto-select first available action when conditions change - const availableActions = computeAvailableActions(escrowState, address); - useEffect(() => { - if (!activeAction || !availableActions.includes(activeAction)) { - setActiveAction(availableActions[0] ?? null); - } - }, [availableActions.join(",")]); // eslint-disable-line react-hooks/exhaustive-deps - - function buildCalldata(): `0x${string}` { - const remarkBytes = toRemarkBytes(remark); - switch (activeAction) { - case "nominate": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "nominate", args: [targetAddress as `0x${string}`, remarkBytes] }); - case "transferBeneficiary": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "transferBeneficiary", args: [targetAddress as `0x${string}`, remarkBytes] }); - case "transferHolder": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "transferHolder", args: [targetAddress as `0x${string}`, remarkBytes] }); - case "transferOwners": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "transferOwners", args: [targetAddress as `0x${string}`, secondAddress as `0x${string}`, remarkBytes] }); - case "rejectBeneficiary": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "rejectTransferBeneficiary", args: [remarkBytes] }); - case "rejectHolder": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "rejectTransferHolder", args: [remarkBytes] }); - case "rejectOwners": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "rejectTransferOwners", args: [remarkBytes] }); - case "returnToIssuer": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "returnToIssuer", args: [remarkBytes] }); - case "shred": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "shred", args: [remarkBytes] }); - default: - throw new Error("Unknown action"); - } - } - - async function handleSend() { - if (!address || !activeAction) return; - setError(null); - setLastTx(null); - setLoading(true); - try { - const calldata = buildCalldata(); - let txHash: string; - - if (isDelegated) { - const { smartAccountClient } = await buildSmartAccountClient( - address as `0x${string}`, - paymasterAddress as `0x${string}`, - ); - txHash = await smartAccountClient.sendTransaction({ to: TITLE_ESCROW_ADDRESS, value: 0n, data: calldata }); - } else { - const walletClient = createWalletClient({ account: address as `0x${string}`, chain: sepolia, transport: custom(window.ethereum) }); - txHash = await walletClient.sendTransaction({ to: TITLE_ESCROW_ADDRESS, value: 0n, data: calldata }); - await getPublicClient().waitForTransactionReceipt({ hash: txHash as `0x${string}` }); - } - - setLastTx({ hash: txHash, gasless: isDelegated }); - await fetchEscrowState(); - setTargetAddress(""); - setSecondAddress(""); - setRemark(""); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : String(e)); - } finally { - setLoading(false); - } - } - - const disabled = !address || !!!paymasterAddress || !titleEscrowAddress; - const needsAddress = activeAction ? ADDRESS_ACTIONS.includes(activeAction) : false; - const needsDualAddress = activeAction ? DUAL_ADDRESS_ACTIONS.includes(activeAction) : false; - const isRemarkOnly = activeAction ? REMARK_ONLY_ACTIONS.includes(activeAction) : false; - - const canSend = - !disabled && - !loading && - !!activeAction && - (isRemarkOnly || - (needsAddress && targetAddress.startsWith("0x")) || - (needsDualAddress && targetAddress.startsWith("0x") && secondAddress.startsWith("0x"))); - - return ( -
-
-

TrustVC Operations

- {isDelegated - ? gasless via UserOp - : regular tx · pays gas} -
- - {!address &&

Connect wallet first.

} - {address && !!!paymasterAddress &&

Set up a paymaster first.

} - {address && !!paymasterAddress && !titleEscrowAddress &&

Set up a title escrow first.

} - - {/* TitleEscrow state */} - {escrowState && ( -
-

TitleEscrow State

- - - - {escrowState.prevBeneficiary !== ZERO_ADDR && ( - - )} - {escrowState.prevHolder !== ZERO_ADDR && ( - - )} -
- Status: - - {escrowState.isHoldingToken ? "Active" : "Returned to issuer"} - -
- -
- )} - - {/* Action selector — only available actions */} - {availableActions.length === 0 && !disabled && ( -

No actions available for your address on this document.

- )} - - {availableActions.length > 0 && ( -
-

Action

-
- {availableActions.map((action) => ( - - ))} -
-
- )} - - {/* Inputs */} - {activeAction && availableActions.length > 0 && ( -
- {(needsAddress || needsDualAddress) && ( - setTargetAddress(e.target.value)} - disabled={disabled} - /> - )} - {needsDualAddress && ( - setSecondAddress(e.target.value)} - disabled={disabled} - /> - )} - setRemark(e.target.value)} - disabled={disabled} - /> -
- )} - - {activeAction && availableActions.length > 0 && ( - - )} - - {lastTx && ( -
-

- Transaction confirmed ✓ {lastTx.gasless ? "(gasless)" : "(gas paid)"} -

- - {lastTx.hash} - -
- )} - {error &&

{error}

} -
- ); -} - -function StateRow({ label, value, highlight }: { label: string; value: string; highlight?: boolean }) { - return ( -
- {label}: - {value} -
- ); -} diff --git a/7702Frontend/src/components/WalletConnect.tsx b/7702Frontend/src/components/WalletConnect.tsx deleted file mode 100644 index 83f0317..0000000 --- a/7702Frontend/src/components/WalletConnect.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { useState, useEffect } from "react"; -import { ethers } from "ethers"; -import { SEPOLIA_CHAIN_ID } from "../lib/constants"; - -interface Props { - address: string | null; - onConnect: (address: string) => void; - onDisconnect: () => void; -} - -export function WalletConnect({ address, onConnect, onDisconnect }: Props) { - const [balance, setBalance] = useState(null); - const [network, setNetwork] = useState(null); - const [error, setError] = useState(null); - - useEffect(() => { - if (!address) return; - (async () => { - try { - const provider = new ethers.BrowserProvider(window.ethereum); - const bal = await provider.getBalance(address); - setBalance(ethers.formatEther(bal).slice(0, 7)); - const net = await provider.getNetwork(); - setNetwork(net.chainId.toString()); - } catch { - // ignore - } - })(); - }, [address]); - - async function connect() { - setError(null); - if (!window.ethereum) { - setError("MetaMask not detected. Install the Chrome extension."); - return; - } - try { - const provider = new ethers.BrowserProvider(window.ethereum); - // Switch to Sepolia first - try { - await window.ethereum.request({ - method: "wallet_switchEthereumChain", - params: [{ chainId: `0x${SEPOLIA_CHAIN_ID.toString(16)}` }], - }); - } catch { - // chain not added — ignore, user can add manually - } - const accounts = await provider.send("eth_requestAccounts", []); - onConnect(accounts[0] as string); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : "Connection rejected"); - } - } - - const isWrongNetwork = network && network !== SEPOLIA_CHAIN_ID.toString(); - - return ( -
-
-

Wallet

- {address ? ( -
- {address} - {balance && ( - {balance} ETH - )} - {isWrongNetwork && ( - Wrong network — switch to Sepolia - )} - {!isWrongNetwork && network && ( - Sepolia - )} -
- ) : ( -

Not connected

- )} - {error &&

{error}

} -
- - {address ? ( - - ) : ( - - )} -
- ); -} diff --git a/7702Frontend/src/index.css b/7702Frontend/src/index.css deleted file mode 100644 index 078bad1..0000000 --- a/7702Frontend/src/index.css +++ /dev/null @@ -1,42 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer base { - body { - @apply bg-gray-950 text-gray-100 font-mono; - } -} - -@layer components { - .panel { - @apply bg-gray-900 border border-gray-700 rounded-xl p-5; - } - .panel-title { - @apply text-sm font-semibold text-indigo-400 uppercase tracking-widest mb-4; - } - .btn { - @apply px-4 py-2 rounded-lg text-sm font-semibold transition-all duration-150 disabled:opacity-40 disabled:cursor-not-allowed; - } - .btn-primary { - @apply btn bg-indigo-600 hover:bg-indigo-500 text-white; - } - .btn-danger { - @apply btn bg-red-700 hover:bg-red-600 text-white; - } - .btn-ghost { - @apply btn bg-gray-800 hover:bg-gray-700 text-gray-300; - } - .input { - @apply bg-gray-800 border border-gray-600 rounded-lg px-3 py-2 text-sm text-gray-100 outline-none focus:border-indigo-500 w-full; - } - .badge-green { - @apply inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-semibold bg-emerald-900/60 text-emerald-300 border border-emerald-700; - } - .badge-yellow { - @apply inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-semibold bg-yellow-900/60 text-yellow-300 border border-yellow-700; - } - .badge-red { - @apply inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-semibold bg-red-900/60 text-red-300 border border-red-700; - } -} diff --git a/7702Frontend/src/lib/abis.ts b/7702Frontend/src/lib/abis.ts deleted file mode 100644 index 37d7e5c..0000000 --- a/7702Frontend/src/lib/abis.ts +++ /dev/null @@ -1,224 +0,0 @@ -export const ENTRY_POINT_ABI = [ - { - type: "function", - name: "getNonce", - inputs: [ - { name: "sender", type: "address" }, - { name: "key", type: "uint192" }, - ], - outputs: [{ name: "", type: "uint256" }], - stateMutability: "view", - }, -] as const; - -export const IMPL_ABI = [ - { - type: "function", - name: "execute", - inputs: [ - { name: "to", type: "address" }, - { name: "value", type: "uint256" }, - { name: "data", type: "bytes" }, - ], - outputs: [{ name: "", type: "bytes" }], - stateMutability: "payable", - }, -] as const; - -export const STORAGE_ABI = [ - { - type: "function", - name: "create", - inputs: [{ name: "_data", type: "string" }], - outputs: [{ name: "", type: "uint256" }], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "update", - inputs: [ - { name: "_id", type: "uint256" }, - { name: "_newData", type: "string" }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "remove", - inputs: [{ name: "_id", type: "uint256" }], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "exists", - inputs: [{ name: "_id", type: "uint256" }], - outputs: [{ name: "", type: "bool" }], - stateMutability: "view", - }, - { - type: "function", - name: "getItemCount", - inputs: [], - outputs: [{ name: "", type: "uint256" }], - stateMutability: "view", - }, - { - type: "event", - name: "ItemCreated", - inputs: [ - { name: "id", type: "uint256", indexed: true }, - { name: "data", type: "string", indexed: false }, - { name: "timestamp", type: "uint256", indexed: false }, - ], - }, - { - type: "event", - name: "ItemUpdated", - inputs: [ - { name: "id", type: "uint256", indexed: true }, - { name: "data", type: "string", indexed: false }, - { name: "timestamp", type: "uint256", indexed: false }, - ], - }, - { - type: "event", - name: "ItemDeleted", - inputs: [{ name: "id", type: "uint256", indexed: true }], - }, -] as const; - -export const TITLE_ESCROW_ABI = [ - { - type: "function", - name: "nominate", - inputs: [ - { name: "_nominee", type: "address" }, - { name: "_remark", type: "bytes" }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "transferBeneficiary", - inputs: [ - { name: "_nominee", type: "address" }, - { name: "_remark", type: "bytes" }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "transferHolder", - inputs: [ - { name: "newHolder", type: "address" }, - { name: "_remark", type: "bytes" }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "transferOwners", - inputs: [ - { name: "_nominee", type: "address" }, - { name: "newHolder", type: "address" }, - { name: "_remark", type: "bytes" }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "rejectTransferBeneficiary", - inputs: [{ name: "_remark", type: "bytes" }], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "rejectTransferHolder", - inputs: [{ name: "_remark", type: "bytes" }], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "rejectTransferOwners", - inputs: [{ name: "_remark", type: "bytes" }], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "returnToIssuer", - inputs: [{ name: "_remark", type: "bytes" }], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "shred", - inputs: [{ name: "_remark", type: "bytes" }], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "beneficiary", - inputs: [], - outputs: [{ name: "", type: "address" }], - stateMutability: "view", - }, - { - type: "function", - name: "holder", - inputs: [], - outputs: [{ name: "", type: "address" }], - stateMutability: "view", - }, - { - type: "function", - name: "nominee", - inputs: [], - outputs: [{ name: "", type: "address" }], - stateMutability: "view", - }, - { - type: "function", - name: "isHoldingToken", - inputs: [], - outputs: [{ name: "", type: "bool" }], - stateMutability: "view", - }, - { - type: "function", - name: "prevBeneficiary", - inputs: [], - outputs: [{ name: "", type: "address" }], - stateMutability: "view", - }, - { - type: "function", - name: "prevHolder", - inputs: [], - outputs: [{ name: "", type: "address" }], - stateMutability: "view", - }, -] as const; - -export const REGISTRY_ABI = [ - { - type: "function", - name: "hasRole", - inputs: [ - { name: "role", type: "bytes32" }, - { name: "account", type: "address" }, - ], - outputs: [{ name: "", type: "bool" }], - stateMutability: "view", - }, -] as const; diff --git a/7702Frontend/src/lib/constants.ts b/7702Frontend/src/lib/constants.ts deleted file mode 100644 index a0b6d15..0000000 --- a/7702Frontend/src/lib/constants.ts +++ /dev/null @@ -1,23 +0,0 @@ -export const PAYMASTER_ADDRESS = (import.meta.env.VITE_PAYMASTER_ADDRESS ?? - "") as `0x${string}`; - -export const TDOC_IMPLEMENTATION = (import.meta.env.VITE_TDOC_IMPLEMENTATION ?? - "") as `0x${string}`; - -export const REGISTRY_ADDRESS = (import.meta.env.VITE_REGISTRY_ADDRESS ?? - "") as `0x${string}`; - -export const TITLE_ESCROW_ADDRESS = (import.meta.env - .VITE_TITLE_ESCROW_ADDRESS ?? "") as `0x${string}`; - -export const FACTORY_ADDRESS = (import.meta.env.VITE_FACTORY_ADDRESS ?? - "") as `0x${string}`; - -export const PIMLICO_API_KEY = import.meta.env.VITE_PIMLICO_API_KEY ?? ""; - -export const SEPOLIA_RPC_URL = - import.meta.env.VITE_SEPOLIA_RPC_URL ?? "https://rpc.sepolia.org"; - -export const PIMLICO_URL = `https://api.pimlico.io/v2/11155111/rpc?apikey=${PIMLICO_API_KEY}`; - -export const SEPOLIA_CHAIN_ID = 11155111; diff --git a/7702Frontend/src/lib/pimlico.ts b/7702Frontend/src/lib/pimlico.ts deleted file mode 100644 index f519f8b..0000000 --- a/7702Frontend/src/lib/pimlico.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { - createPublicClient, - createWalletClient, - custom, - http, - toHex, -} from "viem"; -import { entryPoint08Address } from "viem/account-abstraction"; -import { sepolia } from "viem/chains"; -import { createPimlicoClient } from "permissionless/clients/pimlico"; -import { createSmartAccountClient } from "permissionless"; -import { to7702SimpleSmartAccount } from "permissionless/accounts"; - -import { PAYMASTER_ADDRESS, PIMLICO_URL, SEPOLIA_RPC_URL } from "./constants"; - -// permissionless's EIP-7702 compatible SimpleAccount for v0.8 -export const PERMISSIONLESS_IMPL = - "0xe6Cae83BdE06E4c305530e199D7217f42808555B" as const; - -export function getPublicClient() { - return createPublicClient({ - chain: sepolia, - transport: http(SEPOLIA_RPC_URL), - }); -} - -export async function checkDelegation(address: `0x${string}`) { - const publicClient = getPublicClient(); - const code = await publicClient.getCode({ address }); - if (!code || code === "0x") return null; - if (code.startsWith("0xef0100")) { - return `0x${code.slice(8, 48)}` as `0x${string}`; - } - return null; -} - -export async function buildSmartAccountClient( - ownerAddress: `0x${string}`, - paymasterOverride?: `0x${string}`, -) { - if (!window.ethereum) throw new Error("MetaMask not found"); - - const PAYMASTER = paymasterOverride ?? PAYMASTER_ADDRESS; - if (!PAYMASTER || PAYMASTER === "0x") - throw new Error("No paymaster address configured"); - - const walletClient = createWalletClient({ - account: ownerAddress, - chain: sepolia, - transport: custom(window.ethereum), - }); - - const publicClient = getPublicClient(); - - const pimlicoClient = createPimlicoClient({ - transport: http(PIMLICO_URL), - entryPoint: { address: entryPoint08Address, version: "0.8" }, - }); - - const account = await to7702SimpleSmartAccount({ - client: publicClient, - owner: walletClient, - }); - - const smartAccountClient = createSmartAccountClient({ - account, - chain: sepolia, - bundlerTransport: http(PIMLICO_URL), - client: publicClient, - // Custom PlatformPaymaster — validates on-chain, no off-chain signature needed - paymaster: { - async getPaymasterStubData() { - return { - paymaster: PAYMASTER as `0x${string}`, - paymasterData: "0x" as `0x${string}`, - paymasterVerificationGasLimit: 300_000n, - paymasterPostOpGasLimit: 150_000n, - isFinal: false, - }; - }, - async getPaymasterData() { - return { - paymaster: PAYMASTER as `0x${string}`, - paymasterData: "0x" as `0x${string}`, - paymasterVerificationGasLimit: 300_000n, - paymasterPostOpGasLimit: 150_000n, - }; - }, - }, - userOperation: { - estimateFeesPerGas: async () => { - const { fast } = await pimlicoClient.getUserOperationGasPrice(); - return { - maxFeePerGas: fast.maxFeePerGas, - maxPriorityFeePerGas: fast.maxPriorityFeePerGas, - }; - }, - }, - }); - - return { smartAccountClient, publicClient }; -} - -export function toRemarkBytes(s: string): `0x${string}` { - return toHex(s); -} diff --git a/7702Frontend/src/main.tsx b/7702Frontend/src/main.tsx deleted file mode 100644 index 12fa35b..0000000 --- a/7702Frontend/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { StrictMode } from "react"; -import { createRoot } from "react-dom/client"; -import "./index.css"; -import App from "./App"; - -createRoot(document.getElementById("root")!).render( - - - -); diff --git a/7702Frontend/src/vite-env.d.ts b/7702Frontend/src/vite-env.d.ts deleted file mode 100644 index b50dcfa..0000000 --- a/7702Frontend/src/vite-env.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// - -interface Window { - ethereum: import("ethers").Eip1193Provider & { - request: (args: { method: string; params?: unknown[] }) => Promise; - on: (event: string, handler: (...args: unknown[]) => void) => void; - }; -} diff --git a/7702Frontend/tailwind.config.js b/7702Frontend/tailwind.config.js deleted file mode 100644 index f61974c..0000000 --- a/7702Frontend/tailwind.config.js +++ /dev/null @@ -1,12 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -export default { - content: ["./index.html", "./src/**/*.{ts,tsx}"], - theme: { - extend: { - colors: { - brand: "#6366f1", - }, - }, - }, - plugins: [], -}; diff --git a/7702Frontend/tsconfig.json b/7702Frontend/tsconfig.json deleted file mode 100644 index 6bfa73a..0000000 --- a/7702Frontend/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - "strict": true, - "noUnusedLocals": false, - "noUnusedParameters": false, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/7702Frontend/vite.config.ts b/7702Frontend/vite.config.ts deleted file mode 100644 index 75e3905..0000000 --- a/7702Frontend/vite.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineConfig } from "vite"; -import react from "@vitejs/plugin-react"; - -export default defineConfig({ - plugins: [react()], - define: { - global: "globalThis", - }, -}); diff --git a/EIP7702_METAMASK_ARCHITECTURE.md b/EIP7702_METAMASK_ARCHITECTURE.md deleted file mode 100644 index 3769512..0000000 --- a/EIP7702_METAMASK_ARCHITECTURE.md +++ /dev/null @@ -1,120 +0,0 @@ -# EIP-7702 + MetaMask Architecture - -## The Core Problem - -MetaMask does **not** support `wallet_signAuthorization`. -Ethers `signer.authorize()` also fails with MetaMask (`UNSUPPORTED_OPERATION`). -The current `wallet_signAuthorization` wrapper in `pimlico.ts` is dead code that will throw at runtime. - ---- - -## Architecture Options - -### Option A — SimpleAccount (ERC-4337) `scripts/metamaskDelegation/` - -**Status: Scripts written, CLI-testable today.** - -``` -EOA: 0xABC → SimpleAccount: 0xABC_SA (different address) -``` - -| Step | Script | -|------|--------| -| Print SimpleAccount address | `printAddress.ts` | -| Whitelist for platform ops | `whitelistAccount.ts` | -| Deploy registry (gasless) | `deployRegistryGasless.ts` | -| Mint document (gasless) | `mintDocumentGasless.ts` | -| Transfer holder (gasless) | `transferHolder.ts` | -| Nominate (gasless) | `nominate.ts` | - -**Paymaster interaction:** -- Path A (TitleEscrow calls): target = TitleEscrow → `authorizedTitleEscrows[target]` → **any sender accepted, no whitelist** -- Path B (platform ops): target = paymaster → `userWhitelist[0xABC_SA]` must be > 0 - -**Problem:** `holder` in TitleEscrow becomes `0xABC_SA`, not `0xABC`. User rejected this — holder must stay `0xABC` (EOA address). - ---- - -### Option B — Rabby Wallet + EIP-7702 ✓ **Cleanest browser solution** - -``` -Rabby signs EIP-7702 natively → holder = 0xABC (EOA address preserved) -``` - -Rabby supports EIP-7702 delegation in-browser without any special API. No `wallet_signAuthorization` needed. The delegation signature is bundled into the transaction automatically. - -**Problem:** Users must install Rabby. Not a MetaMask solution. - ---- - -### Option C — `wallet_grantPermissions` (ERC-7715) + Session Key **Best UX for MetaMask** - -**Status: Not yet implemented. MetaMask supports ERC-7715.** - -``` -ONE-TIME SETUP (user approves once in MetaMask popup): - wallet_grantPermissions({ - signer: { type: "key", data: { id: 0xDEF } }, // session key from Privy/Dynamic - permissions: [...], - ... - }) - → MetaMask: signs EIP-7702 auth (upgrades 0xABC to smart account) - + signs delegation granting 0xDEF permission - -FIRST UserOp (atomic): - userOp.sender = 0xABC ← EOA address preserved ✓ - userOp.eip7702Auth = signed auth ← upgrades 0xABC in same tx - userOp.signature = 0xDEF sig + delegation proof - callData = execute(TitleEscrow, 0, transferHolder(...)) - -SUBSEQUENT UserOps (silent, no popup): - userOp.sender = 0xABC - userOp.signature = 0xDEF sig + stored delegation proof - callData = execute(TitleEscrow, 0, ...) -``` - -#### Paymaster whitelist in this flow - -| Operation | `userOp.sender` | Path | Whitelist? | -|-----------|-----------------|------|------------| -| TitleEscrow calls | `0xABC` | A (target = TitleEscrow) | **No** | -| deployRegistry / mintDocument | `0xABC` | B (target = paymaster) | **Yes — whitelist `0xABC`** | - -`0xDEF` is only in the signature field — **never appears as `userOp.sender`**, never needs whitelisting. - -#### Critical blocker - -MetaMask's **Hybrid / Delegation Toolkit** uses **EntryPoint v0.7**. -Our `PlatformPaymaster` uses **EntryPoint v0.8**. -These are incompatible — the paymaster will reject v0.7 UserOps with AA33. - -Resolution options: -1. Deploy a second `PlatformPaymaster` targeting v0.7 EntryPoint -2. Wait for MetaMask to upgrade Delegation Toolkit to v0.8 -3. Use a different wallet that supports EIP-7702 + v0.8 (Privy embedded wallet, Dynamic, etc.) - ---- - -## EntryPoint Versions Quick Reference - -| Component | EntryPoint | -|-----------|-----------| -| `PlatformPaymaster` | **v0.8** `0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108` | -| `to7702SimpleSmartAccount` (permissionless) | **v0.8** | -| `toSimpleSmartAccount` (permissionless) | v0.7 default, **pass v0.8 explicitly** | -| MetaMask Delegation Toolkit | **v0.7** ← incompatible | -| v0.8 SimpleAccount factory (Sepolia) | `0x13E9ed32155810FDbd067D4522C492D6f68E5944` | - ---- - -## Files To Fix (pimlico.ts / DelegationPanel.tsx) - -- `7702Frontend/src/lib/pimlico.ts` — `wallet_signAuthorization` wrapper is broken dead code; remove it -- `7702Frontend/src/components/DelegationPanel.tsx` — shows "auto-delegation on first transaction" which is incorrect; update messaging to reflect actual wallet support status - ---- - -## Decision Pending - -- Pursue Option C (`wallet_grantPermissions`) → resolve EntryPoint v0.7/v0.8 mismatch first -- Or go with Rabby wallet for browser flow + CLI scripts for all other users diff --git a/PIMLICO_EIP7702_DOCS.md b/PIMLICO_EIP7702_DOCS.md deleted file mode 100644 index f116223..0000000 --- a/PIMLICO_EIP7702_DOCS.md +++ /dev/null @@ -1,315 +0,0 @@ -# EIP-7702 + Pimlico Integration — Developer Reference - -## Table of Contents - -1. [How Pimlico Works](#1-how-pimlico-works) -2. [API Key Setup](#2-api-key-setup) -3. [How PaymasterV2 Works](#3-how-paymasterv2-works) -4. [Registry Whitelisting](#4-registry-whitelisting) -5. [Function Reference](#5-function-reference) - ---- - -## 1. How Pimlico Works - -### EIP-7702 in one line - -EIP-7702 lets a regular wallet (EOA) temporarily point to a smart contract -implementation. From that point on, calling the EOA executes smart contract -logic — without deploying a new contract address. - -### The delegation (one-time, per EOA) - -Before any sponsored transaction can be sent, the EOA must be delegated to -our implementation contract. This is a standard Ethereum type-4 transaction -paid by the operator wallet (`PRIVATE_KEY`). The end user only signs an -authorization — no ETH required on their side. - -``` -OWNER_PRIVATE_KEY → end user / holder — signs UserOps, zero ETH needed -PRIVATE_KEY → operator — pays for the one-time delegation tx only -``` - -After delegation, the EOA's on-chain code becomes: - -``` -0xef0100 + 0xECD2812e299c6aD5C3B1F11B91D8Cab83003E09D -``` - -### UserOperation flow (every transaction after delegation) - -``` -User signs UserOp (OWNER_PRIVATE_KEY, raw ECDSA — no ETH) - ↓ -Pimlico Bundler receives the UserOp - ↓ -PaymasterV2 validates and agrees to sponsor gas - ↓ -EntryPoint (0x0000000071727De22E5E9d8BAf0edAc6f37da032) executes - ↓ -EOA's delegated implementation calls execute(to, value, data) - ↓ -Target contract function runs (e.g. nominate(), transferHolder()) -``` - -The end user never touches ETH. Gas is deducted from the paymaster's -pre-funded deposit in the EntryPoint. - -### Key contracts on Sepolia - -| Role | Address | -| ------------------ | -------------------------------------------- | -| EntryPoint v0.7 | `0x0000000071727De22E5E9d8BAf0edAc6f37da032` | -| EOA Implementation | `0xECD2812e299c6aD5C3B1F11B91D8Cab83003E09D` | -| PaymasterV2 | `0xbdd57218ac281eE281A92051C699751738E687Be` | - ---- - -## 2. API Key Setup - -### Get a free Pimlico API key - -1. Go to [dashboard.pimlico.io](https://dashboard.pimlico.io) -2. Create a project → copy the API key -3. Add to your `.env`: - -```env -PIMLICO_API_KEY=your_key_here -OWNER_PRIVATE_KEY=0x... # end user's private key -PRIVATE_KEY=0x... # operator wallet (needs Sepolia ETH) -SEPOLIA_RPC_URL=https://... -REGISTRY_ADDRESS=0x145c2dae82b2717267e2da0c8525f4aed796a120 -``` - -### How it is used in code - -```typescript -const PIMLICO_URL = - `https://api.pimlico.io/v2/11155111/rpc?apikey=${process.env.PIMLICO_API_KEY}`; - -// Pimlico client — handles gas pricing and UserOp submission -const pimlicoClient = createPimlicoClient({ - transport: http(PIMLICO_URL), - entryPoint: { address: ENTRY_POINT, version: "0.7" }, -}); - -// Smart account client — converts sendTransaction() into a UserOp -const smartAccountClient = createSmartAccountClient({ - account: smartAccount, - bundlerTransport: http(PIMLICO_URL), // UserOps go to Pimlico - client: publicClient, // eth_* calls go to your own node - paymaster: { ... }, // PaymasterV2 wired here -}); -``` - -Pimlico is only used for two things: - -- `eth_estimateUserOperationGas` — estimate gas for the UserOp -- `eth_sendUserOperation` — submit the UserOp to the mempool - -All other calls (`eth_getCode`, `eth_getTransactionCount`, etc.) go through -your own `SEPOLIA_RPC_URL`, keeping costs low. - ---- - -## 3. How PaymasterV2 Works - -PaymasterV2 is a custom on-chain paymaster that sponsors gas for UserOps -targeting authorized contracts. No off-chain signing service is required — -all validation happens on-chain. - -### Validation logic (`_validatePaymasterUserOp`) - -Every UserOp goes through this check before gas is committed: - -``` -1. callData length ≥ 36 bytes (must contain at least a selector + address) -2. Selector == execute(address,uint256,bytes) (only our implementation's execute) -3. Decoded `to` address ∈ authorizedRegistries (target must be whitelisted) -4. dailySpend[sender] + maxCost ≤ dailyLimit (per-user daily cap, 0 = no cap) -``` - -If any check fails, the UserOp is rejected — no gas is spent. - -### Gas sponsorship flow - -``` -UserOp arrives at EntryPoint - ↓ -EntryPoint calls PaymasterV2.validatePaymasterUserOp() - ↓ (all 4 checks pass) -EntryPoint executes the UserOp - ↓ -EntryPoint calls PaymasterV2.postOp(actualGasCost) - ↓ -PaymasterV2 records dailySpend[sender] += actualGasCost - ↓ -Gas deducted from PaymasterV2's deposit in EntryPoint -``` - -### Deployed configuration - -``` -Address: 0xbdd57218ac281eE281A92051C699751738E687Be -EntryPoint: 0x0000000071727De22E5E9d8BAf0edAc6f37da032 -Authorized registry: 0x145c2dae82b2717267e2da0c8525f4aed796a120 (TR contract) -Daily limit: 0 (no cap) -``` - ---- - -## 4. Registry Whitelisting - -PaymasterV2 uses a mapping to control which target contracts it will sponsor: - -```solidity -mapping(address => bool) public authorizedRegistries; -``` - -Only UserOps whose `execute()` call targets a whitelisted registry are -sponsored. Calls to any other address are rejected with `"unauthorized target"`. - -### Add a registry (owner only) - -```solidity -function addRegistry(address registry) external onlyOwner -``` - -Script call: - -```typescript -await walletClient.writeContract({ - address: "0xbdd57218ac281eE281A92051C699751738E687Be", - abi: parseAbi(["function addRegistry(address) external"]), - functionName: "addRegistry", - args: ["0xYourNewRegistryAddress"], -}); -``` - -### Remove a registry (owner only) - -```solidity -function removeRegistry(address registry) external onlyOwner -``` - -### Check if a registry is authorized - -```typescript -const ok = await publicClient.readContract({ - address: "0xbdd57218ac281eE281A92051C699751738E687Be", - abi: parseAbi(["function authorizedRegistries(address) view returns (bool)"]), - functionName: "authorizedRegistries", - args: ["0x145c2dae82b2717267e2da0c8525f4aed796a120"], -}); -// ok === true -``` - -> **Note:** The paymaster does NOT whitelist users. Any EOA delegated to the -> implementation can call any authorized registry — access control is enforced -> by the TR contract itself (e.g. `require(msg.sender == holder)`). - ---- - -## 5. Function Reference - -All scripts live in `scripts/trFunctions/`. Run any of them with: - -```bash -npx hardhat run scripts/trFunctions/