@aastar/sdk 0.17.7 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/LICENSE +180 -0
  2. package/dist/UserClient-YUHCJJJL.js +6 -0
  3. package/dist/UserClient-YUHCJJJL.js.map +1 -0
  4. package/dist/account.d.ts +1 -0
  5. package/dist/account.js +6 -0
  6. package/dist/account.js.map +1 -0
  7. package/dist/admin.d.ts +1 -0
  8. package/dist/admin.js +6 -0
  9. package/dist/admin.js.map +1 -0
  10. package/dist/airaccount.d.ts +2 -0
  11. package/dist/airaccount.js +4501 -0
  12. package/dist/airaccount.js.map +1 -0
  13. package/dist/channel.d.ts +1 -0
  14. package/dist/channel.js +6 -0
  15. package/dist/channel.js.map +1 -0
  16. package/dist/chunk-4DVUM4MC.js +106 -0
  17. package/dist/chunk-4DVUM4MC.js.map +1 -0
  18. package/dist/chunk-4KRQXOTI.js +4421 -0
  19. package/dist/chunk-4KRQXOTI.js.map +1 -0
  20. package/dist/chunk-6JCYPTSH.js +281 -0
  21. package/dist/chunk-6JCYPTSH.js.map +1 -0
  22. package/dist/chunk-DI3E6PMI.js +426 -0
  23. package/dist/chunk-DI3E6PMI.js.map +1 -0
  24. package/dist/chunk-DSZ372PH.js +333 -0
  25. package/dist/chunk-DSZ372PH.js.map +1 -0
  26. package/dist/chunk-HVAB4TTT.js +116 -0
  27. package/dist/chunk-HVAB4TTT.js.map +1 -0
  28. package/dist/chunk-MPOMWT2J.js +1140 -0
  29. package/dist/chunk-MPOMWT2J.js.map +1 -0
  30. package/dist/chunk-NZGXB2C5.js +115 -0
  31. package/dist/chunk-NZGXB2C5.js.map +1 -0
  32. package/dist/chunk-O3Y7II3B.js +578 -0
  33. package/dist/chunk-O3Y7II3B.js.map +1 -0
  34. package/dist/chunk-OSPRJZ5T.js +113 -0
  35. package/dist/chunk-OSPRJZ5T.js.map +1 -0
  36. package/dist/chunk-PCLPYRTX.js +229 -0
  37. package/dist/chunk-PCLPYRTX.js.map +1 -0
  38. package/dist/chunk-PZ5AY32C.js +9 -0
  39. package/dist/chunk-PZ5AY32C.js.map +1 -0
  40. package/dist/chunk-XFI3AK32.js +416 -0
  41. package/dist/chunk-XFI3AK32.js.map +1 -0
  42. package/dist/chunk-YHM77LIP.js +432 -0
  43. package/dist/chunk-YHM77LIP.js.map +1 -0
  44. package/dist/chunk-ZSSNU3UF.js +42091 -0
  45. package/dist/chunk-ZSSNU3UF.js.map +1 -0
  46. package/dist/contract-addresses-JE3X6DFY.js +4 -0
  47. package/dist/contract-addresses-JE3X6DFY.js.map +1 -0
  48. package/dist/core.d.ts +13 -0
  49. package/dist/core.js +5 -0
  50. package/dist/core.js.map +1 -0
  51. package/dist/dapp.d.ts +1 -0
  52. package/dist/dapp.js +7 -0
  53. package/dist/dapp.js.map +1 -0
  54. package/dist/dist-GHTBO7CD.js +6 -0
  55. package/dist/dist-GHTBO7CD.js.map +1 -0
  56. package/dist/enduser.d.ts +1 -0
  57. package/dist/enduser.js +7 -0
  58. package/dist/enduser.js.map +1 -0
  59. package/dist/identity.d.ts +1 -0
  60. package/dist/identity.js +6 -0
  61. package/dist/identity.js.map +1 -0
  62. package/dist/index.d.ts +603 -12
  63. package/dist/index.js +1640 -26
  64. package/dist/index.js.map +1 -0
  65. package/dist/index.node-55LOPHNQ.js +5 -0
  66. package/dist/index.node-55LOPHNQ.js.map +1 -0
  67. package/dist/lib-VRTYVDUO.js +1861 -0
  68. package/dist/lib-VRTYVDUO.js.map +1 -0
  69. package/dist/operator.d.ts +1 -0
  70. package/dist/operator.js +6 -0
  71. package/dist/operator.js.map +1 -0
  72. package/dist/paymaster.d.ts +1 -0
  73. package/dist/paymaster.js +6 -0
  74. package/dist/paymaster.js.map +1 -0
  75. package/dist/tokens.d.ts +1 -0
  76. package/dist/tokens.js +6 -0
  77. package/dist/tokens.js.map +1 -0
  78. package/dist/x402.d.ts +1 -0
  79. package/dist/x402.js +6 -0
  80. package/dist/x402.js.map +1 -0
  81. package/package.json +89 -18
  82. package/dist/clients/ExperimentClient.d.ts +0 -34
  83. package/dist/clients/ExperimentClient.js +0 -58
  84. package/dist/clients/admin.d.ts +0 -11
  85. package/dist/clients/admin.js +0 -20
  86. package/dist/clients/community.d.ts +0 -40
  87. package/dist/clients/community.js +0 -300
  88. package/dist/clients/endUser.d.ts +0 -77
  89. package/dist/clients/endUser.js +0 -298
  90. package/dist/clients/operator.d.ts +0 -66
  91. package/dist/clients/operator.js +0 -209
  92. package/dist/errors/decoder.d.ts +0 -6
  93. package/dist/errors/decoder.js +0 -44
  94. package/dist/utils/errorHandler.d.ts +0 -40
  95. package/dist/utils/errorHandler.js +0 -114
  96. package/dist/utils/funding.d.ts +0 -115
  97. package/dist/utils/funding.js +0 -188
  98. package/dist/utils/keys.d.ts +0 -61
  99. package/dist/utils/keys.js +0 -130
  100. package/dist/utils/roleData.d.ts +0 -66
  101. package/dist/utils/roleData.js +0 -128
  102. package/dist/utils/testScenarios.d.ts +0 -33
  103. package/dist/utils/testScenarios.js +0 -85
  104. package/dist/utils/userOp.d.ts +0 -89
  105. package/dist/utils/userOp.js +0 -231
package/dist/index.js CHANGED
@@ -1,26 +1,1640 @@
1
- export * from '@aastar/core';
2
- export * from '@aastar/account';
3
- export * from '@aastar/paymaster';
4
- export * from '@aastar/identity';
5
- export * from '@aastar/tokens';
6
- export * from '@aastar/dapp';
7
- // export * from '@aastar/enduser'; // Commented to avoid CommunityClient conflict with clients/community.js
8
- // Export Role-Based Clients
9
- export * from './clients/endUser.js';
10
- export * from './clients/operator.js';
11
- export { createCommunityClient } from './clients/community.js'; // Restored for backward compatibility (launch API)
12
- export * from './clients/admin.js';
13
- export * from './clients/ExperimentClient.js';
14
- // Export L3 Lifecycle
15
- export * from '@aastar/enduser';
16
- export * from '@aastar/operator';
17
- export * from '@aastar/admin';
18
- // Export AirAccount SDK (ERC-4337 + KMS + BLS)
19
- export * as AirAccount from '@aastar/airaccount';
20
- // Export Utils & Errors
21
- export * from './utils/roleData.js';
22
- export * from './utils/keys.js';
23
- export * from './utils/funding.js';
24
- export * from './utils/userOp.js';
25
- export * from './utils/testScenarios.js';
26
- export * from './errors/decoder.js';
1
+ export { ChannelClient, VOUCHER_TYPES, getVoucherDomain, signVoucher } from './chunk-OSPRJZ5T.js';
2
+ export { CommunityClient, UserLifecycle } from './chunk-YHM77LIP.js';
3
+ export { UserClient } from './chunk-DI3E6PMI.js';
4
+ export { OperatorLifecycle, PaymasterOperatorClient, ProposalState, ProtocolClient } from './chunk-O3Y7II3B.js';
5
+ export { ProtocolGovernance } from './chunk-4DVUM4MC.js';
6
+ export { dist_exports as AirAccount } from './chunk-4KRQXOTI.js';
7
+ export { UserOpClient, createEOAWalletClient, getUserOpHash, packUserOpLimits, toSimpleSmartAccount } from './chunk-HVAB4TTT.js';
8
+ export { ReputationClient, checkMySBT, getMySBTId } from './chunk-NZGXB2C5.js';
9
+ export { FinanceClient } from './chunk-PCLPYRTX.js';
10
+ export { AirAccountEIP1193Provider, DVTClient, announceAirAccount, useCreditScore, useSuperPaymaster, watchProviders } from './chunk-6JCYPTSH.js';
11
+ export { PaymasterClient, PaymasterManager, PaymasterOperator, SuperPaymasterAdminClient, SuperPaymasterClient, buildPaymasterData, buildSuperPaymasterData, checkEligibility, formatUserOpV07, getPaymasterV4Middleware, getSuperPaymasterMiddleware, getUserOpHashV07, tuneGasLimit } from './chunk-MPOMWT2J.js';
12
+ export { EIP3009_TYPES, FacilitatorClient, GTOKEN_EIP712_DOMAIN, HEADER_PAYMENT_REQUIRED, HEADER_PAYMENT_RESPONSE, HEADER_PAYMENT_SIGNATURE, HEADER_V1_PAYMENT, HEADER_V1_PAYMENT_RESPONSE, X402Client, decodePaymentPayload, decodePaymentRequired, decodeSettleResponse, encodePaymentPayload, encodePaymentRequired, encodeSettleResponse, extractPaymentRequired, extractSettleResponse, generateNonce, getEIP3009Domain, signCancelAuthorization, signGTokenTransferWithAuthorization, signReceiveWithAuthorization, signTransferWithAuthorization } from './chunk-XFI3AK32.js';
13
+ import { paymasterActions, superPaymasterActions, sbtActions, registryActions, RegistryABI, stakingActions, aggregatorActions, xPNTsFactoryActions, dvtActions, SuperPaymasterABI, xPNTsTokenABI, PaymasterFactoryABI } from './chunk-ZSSNU3UF.js';
14
+ export { AASTAR_COMMUNITY, AAStarAirAccountFactoryV7ABI, AAStarAirAccountFactoryV7Artifact, AAStarAirAccountV7ABI, AAStarAirAccountV7Artifact, AAStarBLSAggregatorABI, AAStarBLSAggregatorArtifact, AAStarBLSAlgorithmABI, AAStarBLSAlgorithmArtifact, AAStarValidatorABI, AAStarValidatorArtifact, ALL_ROLES, AgentRegistryABI, AgentRegistryArtifact, AirAccountDelegateABI, AirAccountDelegateArtifact, AirAccountExtensionABI, AirAccountExtensionArtifact, AuthorizationState, BLSAggregatorABI, BLSAggregatorArtifact, BLSHelpers, BLSSigner, BLSValidatorABI, BLSValidatorArtifact, BLS_POP_DST, BRANDING, BREAD_COMMUNITY, BaseClient, BundlerClient, COMMUNITIES, CONTRACTS, CONTRACT_METADATA, CalldataParserRegistryABI, CalldataParserRegistryArtifact, ContractConfigManager, DEFAULT_ADMIN_ROLE, DVTValidatorABI, DVTValidatorArtifact, DVT_TIER_T2, DVT_TIER_T3, EntryPointABI, EntryPointArtifact, EntryPointVersion, ForceExitModuleABI, ForceExitModuleArtifact, GTokenABI, GTokenArtifact, GTokenAuthorizationABI, GTokenAuthorizationArtifact, GTokenStakingABI, GTokenStakingArtifact, INITIAL_ROLE_STAKES, LINKS, MicroPaymentChannelABI, MicroPaymentChannelArtifact, MySBTABI, MySBTArtifact, NETWORKS, NodeType, PaymasterABI, PaymasterArtifact, PaymasterFactoryABI, PaymasterFactoryArtifact, PolicyDecision, PolicyRegistryABI, PolicyRegistryArtifact, ROLE_ANODE, ROLE_COMMUNITY, ROLE_DVT, ROLE_ENDUSER, ROLE_KMS, ROLE_NAMES, ROLE_PAYMASTER_AOA, ROLE_PAYMASTER_SUPER, ROLE_PERMISSION_LEVELS, RegistryABI, RegistryArtifact, ReputationSystemABI, ReputationSystemArtifact, RequirementChecker, RolePermissionLevel, SEPOLIA_CONTRACTS, SEPOLIA_V2_VERSIONS, SepoliaFaucetAPI, SessionKeyValidatorABI, SessionKeyValidatorArtifact, SimpleAccountABI, SimpleAccountArtifact, SimpleAccountFactoryABI, SimpleAccountFactoryArtifact, StateValidator, SuperPaymasterABI, SuperPaymasterArtifact, V2_SUMMARY, X402FacilitatorABI, X402FacilitatorArtifact, accountActions, accountFactoryActions, agentActions, agentRegistryActions, aggregatorActions, airAccountActions, airAccountFactoryActions, blsAlgorithmActions, channelActions, createAAStarPublicClient, createHeliosTransport, dvtActions, encodeDVTAccountSignature, encodeDVTVerifierProof, encodeG2Point, entryPointActions, forceExitActions, gTokenActions, gTokenAuthorizationActions, getAddressUrl, getAllCommunityConfigs, getAllV2Contracts, getBlockExplorer, getChainId, getCommunities, getCommunity, getCommunityConfig, getContract, getContractNetworks, getContracts, getCoreContracts, getDeploymentDate, getEntryPoint, getNetwork, getPaymasterV4_1, getRoleName, getRpcUrl, getSimpleAccountFactory, getSuperPaymasterV2, getTestAccounts, getTestTokenContracts, getTokenContracts, getTxUrl, getV2ContractByAddress, getV2ContractByName, getV2ContractsByDate, hashToFieldU0U1, isContractNetworkSupported, isRegisteredCommunity, isV2Contract, lookupAddress, paymasterActions, paymasterFactoryActions, policyRegistryActions, registryActions, reputationActions, resolveEns, resolveEnsVerified, sbtActions, sessionKeyValidatorActions, stakingActions, superPaymasterActions, tokenActions, x402Actions, x402IsNonceUsed, x402NonceKey, xPNTsFactoryABI, xPNTsFactoryActions, xPNTsFactoryArtifact, xPNTsTokenABI, xPNTsTokenActions, xPNTsTokenArtifact } from './chunk-ZSSNU3UF.js';
15
+ import { TEST_ACCOUNT_ADDRESSES, TOKEN_ADDRESSES, CORE_ADDRESSES, TEST_TOKEN_ADDRESSES } from './chunk-DSZ372PH.js';
16
+ export { AGENT_IDENTITY_REGISTRY_ADDRESS, AGENT_REPUTATION_REGISTRY_ADDRESS, ALL_ADDRESSES, APNTS_ADDRESS, BLS_AGGREGATOR_ADDRESS, BLS_VALIDATOR_ADDRESS, BPS_DENOMINATOR, CHAIN_MAINNET, CHAIN_SEPOLIA, COMMUNITY_OWNERS, CONTRACT_SRC_HASH, CORE_ADDRESSES, DEFAULT_APNTS_PRICE_USD, DEFAULT_CALL_GAS_LIMIT, DEFAULT_GAS_TOKEN_MINT_AMOUNT, DEFAULT_PRE_VERIFICATION_GAS, DEFAULT_TIMEOUT_MS, DEFAULT_TOKEN_NAME, DEFAULT_TOKEN_SYMBOL, DEFAULT_USDT_MINT_AMOUNT, DEFAULT_VERIFICATION_GAS_LIMIT, DVT_VALIDATOR_ADDRESS, ENTRY_POINT_ADDRESS, FAUCET_API_URL, GTOKEN_ADDRESS, GTOKEN_STAKING_ADDRESS, MAX_SERVICE_FEE, MICRO_PAYMENT_CHANNEL_ADDRESS, MONITORING_ADDRESSES, NODE_STAKE_AMOUNTS, OFFICIAL_ADDRESSES, PAYMASTER_ADDRESSES, PAYMASTER_FACTORY_ADDRESS, PAYMASTER_V4_ADDRESS, PAYMASTER_V4_IMPL_ADDRESS, REGISTRY_ADDRESS, REPUTATION_SYSTEM_ADDRESS, SBT_ADDRESS, SERVICE_FEE_RATE, SUPER_PAYMASTER_ADDRESS, TEST_ACCOUNT_ADDRESSES, TEST_ACCOUNT_POOL_SIZE, TEST_COMMUNITIES, TEST_TOKEN_ADDRESSES, TOKEN_ADDRESSES, XPNTS_FACTORY_ADDRESS, applyConfig } from './chunk-DSZ372PH.js';
17
+ import './chunk-PZ5AY32C.js';
18
+ import { keccak256, stringToBytes, createClient, publicActions, walletActions, parseAbi, decodeAbiParameters, encodeAbiParameters, zeroAddress, decodeErrorResult, formatEther, http, createPublicClient, createWalletClient, parseEther, erc20Abi, concat, pad, parseAbiParameters, toBytes, encodeFunctionData } from 'viem';
19
+ import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
20
+ import * as fs from 'fs';
21
+
22
+ function createEndUserClient({
23
+ chain,
24
+ transport,
25
+ account,
26
+ addresses
27
+ }) {
28
+ const client = createClient({
29
+ chain,
30
+ transport,
31
+ account
32
+ }).extend(publicActions).extend(walletActions);
33
+ const usedAddresses = { ...CORE_ADDRESSES, ...TOKEN_ADDRESSES, ...TEST_ACCOUNT_ADDRESSES, ...addresses };
34
+ console.log(" SDK Debug: simpleAccountFactory from usedAddresses:", usedAddresses.simpleAccountFactory);
35
+ console.log(" SDK Debug: process.env.SIMPLE_ACCOUNT_FACTORY:", process.env.SIMPLE_ACCOUNT_FACTORY);
36
+ const actions = {
37
+ ...registryActions(usedAddresses.registry)(client),
38
+ ...sbtActions(usedAddresses.mySBT)(client),
39
+ ...superPaymasterActions(usedAddresses.superPaymaster)(client),
40
+ ...paymasterActions(usedAddresses.paymasterV4)(client)
41
+ };
42
+ return Object.assign(client, actions, {
43
+ async onboard({ community, roleId, roleData }) {
44
+ console.log("\u{1F464} Onboarding user to community...");
45
+ const result = await this.joinAndActivate({ community, roleId, roleData });
46
+ console.log(`\u2705 User onboarded! SBT ID: ${result.sbtId}`);
47
+ return { tx: result.tx, sbtId: result.sbtId };
48
+ },
49
+ async joinAndActivate({ community, roleId, roleData }) {
50
+ const accountToUse = account;
51
+ if (!accountToUse) throw new Error("Account required for joinAndActivate");
52
+ console.log(` SDK: Joining community ${community}...`);
53
+ let finalData;
54
+ if (roleData) {
55
+ finalData = roleData;
56
+ } else {
57
+ const { encodeAbiParameters: encodeAbiParameters3 } = await import('viem');
58
+ finalData = encodeAbiParameters3(
59
+ [
60
+ { name: "account", type: "address" },
61
+ { name: "community", type: "address" },
62
+ { name: "avatarURI", type: "string" },
63
+ { name: "ensName", type: "string" },
64
+ { name: "stakeAmount", type: "uint256" }
65
+ ],
66
+ [accountToUse.address, community, "", "", 0n]
67
+ // Use minimum stake (Registry will use roleConfig.minStake)
68
+ );
69
+ }
70
+ const regTx = await client.writeContract({
71
+ address: usedAddresses.registry,
72
+ abi: RegistryABI,
73
+ functionName: "registerRoleSelf",
74
+ args: [roleId, finalData],
75
+ account: accountToUse,
76
+ chain
77
+ });
78
+ await client.waitForTransactionReceipt({ hash: regTx });
79
+ const sbtId = await actions.getUserSBT({ user: accountToUse.address });
80
+ console.log(` SDK: User joined. SBT ID: ${sbtId}`);
81
+ let credit = 0n;
82
+ try {
83
+ const factoryAbi = parseAbi(["function communityToToken(address) view returns (address)"]);
84
+ const tokenAddress = await client.readContract({
85
+ address: usedAddresses.xPNTsFactory,
86
+ abi: factoryAbi,
87
+ functionName: "communityToToken",
88
+ args: [community]
89
+ });
90
+ credit = await actions.getAvailableCredit({
91
+ user: client.aaAddress || accountToUse.address,
92
+ token: tokenAddress
93
+ });
94
+ console.log(` SDK: Activation complete. Current Credit: ${credit} points.`);
95
+ } catch (error) {
96
+ console.log(` SDK: Credit system not available (${error.message.split("\n")[0]}). Continuing...`);
97
+ }
98
+ return {
99
+ tx: regTx,
100
+ sbtId,
101
+ initialCredit: credit
102
+ };
103
+ },
104
+ async executeGasless({ target, data, value = 0n, operator }) {
105
+ const accountToUse = account;
106
+ if (!accountToUse) throw new Error("Wallet account required for gasless execution");
107
+ const { accountAddress } = await this.createSmartAccount({ owner: accountToUse.address });
108
+ console.log(` SDK: Executing gasless via AA ${accountAddress} Sponsored by ${operator}`);
109
+ let nonce = 0n;
110
+ try {
111
+ nonce = await client.readContract({
112
+ address: usedAddresses.entryPoint,
113
+ abi: [{
114
+ type: "function",
115
+ name: "getNonce",
116
+ inputs: [{ type: "address", name: "sender" }, { type: "uint192", name: "key" }],
117
+ outputs: [{ type: "uint256" }],
118
+ stateMutability: "view"
119
+ }],
120
+ functionName: "getNonce",
121
+ args: [accountAddress, 0n]
122
+ // 0 = default nonce key
123
+ });
124
+ } catch (e) {
125
+ console.warn(` \u26A0\uFE0F Failed to fetch nonce from EntryPoint, using default 0:`, e.message);
126
+ nonce = 0n;
127
+ }
128
+ const { encodeFunctionData: encodeFunctionData2, concat: concat2, pad: pad2, keccak256: keccak2565 } = await import('viem');
129
+ const executeData = encodeFunctionData2({
130
+ abi: [{ type: "function", name: "execute", inputs: [{ type: "address" }, { type: "uint256" }, { type: "bytes" }] }],
131
+ functionName: "execute",
132
+ args: [target, value, data]
133
+ });
134
+ const accountGasLimits = concat2([
135
+ pad2(`0x${1e5.toString(16)}`, { dir: "left", size: 16 }),
136
+ // verification
137
+ pad2(`0x${1e5.toString(16)}`, { dir: "left", size: 16 })
138
+ // call
139
+ ]);
140
+ const gasFees = concat2([
141
+ pad2(`0x${2e9.toString(16)}`, { dir: "left", size: 16 }),
142
+ // 2 gwei
143
+ pad2(`0x${2e9.toString(16)}`, { dir: "left", size: 16 })
144
+ // 2 gwei
145
+ ]);
146
+ const paymasterVerificationGas = 250000n;
147
+ const paymasterPostOpGas = 50000n;
148
+ const paymasterAndData = concat2([
149
+ usedAddresses.superPaymaster,
150
+ pad2(`0x${paymasterVerificationGas.toString(16)}`, { dir: "left", size: 16 }),
151
+ pad2(`0x${paymasterPostOpGas.toString(16)}`, { dir: "left", size: 16 }),
152
+ operator
153
+ ]);
154
+ const userOp = {
155
+ sender: accountAddress,
156
+ nonce,
157
+ initCode: "0x",
158
+ callData: executeData,
159
+ accountGasLimits,
160
+ preVerificationGas: 50000n,
161
+ gasFees,
162
+ paymasterAndData,
163
+ signature: "0x"
164
+ };
165
+ const entryPointAddress = usedAddresses.entryPoint || "0x0000000071727De22E5E9d8BAf0edAc6f37da032";
166
+ const userOpHash = await client.readContract({
167
+ address: entryPointAddress,
168
+ abi: [{
169
+ type: "function",
170
+ name: "getUserOpHash",
171
+ inputs: [{
172
+ type: "tuple",
173
+ components: [
174
+ { name: "sender", type: "address" },
175
+ { name: "nonce", type: "uint256" },
176
+ { name: "initCode", type: "bytes" },
177
+ { name: "callData", type: "bytes" },
178
+ { name: "accountGasLimits", type: "bytes32" },
179
+ { name: "preVerificationGas", type: "uint256" },
180
+ { name: "gasFees", type: "bytes32" },
181
+ { name: "paymasterAndData", type: "bytes" },
182
+ { name: "signature", type: "bytes" }
183
+ ]
184
+ }],
185
+ outputs: [{ type: "bytes32" }],
186
+ stateMutability: "view"
187
+ }],
188
+ functionName: "getUserOpHash",
189
+ args: [userOp]
190
+ });
191
+ const signature = await accountToUse.signMessage({
192
+ message: { raw: userOpHash }
193
+ });
194
+ userOp.signature = signature;
195
+ console.log(` SDK: Submitting UserOp ${userOpHash}...`);
196
+ const tx = await client.writeContract({
197
+ address: entryPointAddress,
198
+ abi: [{
199
+ type: "function",
200
+ name: "handleOps",
201
+ inputs: [
202
+ {
203
+ type: "tuple[]",
204
+ components: [
205
+ { name: "sender", type: "address" },
206
+ { name: "nonce", type: "uint256" },
207
+ { name: "initCode", type: "bytes" },
208
+ { name: "callData", type: "bytes" },
209
+ { name: "accountGasLimits", type: "bytes32" },
210
+ { name: "preVerificationGas", type: "uint256" },
211
+ { name: "gasFees", type: "bytes32" },
212
+ { name: "paymasterAndData", type: "bytes" },
213
+ { name: "signature", type: "bytes" }
214
+ ]
215
+ },
216
+ { name: "beneficiary", type: "address" }
217
+ ],
218
+ outputs: [],
219
+ stateMutability: "nonpayable"
220
+ }],
221
+ functionName: "handleOps",
222
+ args: [[userOp], accountToUse.address],
223
+ account,
224
+ chain
225
+ });
226
+ await client.waitForTransactionReceipt({ hash: tx });
227
+ return tx;
228
+ },
229
+ async checkJoinRequirements(address) {
230
+ const accountToUse = address || account?.address;
231
+ if (!accountToUse) throw new Error("Account address required for requirement check");
232
+ const { RequirementChecker: RequirementChecker2 } = await import('./index.node-55LOPHNQ.js');
233
+ const checker = new RequirementChecker2(client, usedAddresses);
234
+ return await checker.checkRequirements({
235
+ address: accountToUse,
236
+ requiredGToken: 440000000000000000n,
237
+ // 0.44 GT (stake + burn)
238
+ requireSBT: false
239
+ });
240
+ },
241
+ async createSmartAccount({ owner, salt = 0n }) {
242
+ const { SimpleAccountFactoryABI: SimpleAccountFactoryABI2 } = await import('./index.node-55LOPHNQ.js');
243
+ const { encodeFunctionData: encodeFunctionData2, concat: concat2 } = await import('viem');
244
+ let factoryAddress = usedAddresses.simpleAccountFactory;
245
+ console.log(` SDK: Using SimpleAccountFactory: ${factoryAddress} (Owner: ${owner}, Salt: ${salt})`);
246
+ if (!factoryAddress || factoryAddress === "0x0000000000000000000000000000000000000000") {
247
+ console.warn(" \u26A0\uFE0F SimpleAccountFactory not found in configuration. Using default fallback.");
248
+ factoryAddress = "0x9406Cc6185a346906296840746125a0E44976454";
249
+ }
250
+ const accountAddress = await client.readContract({
251
+ address: factoryAddress,
252
+ abi: SimpleAccountFactoryABI2,
253
+ functionName: "getAddress",
254
+ args: [owner, salt]
255
+ });
256
+ const createAccountData = encodeFunctionData2({
257
+ abi: SimpleAccountFactoryABI2,
258
+ functionName: "createAccount",
259
+ args: [owner, salt]
260
+ });
261
+ const initCode = concat2([factoryAddress, createAccountData]);
262
+ const byteCode = await client.getBytecode({ address: accountAddress });
263
+ const isDeployed = byteCode !== void 0 && byteCode !== "0x";
264
+ return { accountAddress, initCode, isDeployed };
265
+ },
266
+ async deploySmartAccount({ owner, salt = 0n, fundWithETH = 0n }) {
267
+ const { accountAddress, isDeployed } = await this.createSmartAccount({ owner, salt });
268
+ const { formatEther: formatEther2 } = await import('viem');
269
+ let deployHash = "0x0";
270
+ if (isDeployed) {
271
+ console.log(` \u2139\uFE0F Account ${accountAddress} already deployed.`);
272
+ } else {
273
+ const { SimpleAccountFactoryABI: SimpleAccountFactoryABI2 } = await import('./index.node-55LOPHNQ.js');
274
+ let factoryAddress = usedAddresses.simpleAccountFactory;
275
+ if (!factoryAddress || factoryAddress === "0x0000000000000000000000000000000000000000") {
276
+ factoryAddress = "0x9406Cc6185a346906296840746125a0E44976454";
277
+ }
278
+ console.log(` \u{1F3ED} Deploying Smart Account for ${owner}...`);
279
+ deployHash = await client.writeContract({
280
+ address: factoryAddress,
281
+ abi: SimpleAccountFactoryABI2,
282
+ functionName: "createAccount",
283
+ args: [owner, salt],
284
+ account,
285
+ chain
286
+ });
287
+ await client.waitForTransactionReceipt({ hash: deployHash });
288
+ console.log(` \u2705 Deployed at ${accountAddress}`);
289
+ }
290
+ if (fundWithETH > 0n) {
291
+ console.log(` \u26FD Funding account with ${formatEther2(fundWithETH)} ETH...`);
292
+ const tx = await client.sendTransaction({
293
+ to: accountAddress,
294
+ value: fundWithETH,
295
+ account,
296
+ chain
297
+ });
298
+ await client.waitForTransactionReceipt({ hash: tx });
299
+ }
300
+ return { accountAddress, deployTxHash: deployHash, isDeployed: true };
301
+ }
302
+ });
303
+ }
304
+ var RoleIds = {
305
+ PAYMASTER_SUPER: keccak256(stringToBytes("PAYMASTER_SUPER")),
306
+ DVT: keccak256(stringToBytes("DVT")),
307
+ // Replaced PAYMASTER
308
+ PAYMASTER_AOA: keccak256(stringToBytes("PAYMASTER_AOA")),
309
+ KMS: keccak256(stringToBytes("KMS")),
310
+ COMMUNITY: keccak256(stringToBytes("COMMUNITY")),
311
+ ENDUSER: keccak256(stringToBytes("ENDUSER")),
312
+ ANODE: keccak256(stringToBytes("ANODE"))
313
+ };
314
+ var RoleDataFactory = {
315
+ /**
316
+ * Data for SuperPaymaster Operator (Empty)
317
+ */
318
+ paymasterSuper: () => "0x",
319
+ /**
320
+ * Data for Generic DVT Role (Empty)
321
+ */
322
+ dvt: () => "0x",
323
+ /**
324
+ * Data for Community Registration (matches Registry.sol CommunityRoleData)
325
+ * NOTE: Solidity's abi.encode(struct) adds a 32-byte offset prefix (0x20)
326
+ * which is required for abi.decode(struct) to work correctly.
327
+ *
328
+ * @param params.name Community Name (defaults to 'TestCommunity')
329
+ * @param params.ensName ENS name (optional)
330
+ * @param params.website Website URL (optional)
331
+ * @param params.description Community description (optional)
332
+ * @param params.logoURI Logo URI string (optional)
333
+ * @param params.stakeAmount Stake amount (defaults to 0)
334
+ */
335
+ community: (params) => {
336
+ return encodeAbiParameters(
337
+ [{
338
+ type: "tuple",
339
+ components: [
340
+ { name: "name", type: "string" },
341
+ { name: "ensName", type: "string" },
342
+ { name: "website", type: "string" },
343
+ { name: "description", type: "string" },
344
+ { name: "logoURI", type: "string" },
345
+ { name: "stakeAmount", type: "uint256" }
346
+ ]
347
+ }],
348
+ [[
349
+ params?.name || "TestCommunity",
350
+ params?.ensName || "",
351
+ params?.website || "",
352
+ params?.description || "",
353
+ params?.logoURI || "",
354
+ params?.stakeAmount || 0n
355
+ ]]
356
+ );
357
+ },
358
+ /**
359
+ * Data for EndUser (matches Registry.sol EndUserRoleData)
360
+ */
361
+ endUser: (params) => {
362
+ return encodeAbiParameters(
363
+ [{
364
+ type: "tuple",
365
+ components: [
366
+ { name: "account", type: "address" },
367
+ { name: "community", type: "address" },
368
+ { name: "avatarURI", type: "string" },
369
+ { name: "ensName", type: "string" },
370
+ { name: "stakeAmount", type: "uint256" }
371
+ ]
372
+ }],
373
+ [[
374
+ params?.account || zeroAddress,
375
+ params?.community || zeroAddress,
376
+ params?.avatarURI || "",
377
+ params?.ensName || "",
378
+ params?.stakeAmount || 0n
379
+ ]]
380
+ );
381
+ },
382
+ decodeCommunity: (data) => {
383
+ const decoded = decodeAbiParameters(
384
+ [{
385
+ type: "tuple",
386
+ components: [
387
+ { name: "name", type: "string" },
388
+ { name: "ensName", type: "string" },
389
+ { name: "website", type: "string" },
390
+ { name: "description", type: "string" },
391
+ { name: "logoURI", type: "string" },
392
+ { name: "stakeAmount", type: "uint256" }
393
+ ]
394
+ }],
395
+ data
396
+ );
397
+ const result = decoded[0];
398
+ if (Array.isArray(result)) {
399
+ const [n, e, w, d, l, s] = result;
400
+ return { name: n, ensName: e, website: w, description: d, logoURI: l, stakeAmount: s };
401
+ } else {
402
+ return {
403
+ name: result.name,
404
+ ensName: result.ensName,
405
+ website: result.website,
406
+ description: result.description,
407
+ logoURI: result.logoURI,
408
+ stakeAmount: result.stakeAmount
409
+ };
410
+ }
411
+ },
412
+ decodeEndUser: (data) => {
413
+ const decoded = decodeAbiParameters(
414
+ [{
415
+ type: "tuple",
416
+ components: [
417
+ { name: "account", type: "address" },
418
+ { name: "community", type: "address" },
419
+ { name: "avatarURI", type: "string" },
420
+ { name: "ensName", type: "string" },
421
+ { name: "stakeAmount", type: "uint256" }
422
+ ]
423
+ }],
424
+ data
425
+ );
426
+ const result = decoded[0];
427
+ if (Array.isArray(result)) {
428
+ const [a, c, av, en, s] = result;
429
+ return { account: a, community: c, avatarURI: av, ensName: en, stakeAmount: s };
430
+ } else {
431
+ return {
432
+ account: result.account,
433
+ community: result.community,
434
+ avatarURI: result.avatarURI,
435
+ ensName: result.ensName,
436
+ stakeAmount: result.stakeAmount
437
+ };
438
+ }
439
+ }
440
+ };
441
+ var CustomErrors = {
442
+ RoleNotConfigured: "RoleNotConfigured(bytes32,bool)",
443
+ RoleAlreadyGranted: "RoleAlreadyGranted(bytes32,address)",
444
+ InsufficientStake: "InsufficientStake(uint256,uint256)"
445
+ };
446
+ function decodeContractError(error) {
447
+ if (!error || typeof error !== "object") return null;
448
+ if (error.name === "ContractFunctionExecutionError" || error.walk) {
449
+ const internalError = error.walk ? error.walk((e) => e.data) : error;
450
+ const data = internalError?.data;
451
+ if (data) {
452
+ try {
453
+ const decoded = decodeErrorResult({
454
+ abi: RegistryABI,
455
+ data
456
+ });
457
+ if (decoded.errorName === "RoleNotConfigured") {
458
+ const [roleId, isActive] = decoded.args;
459
+ return `RoleNotConfigured: Role ${roleId} is ${isActive ? "ACTIVE" : "INACTIVE"} in Registry.`;
460
+ }
461
+ if (decoded.errorName === "RoleAlreadyGranted") {
462
+ const [roleId, user] = decoded.args;
463
+ return `RoleAlreadyGranted: User ${user} already has role ${roleId}.`;
464
+ }
465
+ if (decoded.errorName === "InsufficientStake") {
466
+ const [stake, minStake] = decoded.args;
467
+ return `InsufficientStake: Provided ${stake}, Required ${minStake}.`;
468
+ }
469
+ return `${decoded.errorName}: ${decoded.args}`;
470
+ } catch (e) {
471
+ return null;
472
+ }
473
+ }
474
+ }
475
+ return null;
476
+ }
477
+
478
+ // src/clients/operator.ts
479
+ function createOperatorClient({
480
+ chain,
481
+ transport,
482
+ account,
483
+ addresses
484
+ }) {
485
+ const client = createClient({
486
+ chain,
487
+ transport,
488
+ account
489
+ }).extend(publicActions).extend(walletActions);
490
+ const usedAddresses = { ...CORE_ADDRESSES, ...TEST_TOKEN_ADDRESSES, ...TEST_ACCOUNT_ADDRESSES, ...addresses };
491
+ const spActions = superPaymasterActions(usedAddresses.superPaymaster)(client);
492
+ const regActions = registryActions(usedAddresses.registry)(client);
493
+ const stkActions = stakingActions(usedAddresses.gTokenStaking)(client);
494
+ const pmV4Actions = paymasterActions(usedAddresses.paymasterV4)(client);
495
+ const actions = {
496
+ ...stkActions,
497
+ ...spActions,
498
+ ...pmV4Actions,
499
+ ...regActions,
500
+ async setup(args) {
501
+ console.log("\u2699\uFE0F Setting up operator...");
502
+ const txs = await this._onboardOperator(args);
503
+ console.log(`\u2705 Operator setup complete! Transactions: ${txs.length}`);
504
+ return { txs };
505
+ },
506
+ async onboardOperator(args) {
507
+ return this.onboardFully(args);
508
+ },
509
+ async onboardFully(args) {
510
+ return this._onboardOperator(args);
511
+ },
512
+ async deployPaymasterV4({ version = "v4.1", initData = "0x" } = {}) {
513
+ console.log(` SDK: Deploying Paymaster V4 (${version})...`);
514
+ const tx = await client.writeContract({
515
+ address: usedAddresses.paymasterFactory,
516
+ abi: PaymasterFactoryABI,
517
+ functionName: "deployPaymaster",
518
+ args: [version, initData],
519
+ account,
520
+ chain
521
+ });
522
+ await client.waitForTransactionReceipt({ hash: tx });
523
+ return tx;
524
+ },
525
+ async _onboardOperator({ stakeAmount, depositAmount, roleId, roleData }) {
526
+ const txs = [];
527
+ const accountToUse = account;
528
+ if (!accountToUse) throw new Error("Account required for onboarding");
529
+ try {
530
+ console.log(" SDK: Fetching role config for entry burn...");
531
+ const roleConfig = await client.readContract({
532
+ address: usedAddresses.registry,
533
+ abi: RegistryABI,
534
+ functionName: "roleConfigs",
535
+ args: [roleId]
536
+ });
537
+ const entryBurn = roleConfig[1];
538
+ const totalStakeNeeded = stakeAmount + entryBurn;
539
+ console.log(` SDK: Approving GToken (Stake: ${stakeAmount}, Burn: ${entryBurn})...`);
540
+ const approveGToken = await client.writeContract({
541
+ address: usedAddresses.gToken,
542
+ abi: erc20Abi,
543
+ functionName: "approve",
544
+ args: [usedAddresses.gTokenStaking, totalStakeNeeded],
545
+ account: accountToUse,
546
+ chain
547
+ });
548
+ await client.waitForTransactionReceipt({ hash: approveGToken });
549
+ txs.push(approveGToken);
550
+ let data;
551
+ if (roleData && roleData !== "0x") {
552
+ data = roleData;
553
+ } else {
554
+ console.log(` SDK: Auto-generating roleData for roleId ${roleId}...`);
555
+ if (roleId === keccak256(stringToBytes("COMMUNITY"))) {
556
+ data = RoleDataFactory.community();
557
+ } else if (roleId === keccak256(stringToBytes("ENDUSER"))) {
558
+ data = RoleDataFactory.endUser();
559
+ } else if (roleId === keccak256(stringToBytes("PAYMASTER_SUPER"))) {
560
+ data = RoleDataFactory.paymasterSuper();
561
+ } else {
562
+ data = RoleDataFactory.paymasterSuper();
563
+ }
564
+ }
565
+ console.log(` SDK: Checking if role already granted...`);
566
+ const hasRoleResult = await client.readContract({
567
+ address: usedAddresses.registry,
568
+ abi: RegistryABI,
569
+ functionName: "hasRole",
570
+ args: [roleId, accountToUse.address]
571
+ });
572
+ if (hasRoleResult) {
573
+ console.log(` \u2139\uFE0F Role already granted, skipping registration`);
574
+ } else {
575
+ console.log(` SDK: Registering role ${roleId}...`);
576
+ const registerTx = await actions.registerRoleSelf({
577
+ roleId,
578
+ data,
579
+ account: accountToUse
580
+ });
581
+ await client.waitForTransactionReceipt({ hash: registerTx });
582
+ txs.push(registerTx);
583
+ }
584
+ if (depositAmount > 0n) {
585
+ console.log(" SDK: Depositing aPNTs via depositFor...");
586
+ const depositTx = await client.writeContract({
587
+ address: usedAddresses.superPaymaster,
588
+ abi: SuperPaymasterABI,
589
+ functionName: "depositFor",
590
+ args: [accountToUse.address, depositAmount],
591
+ account: accountToUse,
592
+ chain
593
+ });
594
+ await client.waitForTransactionReceipt({ hash: depositTx });
595
+ txs.push(depositTx);
596
+ }
597
+ return txs;
598
+ } catch (error) {
599
+ const decodedMsg = decodeContractError(error);
600
+ throw decodedMsg ? new Error(`Onboarding Failed: ${decodedMsg}`) : error;
601
+ }
602
+ },
603
+ async onboardToSuperPaymaster(args) {
604
+ return this.onboardOperator(args);
605
+ },
606
+ async configureOperator({ xPNTsToken, treasury, account: accountOverride }) {
607
+ const tx = await spActions.configureOperator({
608
+ xPNTsToken,
609
+ opTreasury: treasury,
610
+ account: accountOverride || account
611
+ });
612
+ await client.waitForTransactionReceipt({ hash: tx });
613
+ return tx;
614
+ },
615
+ async getOperatorStatus(accountAddress) {
616
+ try {
617
+ const hasRole = await client.readContract({
618
+ address: usedAddresses.registry,
619
+ abi: RegistryABI,
620
+ functionName: "hasRole",
621
+ args: [keccak256(stringToBytes("PAYMASTER_SUPER")), accountAddress]
622
+ });
623
+ let operatorType = null;
624
+ let superPaymasterInfo = null;
625
+ let paymasterV4Info = null;
626
+ if (hasRole && usedAddresses.superPaymaster) {
627
+ const operatorData = await client.readContract({
628
+ address: usedAddresses.superPaymaster,
629
+ abi: SuperPaymasterABI,
630
+ functionName: "operators",
631
+ args: [accountAddress]
632
+ });
633
+ if (operatorData && operatorData[1]) {
634
+ operatorType = "super";
635
+ const xPNTsTokenAddr = operatorData[3];
636
+ let exchangeRate = 0n;
637
+ if (xPNTsTokenAddr && xPNTsTokenAddr !== zeroAddress) {
638
+ try {
639
+ exchangeRate = await client.readContract({
640
+ address: xPNTsTokenAddr,
641
+ abi: xPNTsTokenABI,
642
+ functionName: "exchangeRate"
643
+ });
644
+ } catch (rateErr) {
645
+ const msg = rateErr instanceof Error ? rateErr.message : String(rateErr);
646
+ if (!msg.includes("ContractFunctionExecutionError") && !msg.includes("code: -32")) {
647
+ console.warn(` \u26A0\uFE0F Unexpected error reading exchangeRate from ${xPNTsTokenAddr}:`, msg);
648
+ }
649
+ }
650
+ }
651
+ superPaymasterInfo = {
652
+ hasRole: true,
653
+ isConfigured: true,
654
+ balance: operatorData[0],
655
+ exchangeRate,
656
+ treasury: operatorData[6]
657
+ };
658
+ }
659
+ }
660
+ if (usedAddresses.paymasterFactory && usedAddresses.paymasterFactory !== zeroAddress) {
661
+ try {
662
+ const pmAddr = await client.readContract({
663
+ address: usedAddresses.paymasterFactory,
664
+ abi: PaymasterFactoryABI,
665
+ functionName: "getPaymasterByOperator",
666
+ args: [accountAddress]
667
+ });
668
+ if (pmAddr !== zeroAddress) {
669
+ operatorType = operatorType || "v4";
670
+ paymasterV4Info = {
671
+ address: pmAddr,
672
+ balance: await client.getBalance({ address: pmAddr })
673
+ };
674
+ }
675
+ } catch (e) {
676
+ console.warn(` \u26A0\uFE0F Failed to fetch V4 info from factory ${usedAddresses.paymasterFactory}:`, e);
677
+ }
678
+ }
679
+ return { type: operatorType, superPaymaster: superPaymasterInfo, paymasterV4: paymasterV4Info };
680
+ } catch (error) {
681
+ console.error("Error in getOperatorStatus:", error);
682
+ return { type: null, superPaymaster: null, paymasterV4: null };
683
+ }
684
+ }
685
+ };
686
+ return Object.assign(client, actions);
687
+ }
688
+ function createCommunityClient({
689
+ chain,
690
+ transport,
691
+ account,
692
+ addresses
693
+ }) {
694
+ const client = createClient({
695
+ chain,
696
+ transport,
697
+ account
698
+ }).extend(publicActions).extend(walletActions);
699
+ const usedAddresses = { ...CORE_ADDRESSES, ...TEST_TOKEN_ADDRESSES, ...addresses };
700
+ const registryActionsObj = registryActions(usedAddresses.registry)(client);
701
+ const sbtActionsObj = sbtActions(usedAddresses.mySBT)(client);
702
+ const launch = async (args) => {
703
+ try {
704
+ console.log(`\u{1F680} Launching community: ${args.name}`);
705
+ if (!account) {
706
+ throw new Error("Account is required for launch()");
707
+ }
708
+ const uniqueName = `${args.name}_${Date.now()}`;
709
+ console.log(` \u{1F4DD} Unique name: ${uniqueName}`);
710
+ const roleData = RoleDataFactory.community({
711
+ name: uniqueName,
712
+ ensName: "",
713
+ website: args.website || "",
714
+ description: args.description || "",
715
+ logoURI: args.logoURI || "",
716
+ stakeAmount: 0n
717
+ });
718
+ console.log(` \u2705 RoleData generated:`, roleData);
719
+ console.log(` \u{1F4CA} RoleData type:`, typeof roleData);
720
+ console.log(` \u{1F4CF} RoleData length:`, roleData?.length);
721
+ const hasRole = await client.readContract({
722
+ address: usedAddresses.registry,
723
+ abi: RegistryABI,
724
+ functionName: "hasRole",
725
+ args: [RoleIds.COMMUNITY, account.address]
726
+ });
727
+ let registerTx;
728
+ if (hasRole) {
729
+ console.log(` \u2139\uFE0F Account already has COMMUNITY role. Skipping registration.`);
730
+ } else {
731
+ if (usedAddresses.gToken && usedAddresses.gTokenStaking) {
732
+ console.log(` \u{1F4B0} Checking GToken allowance...`);
733
+ const balance = await client.readContract({
734
+ address: usedAddresses.gToken,
735
+ abi: erc20Abi,
736
+ functionName: "balanceOf",
737
+ args: [account.address]
738
+ });
739
+ if (balance < 50000000000000000000n) {
740
+ console.warn(` \u26A0\uFE0F Warning: Low GToken balance (${balance}). Registration may fail if minStake > balance.`);
741
+ }
742
+ const allowance = await client.readContract({
743
+ address: usedAddresses.gToken,
744
+ abi: erc20Abi,
745
+ functionName: "allowance",
746
+ args: [account.address, usedAddresses.gTokenStaking]
747
+ });
748
+ if (allowance < 50000000000000000000n) {
749
+ console.log(` \u{1F513} Approving GToken for Staking...`);
750
+ const approveTx = await client.writeContract({
751
+ address: usedAddresses.gToken,
752
+ abi: erc20Abi,
753
+ functionName: "approve",
754
+ args: [usedAddresses.gTokenStaking, 115792089237316195423570985008687907853269984665640564039457584007913129639935n],
755
+ // MaxUint256
756
+ account
757
+ });
758
+ console.log(` \u2705 Approved: ${approveTx}`);
759
+ await client.waitForTransactionReceipt({ hash: approveTx });
760
+ }
761
+ }
762
+ console.log(` \u{1F4E4} Registering community role...`);
763
+ try {
764
+ registerTx = await registryActionsObj.registerRole({
765
+ roleId: RoleIds.COMMUNITY,
766
+ user: account.address,
767
+ data: roleData,
768
+ account
769
+ });
770
+ console.log(` \u2705 Community registered: ${registerTx}`);
771
+ } catch (e) {
772
+ const isRoleError = e.message?.includes("RoleAlreadyGranted") || e.cause?.data?.errorName === "RoleAlreadyGranted" || e.name === "RoleAlreadyGranted" || e.name === "RoleAlreadyGranted";
773
+ if (isRoleError) {
774
+ console.log(` \u2139\uFE0F Role already granted (caught in tx). Skipping.`);
775
+ } else {
776
+ throw e;
777
+ }
778
+ }
779
+ }
780
+ let tokenAddress = "0x0000000000000000000000000000000000000000";
781
+ const txs = [];
782
+ if (registerTx) txs.push(registerTx);
783
+ if (usedAddresses.xPNTsFactory) {
784
+ if (!client.account) {
785
+ throw new Error("Client account is required for token deployment");
786
+ }
787
+ const factoryAbi = [
788
+ {
789
+ type: "function",
790
+ name: "deployxPNTsToken",
791
+ inputs: [
792
+ { name: "name", type: "string" },
793
+ { name: "symbol", type: "string" },
794
+ { name: "communityName", type: "string" },
795
+ { name: "communityENS", type: "string" },
796
+ { name: "exchangeRate", type: "uint256" },
797
+ { name: "paymasterAOA", type: "address" }
798
+ ],
799
+ outputs: [{ name: "token", type: "address" }],
800
+ stateMutability: "nonpayable"
801
+ },
802
+ {
803
+ type: "function",
804
+ name: "getTokenAddress",
805
+ inputs: [{ name: "community", type: "address" }],
806
+ outputs: [{ name: "token", type: "address" }],
807
+ stateMutability: "view"
808
+ }
809
+ ];
810
+ try {
811
+ const existingToken = await client.readContract({
812
+ address: usedAddresses.xPNTsFactory,
813
+ abi: factoryAbi,
814
+ functionName: "getTokenAddress",
815
+ args: [account.address]
816
+ });
817
+ if (existingToken && existingToken !== "0x0000000000000000000000000000000000000000") {
818
+ console.log(` \u2139\uFE0F Found existing token at ${existingToken}`);
819
+ tokenAddress = existingToken;
820
+ return { tokenAddress, txs };
821
+ }
822
+ } catch (e) {
823
+ console.warn(` \u26A0\uFE0F Failed to check for existing token:`, e);
824
+ }
825
+ console.log(` \u{1F3ED} Deploying Token via Factory: ${usedAddresses.xPNTsFactory}`);
826
+ try {
827
+ const { request } = await client.simulateContract({
828
+ address: usedAddresses.xPNTsFactory,
829
+ abi: factoryAbi,
830
+ functionName: "deployxPNTsToken",
831
+ args: [
832
+ args.tokenName,
833
+ args.tokenSymbol,
834
+ args.name,
835
+ // communityName
836
+ args.website || "",
837
+ // communityENS (mapping website to ENS param for now)
838
+ 1000000000000000000n,
839
+ // exchangeRate 1e18 (1:1)
840
+ "0x0000000000000000000000000000000000000000"
841
+ // paymasterAOA (optional)
842
+ ],
843
+ account: client.account
844
+ });
845
+ const deployTx = await client.writeContract(request);
846
+ console.log(` \u{1F4E4} Deploy Token Tx: ${deployTx}`);
847
+ txs.push(deployTx);
848
+ const receipt = await client.waitForTransactionReceipt({ hash: deployTx });
849
+ const newTokenAddress = await client.readContract({
850
+ address: usedAddresses.xPNTsFactory,
851
+ abi: factoryAbi,
852
+ functionName: "getTokenAddress",
853
+ args: [account.address]
854
+ });
855
+ if (newTokenAddress) {
856
+ tokenAddress = newTokenAddress;
857
+ console.log(` \u{1FA99} Token Deployed: ${tokenAddress}`);
858
+ }
859
+ } catch (deployError) {
860
+ console.warn(" \u26A0\uFE0F Failed to deploy token, but community registered:", deployError);
861
+ }
862
+ }
863
+ return { tokenAddress, txs };
864
+ } catch (error) {
865
+ console.error("\u274C Error in launch():", error);
866
+ const errorMessage = error.message || "";
867
+ const errorData = error.data?.errorName || "";
868
+ const errorString = JSON.stringify(error);
869
+ if (errorMessage.includes("RoleAlreadyGranted") || errorData === "RoleAlreadyGranted" || errorString.includes("RoleAlreadyGranted")) {
870
+ throw new Error(`Account ${account?.address || "unknown"} already has COMMUNITY role. Please use a different account or exit the role first.`);
871
+ }
872
+ if (errorMessage.includes("InsufficientStake")) {
873
+ throw new Error("Insufficient stake. Please ensure you have enough GToken staked.");
874
+ }
875
+ if (errorMessage.includes("RoleNotConfigured")) {
876
+ throw new Error("COMMUNITY role is not configured in the Registry contract.");
877
+ }
878
+ throw error;
879
+ }
880
+ };
881
+ const getCommunityInfo = async (accountAddress) => {
882
+ try {
883
+ const hasRole = await client.readContract({
884
+ address: usedAddresses.registry,
885
+ abi: RegistryABI,
886
+ functionName: "hasRole",
887
+ args: [RoleIds.COMMUNITY, accountAddress]
888
+ });
889
+ if (!hasRole) {
890
+ return {
891
+ hasRole: false,
892
+ tokenAddress: null,
893
+ communityData: null
894
+ };
895
+ }
896
+ const factoryAbi = [
897
+ {
898
+ inputs: [{ name: "community", type: "address" }],
899
+ name: "getTokenAddress",
900
+ outputs: [{ name: "", type: "address" }],
901
+ stateMutability: "view",
902
+ type: "function"
903
+ }
904
+ ];
905
+ const tokenAddress = await client.readContract({
906
+ address: usedAddresses.xPNTsFactory,
907
+ abi: factoryAbi,
908
+ functionName: "getTokenAddress",
909
+ args: [accountAddress]
910
+ });
911
+ const metadata = await client.readContract({
912
+ address: usedAddresses.registry,
913
+ abi: RegistryABI,
914
+ functionName: "roleMetadata",
915
+ args: [RoleIds.COMMUNITY, accountAddress]
916
+ });
917
+ let communityData = {
918
+ name: "Community",
919
+ ensName: "",
920
+ website: "",
921
+ description: "",
922
+ logoURI: ""
923
+ };
924
+ if (metadata && metadata !== "0x") {
925
+ try {
926
+ const decoded = RoleDataFactory.decodeCommunity(metadata);
927
+ communityData = {
928
+ name: decoded.name || "Community",
929
+ ensName: decoded.ensName || "",
930
+ website: decoded.website || "",
931
+ description: decoded.description || "",
932
+ logoURI: decoded.logoURI || ""
933
+ };
934
+ } catch (e) {
935
+ console.warn(" \u26A0\uFE0F Failed to decode community metadata:", e);
936
+ }
937
+ }
938
+ return {
939
+ hasRole: true,
940
+ tokenAddress: tokenAddress && tokenAddress !== "0x0000000000000000000000000000000000000000" ? tokenAddress : null,
941
+ communityData: metadata && metadata !== "0x" ? communityData : null
942
+ };
943
+ } catch (error) {
944
+ console.error("Error fetching community info:", error);
945
+ return {
946
+ hasRole: false,
947
+ tokenAddress: null,
948
+ communityData: null
949
+ };
950
+ }
951
+ };
952
+ return Object.assign(client, registryActionsObj, sbtActionsObj, {
953
+ launch,
954
+ getCommunityInfo
955
+ });
956
+ }
957
+ var ADDRESS_PLACEHOLDER = "0x0000000000000000000000000000000000000000";
958
+ function createAdminClient({
959
+ chain,
960
+ transport,
961
+ account,
962
+ addresses
963
+ }) {
964
+ const baseClient = createClient({ chain, transport, account }).extend(publicActions).extend(walletActions);
965
+ const usedAddresses = { ...CORE_ADDRESSES, ...TOKEN_ADDRESSES, ...addresses };
966
+ const actions = {
967
+ ...registryActions(usedAddresses.registry)(baseClient),
968
+ ...superPaymasterActions(usedAddresses.superPaymaster)(baseClient),
969
+ ...paymasterActions(usedAddresses.paymasterV4)(baseClient),
970
+ ...stakingActions(usedAddresses.gTokenStaking)(baseClient),
971
+ ...sbtActions(usedAddresses.mySBT)(baseClient),
972
+ ...dvtActions(ADDRESS_PLACEHOLDER)(baseClient),
973
+ ...xPNTsFactoryActions(usedAddresses.xPNTsFactory || "0x")(baseClient),
974
+ ...aggregatorActions(ADDRESS_PLACEHOLDER)(baseClient)
975
+ };
976
+ return Object.assign(baseClient, actions);
977
+ }
978
+ var ExperimentClient = class {
979
+ records = [];
980
+ scenarioId;
981
+ group;
982
+ constructor(scenarioId, group) {
983
+ this.scenarioId = scenarioId;
984
+ this.group = group;
985
+ }
986
+ /**
987
+ * Record a transaction result
988
+ */
989
+ recordTx(txHash, receipt, status, meta) {
990
+ const gasUsed = BigInt(receipt.gasUsed || 0);
991
+ const gasPrice = BigInt(receipt.effectiveGasPrice || 0);
992
+ const costBN = gasUsed * gasPrice;
993
+ const record = {
994
+ id: `${Date.now()}-${Math.floor(Math.random() * 1e3)}`,
995
+ scenario: this.scenarioId,
996
+ group: this.group,
997
+ txHash,
998
+ gasUsed,
999
+ gasPrice,
1000
+ costETH: formatEther(costBN),
1001
+ status,
1002
+ timestamp: Date.now(),
1003
+ meta
1004
+ };
1005
+ this.records.push(record);
1006
+ return record;
1007
+ }
1008
+ /**
1009
+ * Measure an async task (transaction) automatically
1010
+ */
1011
+ async measureTx(taskName, txPromise, publicClient) {
1012
+ console.log(`[Experiment: ${this.group}] Executing: ${taskName}...`);
1013
+ const start = Date.now();
1014
+ try {
1015
+ const hash = await txPromise;
1016
+ const receipt = await publicClient.waitForTransactionReceipt({ hash });
1017
+ this.recordTx(hash, receipt, "Success", { latency: Date.now() - start });
1018
+ const gasUsed = BigInt(receipt.gasUsed || 0);
1019
+ const gasPrice = BigInt(receipt.effectiveGasPrice || 0);
1020
+ console.log(` \u2705 Success! Gas: ${gasUsed} | Cost: ${formatEther(gasUsed * gasPrice)} ETH`);
1021
+ return hash;
1022
+ } catch (e) {
1023
+ console.error(` \u274C Failed: ${taskName}`, e);
1024
+ throw e;
1025
+ }
1026
+ }
1027
+ getRecords() {
1028
+ return this.records;
1029
+ }
1030
+ };
1031
+ var KeyManager = class {
1032
+ /**
1033
+ * 生成单个密钥对
1034
+ * @param name - 密钥名称(如 'Jason', 'Anni')
1035
+ */
1036
+ static generateKeyPair(name) {
1037
+ const privateKey = generatePrivateKey();
1038
+ const account = privateKeyToAccount(privateKey);
1039
+ return {
1040
+ name,
1041
+ privateKey,
1042
+ address: account.address
1043
+ };
1044
+ }
1045
+ /**
1046
+ * 批量生成密钥对
1047
+ * @param names - 密钥名称数组
1048
+ */
1049
+ static generateKeyPairs(names) {
1050
+ return names.map((name) => this.generateKeyPair(name));
1051
+ }
1052
+ /**
1053
+ * 生成指定数量的密钥对(自动命名为 Operator_1, Operator_2, ...)
1054
+ * @param count - 数量
1055
+ * @param prefix - 名称前缀(默认 'Operator')
1056
+ */
1057
+ static generateMultiple(count, prefix = "Operator") {
1058
+ const names = Array.from({ length: count }, (_, i) => `${prefix}_${i + 1}`);
1059
+ return this.generateKeyPairs(names);
1060
+ }
1061
+ /**
1062
+ * 保存密钥到 .env 文件
1063
+ * @param filePath - 文件路径(绝对路径)
1064
+ * @param keys - 密钥对数组
1065
+ * @param overwrite - 是否覆盖已存在的文件(默认 false)
1066
+ */
1067
+ static saveToEnvFile(filePath, keys, overwrite = false) {
1068
+ if (fs.existsSync(filePath) && !overwrite) {
1069
+ throw new Error(`File already exists: ${filePath}. Set overwrite=true to replace.`);
1070
+ }
1071
+ const content = keys.map(
1072
+ (k) => `${k.name.toUpperCase().replace(/\s+/g, "_")}_PRIVATE_KEY=${k.privateKey}`
1073
+ ).join("\n") + "\n";
1074
+ fs.writeFileSync(filePath, content, { mode: 384 });
1075
+ console.log(`\u2705 Keys saved to ${filePath} (${keys.length} keys)`);
1076
+ }
1077
+ /**
1078
+ * 从 .env 文件加载密钥
1079
+ * @param filePath - 文件路径(绝对路径)
1080
+ * @returns 密钥对数组
1081
+ */
1082
+ static loadFromEnvFile(filePath) {
1083
+ if (!fs.existsSync(filePath)) {
1084
+ throw new Error(`File not found: ${filePath}`);
1085
+ }
1086
+ const content = fs.readFileSync(filePath, "utf-8");
1087
+ const lines = content.split("\n").filter((line) => line.trim() && !line.startsWith("#"));
1088
+ return lines.map((line) => {
1089
+ const [key, value] = line.split("=");
1090
+ const name = key.replace(/_PRIVATE_KEY$/, "").toLowerCase().replace(/_/g, " ");
1091
+ const privateKey = value.trim();
1092
+ const account = privateKeyToAccount(privateKey);
1093
+ return {
1094
+ name,
1095
+ privateKey,
1096
+ address: account.address
1097
+ };
1098
+ });
1099
+ }
1100
+ /**
1101
+ * 保存密钥到 JSON 文件(包含地址信息)
1102
+ * @param filePath - 文件路径(绝对路径)
1103
+ * @param keys - 密钥对数组
1104
+ * @param overwrite - 是否覆盖已存在的文件(默认 false)
1105
+ */
1106
+ static saveToJsonFile(filePath, keys, overwrite = false) {
1107
+ if (fs.existsSync(filePath) && !overwrite) {
1108
+ throw new Error(`File already exists: ${filePath}. Set overwrite=true to replace.`);
1109
+ }
1110
+ const data = {
1111
+ generated: (/* @__PURE__ */ new Date()).toISOString(),
1112
+ keys: keys.map((k) => ({
1113
+ name: k.name,
1114
+ privateKey: k.privateKey,
1115
+ address: k.address
1116
+ }))
1117
+ };
1118
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2), { mode: 384 });
1119
+ console.log(`\u2705 Keys saved to ${filePath} (${keys.length} keys)`);
1120
+ }
1121
+ /**
1122
+ * 从 JSON 文件加载密钥
1123
+ * @param filePath - 文件路径(绝对路径)
1124
+ */
1125
+ static loadFromJsonFile(filePath) {
1126
+ if (!fs.existsSync(filePath)) {
1127
+ throw new Error(`File not found: ${filePath}`);
1128
+ }
1129
+ const content = fs.readFileSync(filePath, "utf-8");
1130
+ const data = JSON.parse(content);
1131
+ return data.keys.map((k) => ({
1132
+ name: k.name,
1133
+ privateKey: k.privateKey,
1134
+ address: k.address
1135
+ }));
1136
+ }
1137
+ /**
1138
+ * 打印密钥信息(隐藏私钥)
1139
+ * @param keys - 密钥对数组
1140
+ */
1141
+ static printKeys(keys, showPrivateKey = false) {
1142
+ console.log("\n\u{1F511} Generated Keys:");
1143
+ console.log("\u2500".repeat(80));
1144
+ keys.forEach((k, i) => {
1145
+ console.log(`${i + 1}. ${k.name}`);
1146
+ console.log(` Address: ${k.address}`);
1147
+ if (showPrivateKey) {
1148
+ console.log(` Private Key: ${k.privateKey}`);
1149
+ } else {
1150
+ console.log(` Private Key: ${k.privateKey.slice(0, 10)}...${k.privateKey.slice(-8)}`);
1151
+ }
1152
+ });
1153
+ console.log("\u2500".repeat(80));
1154
+ }
1155
+ };
1156
+ var FundingManager = class {
1157
+ /**
1158
+ * 创建 PublicClient 和 WalletClient
1159
+ */
1160
+ static createClients(params) {
1161
+ const account = privateKeyToAccount(params.supplierKey);
1162
+ const transport = http(params.rpcUrl);
1163
+ const publicClient = createPublicClient({
1164
+ chain: params.chain,
1165
+ transport
1166
+ });
1167
+ const walletClient = createWalletClient({
1168
+ account,
1169
+ chain: params.chain,
1170
+ transport
1171
+ });
1172
+ return { publicClient, walletClient, account };
1173
+ }
1174
+ /**
1175
+ * 充值 ETH 到目标地址
1176
+ * @param params - 充值参数
1177
+ * @returns 充值结果
1178
+ */
1179
+ static async fundWithETH(params) {
1180
+ try {
1181
+ const { publicClient, walletClient } = this.createClients(params);
1182
+ const amount = parseEther(params.amount);
1183
+ console.log(`\u{1F4B8} Funding ${params.targetAddress} with ${params.amount} ETH...`);
1184
+ const hash = await walletClient.sendTransaction({
1185
+ account: walletClient.account,
1186
+ chain: params.chain,
1187
+ to: params.targetAddress,
1188
+ value: amount
1189
+ });
1190
+ console.log(` Transaction Sent: ${hash}`);
1191
+ await publicClient.waitForTransactionReceipt({ hash });
1192
+ console.log(` \u2705 ETH Funded.`);
1193
+ return { success: true, txHash: hash };
1194
+ } catch (error) {
1195
+ console.error(` \u274C ETH Funding Failed:`, error);
1196
+ return { success: false, error: error.message };
1197
+ }
1198
+ }
1199
+ /**
1200
+ * 充值 ERC20 Token 到目标地址
1201
+ * @param params - 充值参数
1202
+ * @returns 充值结果
1203
+ */
1204
+ static async fundWithToken(params) {
1205
+ try {
1206
+ const { publicClient, walletClient, account } = this.createClients(params);
1207
+ const amount = parseEther(params.amount);
1208
+ console.log(`\u{1F4B8} Funding ${params.targetAddress} with ${params.amount} tokens...`);
1209
+ const { request } = await publicClient.simulateContract({
1210
+ account,
1211
+ address: params.tokenAddress,
1212
+ abi: erc20Abi,
1213
+ functionName: "transfer",
1214
+ args: [params.targetAddress, amount]
1215
+ });
1216
+ const hash = await walletClient.writeContract(request);
1217
+ console.log(` Transaction Sent: ${hash}`);
1218
+ await publicClient.waitForTransactionReceipt({ hash });
1219
+ console.log(` \u2705 Token Funded.`);
1220
+ return { success: true, txHash: hash };
1221
+ } catch (error) {
1222
+ console.error(` \u274C Token Funding Failed:`, error);
1223
+ return { success: false, error: error.message };
1224
+ }
1225
+ }
1226
+ /**
1227
+ * 检查 ETH 余额
1228
+ * @param params - 基础参数
1229
+ * @returns ETH 余额(wei)
1230
+ */
1231
+ static async getETHBalance(params) {
1232
+ const { publicClient } = this.createClients(params);
1233
+ return await publicClient.getBalance({ address: params.targetAddress });
1234
+ }
1235
+ /**
1236
+ * 检查 ERC20 Token 余额
1237
+ * @param params - 基础参数
1238
+ * @param tokenAddress - Token 合约地址
1239
+ * @returns Token 余额
1240
+ */
1241
+ static async getTokenBalance(params, tokenAddress) {
1242
+ const { publicClient } = this.createClients(params);
1243
+ return await publicClient.readContract({
1244
+ address: tokenAddress,
1245
+ abi: erc20Abi,
1246
+ functionName: "balanceOf",
1247
+ args: [params.targetAddress]
1248
+ });
1249
+ }
1250
+ /**
1251
+ * 智能充值:检查余额,不足时自动充值
1252
+ * @param params - 充值参数
1253
+ * @returns 充值结果数组
1254
+ */
1255
+ static async ensureFunding(params) {
1256
+ const results = [];
1257
+ const { publicClient } = this.createClients(params);
1258
+ if (params.minETH && params.targetETH) {
1259
+ const ethBalance = await publicClient.getBalance({ address: params.targetAddress });
1260
+ const minETH = parseEther(params.minETH);
1261
+ parseEther(params.targetETH);
1262
+ if (ethBalance < minETH) {
1263
+ console.log(`\u26A0\uFE0F ETH balance (${Number(ethBalance) / 1e18}) below threshold (${params.minETH})`);
1264
+ const result = await this.fundWithETH({
1265
+ ...params,
1266
+ amount: params.targetETH
1267
+ });
1268
+ results.push(result);
1269
+ } else {
1270
+ console.log(`\u2705 Sufficient ETH: ${Number(ethBalance) / 1e18} ETH`);
1271
+ results.push({ success: true });
1272
+ }
1273
+ }
1274
+ if (params.token) {
1275
+ const tokenBalance = await this.getTokenBalance(params, params.token.address);
1276
+ const minToken = params.token.minBalance ? parseEther(params.token.minBalance) : 0n;
1277
+ const targetToken = params.token.targetAmount ? parseEther(params.token.targetAmount) : 0n;
1278
+ if (tokenBalance < minToken && targetToken > 0n) {
1279
+ console.log(`\u26A0\uFE0F Token balance (${Number(tokenBalance) / 1e18}) below threshold (${params.token.minBalance})`);
1280
+ const result = await this.fundWithToken({
1281
+ ...params,
1282
+ tokenAddress: params.token.address,
1283
+ amount: params.token.targetAmount
1284
+ });
1285
+ results.push(result);
1286
+ } else {
1287
+ console.log(`\u2705 Sufficient Token: ${Number(tokenBalance) / 1e18}`);
1288
+ results.push({ success: true });
1289
+ }
1290
+ }
1291
+ return results;
1292
+ }
1293
+ /**
1294
+ * 批量充值 ETH
1295
+ * @param params - 基础参数
1296
+ * @param targets - 目标地址和金额数组
1297
+ * @returns 充值结果数组
1298
+ */
1299
+ static async batchFundETH(params, targets) {
1300
+ const results = [];
1301
+ for (const target of targets) {
1302
+ const result = await this.fundWithETH({
1303
+ ...params,
1304
+ targetAddress: target.address,
1305
+ amount: target.amount
1306
+ });
1307
+ results.push(result);
1308
+ }
1309
+ return results;
1310
+ }
1311
+ /**
1312
+ * 批量充值 Token
1313
+ * @param params - 基础参数
1314
+ * @param tokenAddress - Token 合约地址
1315
+ * @param targets - 目标地址和金额数组
1316
+ * @returns 充值结果数组
1317
+ */
1318
+ static async batchFundToken(params, tokenAddress, targets) {
1319
+ const results = [];
1320
+ for (const target of targets) {
1321
+ const result = await this.fundWithToken({
1322
+ ...params,
1323
+ targetAddress: target.address,
1324
+ tokenAddress,
1325
+ amount: target.amount
1326
+ });
1327
+ results.push(result);
1328
+ }
1329
+ return results;
1330
+ }
1331
+ };
1332
+ var UserOperationBuilder = class {
1333
+ /**
1334
+ * Packs verificationGasLimit and callGasLimit into a bytes32 Hex string.
1335
+ */
1336
+ static packAccountGasLimits(verificationGasLimit, callGasLimit) {
1337
+ return concat([
1338
+ pad(`0x${verificationGasLimit.toString(16)}`, { dir: "left", size: 16 }),
1339
+ pad(`0x${callGasLimit.toString(16)}`, { dir: "left", size: 16 })
1340
+ ]);
1341
+ }
1342
+ /**
1343
+ * Packs maxPriorityFeePerGas and maxFeePerGas into a bytes32 Hex string.
1344
+ */
1345
+ static packGasFees(maxPriorityFeePerGas, maxFeePerGas) {
1346
+ return concat([
1347
+ pad(`0x${maxPriorityFeePerGas.toString(16)}`, { dir: "left", size: 16 }),
1348
+ pad(`0x${maxFeePerGas.toString(16)}`, { dir: "left", size: 16 })
1349
+ ]);
1350
+ }
1351
+ static estimatePreVerificationGasV07(userOp) {
1352
+ const nonce = typeof userOp.nonce === "bigint" ? userOp.nonce : typeof userOp.nonce === "number" ? BigInt(userOp.nonce) : BigInt(userOp.nonce);
1353
+ const preVerificationGas = typeof userOp.preVerificationGas === "bigint" ? userOp.preVerificationGas : typeof userOp.preVerificationGas === "number" ? BigInt(userOp.preVerificationGas) : BigInt(userOp.preVerificationGas);
1354
+ const encoded = encodeAbiParameters(
1355
+ parseAbiParameters("(address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes)"),
1356
+ [
1357
+ [
1358
+ userOp.sender,
1359
+ nonce,
1360
+ userOp.initCode,
1361
+ userOp.callData,
1362
+ userOp.accountGasLimits,
1363
+ preVerificationGas,
1364
+ userOp.gasFees,
1365
+ userOp.paymasterAndData,
1366
+ userOp.signature
1367
+ ]
1368
+ ]
1369
+ );
1370
+ const bytes = toBytes(encoded);
1371
+ let calldataCost = 0n;
1372
+ for (const b of bytes) calldataCost += b === 0 ? 4n : 16n;
1373
+ return calldataCost + 26000n;
1374
+ }
1375
+ /**
1376
+ * Packs Paymaster parameters into the v0.7 paymasterAndData format.
1377
+ */
1378
+ static packPaymasterAndData(paymaster, paymasterGasLimit, paymasterPostOpGasLimit, paymasterData = "0x") {
1379
+ return concat([
1380
+ paymaster,
1381
+ pad(`0x${paymasterGasLimit.toString(16)}`, { dir: "left", size: 16 }),
1382
+ pad(`0x${paymasterPostOpGasLimit.toString(16)}`, { dir: "left", size: 16 }),
1383
+ paymasterData
1384
+ ]);
1385
+ }
1386
+ /**
1387
+ * Pack PaymasterV4 Deposit-Only paymasterAndData
1388
+ *
1389
+ * v0.7 EntryPoint packs: [paymaster(20)][verificationGas(16)][postOpGas(16)][paymasterData]
1390
+ * Contract extracts token at offset 52 = paymasterData[0:20]
1391
+ *
1392
+ * So paymasterData format must be: [token(20)][validUntil(6)][validAfter(6)]
1393
+ *
1394
+ * @param paymaster - Paymaster address (20 bytes)
1395
+ * @param paymentToken - ERC20 token address (20 bytes, FIRST in paymasterData!)
1396
+ * @param validUntil - Validity end timestamp (6 bytes)
1397
+ * @param validAfter - Validity start timestamp (6 bytes)
1398
+ */
1399
+ static packPaymasterV4DepositData(paymaster, paymasterVerificationGasLimit, paymasterPostOpGasLimit, paymentToken, validUntil, validAfter) {
1400
+ return concat([
1401
+ paymaster,
1402
+ pad(`0x${paymasterVerificationGasLimit.toString(16)}`, { dir: "left", size: 16 }),
1403
+ pad(`0x${paymasterPostOpGasLimit.toString(16)}`, { dir: "left", size: 16 }),
1404
+ paymentToken,
1405
+ pad(`0x${validUntil.toString(16)}`, { dir: "left", size: 6 }),
1406
+ pad(`0x${validAfter.toString(16)}`, { dir: "left", size: 6 })
1407
+ ]);
1408
+ }
1409
+ /**
1410
+ * Computes the UserOperation hash for signing.
1411
+ */
1412
+ static async getUserOpHash({
1413
+ userOp,
1414
+ entryPoint,
1415
+ chainId,
1416
+ publicClient
1417
+ }) {
1418
+ return await publicClient.readContract({
1419
+ address: entryPoint,
1420
+ abi: [{
1421
+ type: "function",
1422
+ name: "getUserOpHash",
1423
+ inputs: [{
1424
+ type: "tuple",
1425
+ components: [
1426
+ { name: "sender", type: "address" },
1427
+ { name: "nonce", type: "uint256" },
1428
+ { name: "initCode", type: "bytes" },
1429
+ { name: "callData", type: "bytes" },
1430
+ { name: "accountGasLimits", type: "bytes32" },
1431
+ { name: "preVerificationGas", type: "uint256" },
1432
+ { name: "gasFees", type: "bytes32" },
1433
+ { name: "paymasterAndData", type: "bytes" },
1434
+ { name: "signature", type: "bytes" }
1435
+ ]
1436
+ }],
1437
+ outputs: [{ type: "bytes32" }],
1438
+ stateMutability: "view"
1439
+ }],
1440
+ functionName: "getUserOpHash",
1441
+ args: [userOp]
1442
+ });
1443
+ }
1444
+ /**
1445
+ * Formats a PackedUserOperation into a JSON-RPC compatible object with hex-encoded strings.
1446
+ */
1447
+ static jsonifyUserOp(userOp) {
1448
+ const result = {
1449
+ sender: userOp.sender,
1450
+ nonce: userOp.nonce,
1451
+ initCode: userOp.initCode,
1452
+ callData: userOp.callData,
1453
+ accountGasLimits: userOp.accountGasLimits,
1454
+ preVerificationGas: userOp.preVerificationGas,
1455
+ gasFees: userOp.gasFees,
1456
+ paymasterAndData: userOp.paymasterAndData,
1457
+ signature: userOp.signature
1458
+ };
1459
+ const toCompactHex = (val) => {
1460
+ if (typeof val === "bigint") return `0x${val.toString(16)}`;
1461
+ if (typeof val === "number") return `0x${val.toString(16)}`;
1462
+ if (typeof val === "string") {
1463
+ if (val === "0x") return "0x0";
1464
+ if (val === "0x0") return "0x0";
1465
+ return val.replace(/^0x0+(?!$)/, "0x");
1466
+ }
1467
+ return val;
1468
+ };
1469
+ result.nonce = toCompactHex(result.nonce);
1470
+ result.preVerificationGas = toCompactHex(result.preVerificationGas);
1471
+ return result;
1472
+ }
1473
+ /**
1474
+ * Converts a PackedUserOperation to the Alchemy-specific v0.7 JSON format.
1475
+ * @param userOp - The packed UserOperation
1476
+ * @param options - Optional configuration
1477
+ * @param options.paymasterVerificationGasLimit - Gas limit for paymaster verification (default: 200000)
1478
+ * @param options.paymasterPostOpGasLimit - Gas limit for paymaster postOp (default: 200000)
1479
+ */
1480
+ static toAlchemyUserOperation(userOp, options) {
1481
+ const toHexStr = (val) => {
1482
+ if (val === void 0 || val === null) return void 0;
1483
+ if (typeof val === "bigint") return `0x${val.toString(16)}`;
1484
+ if (typeof val === "number") return `0x${val.toString(16)}`;
1485
+ if (typeof val === "string" && !val.startsWith("0x")) return `0x${val}`;
1486
+ return val;
1487
+ };
1488
+ const result = {
1489
+ sender: userOp.sender,
1490
+ nonce: toHexStr(userOp.nonce),
1491
+ callData: userOp.callData,
1492
+ signature: userOp.signature
1493
+ };
1494
+ if (userOp.accountGasLimits && userOp.accountGasLimits !== "0x") {
1495
+ const val = userOp.accountGasLimits.toString().startsWith("0x") ? userOp.accountGasLimits.slice(2) : userOp.accountGasLimits;
1496
+ const padded = val.padStart(64, "0");
1497
+ const verificationGasLimit = BigInt("0x" + padded.slice(0, 32));
1498
+ const callGasLimit = BigInt("0x" + padded.slice(32, 64));
1499
+ result.verificationGasLimit = `0x${verificationGasLimit.toString(16)}`;
1500
+ result.callGasLimit = `0x${callGasLimit.toString(16)}`;
1501
+ }
1502
+ if (userOp.gasFees && userOp.gasFees !== "0x") {
1503
+ const val = userOp.gasFees.toString().startsWith("0x") ? userOp.gasFees.slice(2) : userOp.gasFees;
1504
+ const padded = val.padStart(64, "0");
1505
+ const maxPriorityFeePerGas = BigInt("0x" + padded.slice(0, 32));
1506
+ const maxFeePerGas = BigInt("0x" + padded.slice(32, 64));
1507
+ result.maxPriorityFeePerGas = `0x${maxPriorityFeePerGas.toString(16)}`;
1508
+ result.maxFeePerGas = `0x${maxFeePerGas.toString(16)}`;
1509
+ }
1510
+ if (userOp.preVerificationGas) {
1511
+ result.preVerificationGas = `0x${BigInt(userOp.preVerificationGas).toString(16)}`;
1512
+ }
1513
+ if (userOp.initCode && userOp.initCode !== "0x") {
1514
+ const initCode = userOp.initCode.toString();
1515
+ result.factory = initCode.slice(0, 42);
1516
+ result.factoryData = "0x" + initCode.slice(42);
1517
+ }
1518
+ if (userOp.paymasterAndData && userOp.paymasterAndData !== "0x") {
1519
+ const pmd = userOp.paymasterAndData.toString().startsWith("0x") ? userOp.paymasterAndData.slice(2) : userOp.paymasterAndData;
1520
+ if (pmd.length >= 104) {
1521
+ result.paymaster = "0x" + pmd.slice(0, 40);
1522
+ const vGas = BigInt("0x" + pmd.slice(40, 72));
1523
+ const pGas = BigInt("0x" + pmd.slice(72, 104));
1524
+ result.paymasterVerificationGasLimit = `0x${vGas.toString(16)}`;
1525
+ result.paymasterPostOpGasLimit = `0x${pGas.toString(16)}`;
1526
+ result.paymasterData = "0x" + pmd.slice(104);
1527
+ } else if (pmd.length >= 40) {
1528
+ result.paymaster = "0x" + pmd.slice(0, 40);
1529
+ result.paymasterData = "0x" + pmd.slice(40);
1530
+ const defaultGasLimit = 200000n;
1531
+ result.paymasterVerificationGasLimit = `0x${(options?.paymasterVerificationGasLimit || defaultGasLimit).toString(16)}`;
1532
+ result.paymasterPostOpGasLimit = `0x${(options?.paymasterPostOpGasLimit || defaultGasLimit).toString(16)}`;
1533
+ }
1534
+ }
1535
+ return result;
1536
+ }
1537
+ };
1538
+ var UserOpScenarioType = /* @__PURE__ */ ((UserOpScenarioType2) => {
1539
+ UserOpScenarioType2["NATIVE"] = "NATIVE";
1540
+ UserOpScenarioType2["GASLESS_V4"] = "GASLESS_V4";
1541
+ UserOpScenarioType2["SUPER_BPNT"] = "SUPER_BPNT";
1542
+ UserOpScenarioType2["SUPER_CPNT"] = "SUPER_CPNT";
1543
+ UserOpScenarioType2["SUPER_CUSTOM"] = "SUPER_CUSTOM";
1544
+ return UserOpScenarioType2;
1545
+ })(UserOpScenarioType || {});
1546
+ var UserOpScenarioBuilder = class {
1547
+ /**
1548
+ * Builds a signed PackedUserOperation for a token transfer based on the specified scenario.
1549
+ */
1550
+ static async buildTransferScenario(type, params) {
1551
+ const {
1552
+ sender,
1553
+ ownerAccount,
1554
+ recipient,
1555
+ tokenAddress,
1556
+ amount,
1557
+ entryPoint,
1558
+ chainId,
1559
+ publicClient,
1560
+ paymaster,
1561
+ operator,
1562
+ paymasterGasLimit = 100000n,
1563
+ paymasterPostOpGasLimit = 40000n,
1564
+ nonceKey = 0n,
1565
+ gasToken
1566
+ } = params;
1567
+ const transferData = encodeFunctionData({
1568
+ abi: [{ name: "transfer", type: "function", inputs: [{ type: "address", name: "to" }, { type: "uint256", name: "amount" }], outputs: [{ type: "bool" }] }],
1569
+ functionName: "transfer",
1570
+ args: [recipient, amount]
1571
+ });
1572
+ const callData = encodeFunctionData({
1573
+ abi: [{ name: "execute", type: "function", inputs: [{ type: "address" }, { type: "uint256" }, { type: "bytes" }] }],
1574
+ functionName: "execute",
1575
+ args: [tokenAddress, 0n, transferData]
1576
+ });
1577
+ const userOp = {
1578
+ sender,
1579
+ nonce: await publicClient.readContract({
1580
+ address: entryPoint,
1581
+ abi: [{ name: "getNonce", type: "function", inputs: [{ type: "address" }, { type: "uint192" }], outputs: [{ type: "uint256" }] }],
1582
+ functionName: "getNonce",
1583
+ args: [sender, nonceKey]
1584
+ }),
1585
+ initCode: "0x",
1586
+ callData,
1587
+ accountGasLimits: UserOperationBuilder.packAccountGasLimits(type === "NATIVE" /* NATIVE */ ? 75000n : 250000n, 150000n),
1588
+ preVerificationGas: 80000n,
1589
+ gasFees: UserOperationBuilder.packGasFees(2000000000n, 2000000000n),
1590
+ // 2 Gwei
1591
+ paymasterAndData: "0x",
1592
+ signature: "0x"
1593
+ };
1594
+ if (type === "NATIVE" /* NATIVE */) {
1595
+ userOp.paymasterAndData = "0x";
1596
+ } else if (type === "GASLESS_V4" /* GASLESS_V4 */) {
1597
+ const pm = paymaster;
1598
+ const token = gasToken || tokenAddress;
1599
+ const validUntil = BigInt(Math.floor(Date.now() / 1e3) + 3600);
1600
+ const validAfter = BigInt(Math.floor(Date.now() / 1e3) - 100);
1601
+ if (!pm) throw new Error("paymaster address required for GASLESS_V4");
1602
+ if (!token) throw new Error("gasToken or tokenAddress required for GASLESS_V4");
1603
+ userOp.paymasterAndData = UserOperationBuilder.packPaymasterV4DepositData(
1604
+ pm,
1605
+ paymasterGasLimit,
1606
+ // paymasterVerificationGasLimit
1607
+ paymasterPostOpGasLimit,
1608
+ // paymasterPostOpGasLimit
1609
+ token,
1610
+ // Payment token
1611
+ validUntil,
1612
+ validAfter
1613
+ );
1614
+ } else if (type.startsWith("SUPER_")) {
1615
+ if (!paymaster || !operator) throw new Error("Paymaster and Operator required for SuperPM scenarios");
1616
+ userOp.paymasterAndData = UserOperationBuilder.packPaymasterAndData(
1617
+ paymaster,
1618
+ paymasterGasLimit,
1619
+ paymasterPostOpGasLimit,
1620
+ operator
1621
+ );
1622
+ }
1623
+ const opHash = await UserOperationBuilder.getUserOpHash({
1624
+ userOp,
1625
+ entryPoint,
1626
+ chainId,
1627
+ publicClient
1628
+ });
1629
+ const signature = await ownerAccount.signMessage({
1630
+ message: { raw: opHash }
1631
+ });
1632
+ userOp.signature = signature;
1633
+ const jsonUserOp = UserOperationBuilder.jsonifyUserOp(userOp);
1634
+ return { userOp: jsonUserOp, opHash };
1635
+ }
1636
+ };
1637
+
1638
+ export { CustomErrors, ExperimentClient, FundingManager, KeyManager, RoleDataFactory, RoleIds, UserOpScenarioBuilder, UserOpScenarioType, UserOperationBuilder, createAdminClient, createCommunityClient, createEndUserClient, createOperatorClient, decodeContractError };
1639
+ //# sourceMappingURL=index.js.map
1640
+ //# sourceMappingURL=index.js.map