@aastar/sdk 0.18.0 → 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 -21
  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 +601 -12
  63. package/dist/index.js +1640 -28
  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 +87 -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
@@ -0,0 +1 @@
1
+ export * from '@aastar/operator';
@@ -0,0 +1,6 @@
1
+ export { OperatorLifecycle, PaymasterOperatorClient, ProposalState, ProtocolClient } from './chunk-O3Y7II3B.js';
2
+ import './chunk-ZSSNU3UF.js';
3
+ import './chunk-DSZ372PH.js';
4
+ import './chunk-PZ5AY32C.js';
5
+ //# sourceMappingURL=operator.js.map
6
+ //# sourceMappingURL=operator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"operator.js"}
@@ -0,0 +1 @@
1
+ export * from '@aastar/paymaster';
@@ -0,0 +1,6 @@
1
+ export { PaymasterClient, PaymasterManager, PaymasterOperator, SuperPaymasterAdminClient, SuperPaymasterClient, buildPaymasterData, buildSuperPaymasterData, checkEligibility, formatUserOpV07, getPaymasterV4Middleware, getSuperPaymasterMiddleware, getUserOpHashV07, tuneGasLimit } from './chunk-MPOMWT2J.js';
2
+ import './chunk-ZSSNU3UF.js';
3
+ import './chunk-DSZ372PH.js';
4
+ import './chunk-PZ5AY32C.js';
5
+ //# sourceMappingURL=paymaster.js.map
6
+ //# sourceMappingURL=paymaster.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"paymaster.js"}
@@ -0,0 +1 @@
1
+ export * from '@aastar/tokens';
package/dist/tokens.js ADDED
@@ -0,0 +1,6 @@
1
+ export { FinanceClient } from './chunk-PCLPYRTX.js';
2
+ import './chunk-ZSSNU3UF.js';
3
+ import './chunk-DSZ372PH.js';
4
+ import './chunk-PZ5AY32C.js';
5
+ //# sourceMappingURL=tokens.js.map
6
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"tokens.js"}
package/dist/x402.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from '@aastar/x402';
package/dist/x402.js ADDED
@@ -0,0 +1,6 @@
1
+ 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';
2
+ import './chunk-ZSSNU3UF.js';
3
+ import './chunk-DSZ372PH.js';
4
+ import './chunk-PZ5AY32C.js';
5
+ //# sourceMappingURL=x402.js.map
6
+ //# sourceMappingURL=x402.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"x402.js"}
package/package.json CHANGED
@@ -1,39 +1,108 @@
1
1
  {
2
2
  "name": "@aastar/sdk",
3
- "version": "0.18.0",
4
- "description": "AAStar SDK - The all-in-one package for Mycelium Network",
3
+ "version": "0.20.1",
4
+ "description": "AAStar SDK - the all-in-one package for Mycelium Network (single bundled package; subpaths preserve the module structure)",
5
5
  "type": "module",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
9
9
  "license": "MIT",
10
10
  "main": "dist/index.js",
11
+ "module": "dist/index.js",
11
12
  "types": "dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js"
17
+ },
18
+ "./core": {
19
+ "types": "./dist/core.d.ts",
20
+ "import": "./dist/core.js"
21
+ },
22
+ "./account": {
23
+ "types": "./dist/account.d.ts",
24
+ "import": "./dist/account.js"
25
+ },
26
+ "./paymaster": {
27
+ "types": "./dist/paymaster.d.ts",
28
+ "import": "./dist/paymaster.js"
29
+ },
30
+ "./identity": {
31
+ "types": "./dist/identity.d.ts",
32
+ "import": "./dist/identity.js"
33
+ },
34
+ "./tokens": {
35
+ "types": "./dist/tokens.d.ts",
36
+ "import": "./dist/tokens.js"
37
+ },
38
+ "./dapp": {
39
+ "types": "./dist/dapp.d.ts",
40
+ "import": "./dist/dapp.js"
41
+ },
42
+ "./x402": {
43
+ "types": "./dist/x402.d.ts",
44
+ "import": "./dist/x402.js"
45
+ },
46
+ "./channel": {
47
+ "types": "./dist/channel.d.ts",
48
+ "import": "./dist/channel.js"
49
+ },
50
+ "./enduser": {
51
+ "types": "./dist/enduser.d.ts",
52
+ "import": "./dist/enduser.js"
53
+ },
54
+ "./operator": {
55
+ "types": "./dist/operator.d.ts",
56
+ "import": "./dist/operator.js"
57
+ },
58
+ "./admin": {
59
+ "types": "./dist/admin.d.ts",
60
+ "import": "./dist/admin.js"
61
+ },
62
+ "./airaccount": {
63
+ "types": "./dist/airaccount.d.ts",
64
+ "import": "./dist/airaccount.js"
65
+ }
66
+ },
12
67
  "files": [
13
68
  "dist"
14
69
  ],
15
70
  "dependencies": {
16
71
  "viem": "2.43.3",
17
- "@aastar/core": "0.18.0",
18
- "@aastar/dapp": "0.18.0",
19
- "@aastar/account": "0.18.0",
20
- "@aastar/paymaster": "0.18.0",
21
- "@aastar/identity": "0.18.0",
22
- "@aastar/enduser": "0.18.0",
23
- "@aastar/tokens": "0.18.0",
24
- "@aastar/operator": "0.18.0",
25
- "@aastar/admin": "0.18.0",
26
- "@aastar/airaccount": "0.18.0",
27
- "@aastar/x402": "0.18.0",
28
- "@aastar/channel": "0.18.0"
72
+ "ethers": "^6.0.0",
73
+ "@simplewebauthn/browser": "^13.2.2",
74
+ "axios": "^1.12.2"
75
+ },
76
+ "peerDependencies": {
77
+ "react": "^18.0.0",
78
+ "react-dom": "^18.0.0"
79
+ },
80
+ "peerDependenciesMeta": {
81
+ "react": {
82
+ "optional": true
83
+ },
84
+ "react-dom": {
85
+ "optional": true
86
+ }
29
87
  },
30
88
  "devDependencies": {
31
- "typescript": "5.7.2"
89
+ "tsup": "^8.0.0",
90
+ "typescript": "5.7.2",
91
+ "@aastar/account": "0.20.1",
92
+ "@aastar/core": "0.20.1",
93
+ "@aastar/dapp": "0.20.1",
94
+ "@aastar/paymaster": "0.20.1",
95
+ "@aastar/identity": "0.20.1",
96
+ "@aastar/enduser": "0.20.1",
97
+ "@aastar/tokens": "0.20.1",
98
+ "@aastar/operator": "0.20.1",
99
+ "@aastar/admin": "0.20.1",
100
+ "@aastar/x402": "0.20.1",
101
+ "@aastar/airaccount": "0.20.1",
102
+ "@aastar/channel": "0.20.1"
32
103
  },
33
104
  "scripts": {
34
- "clean": "find src -name '*.js' -o -name '*.d.ts' -o -name '*.map' | xargs rm -f",
35
- "prebuild": "pnpm clean",
36
- "build": "tsc",
105
+ "build": "tsup",
37
106
  "example:local": "tsx examples/regression_test.ts",
38
107
  "test": "vitest run"
39
108
  }
@@ -1,34 +0,0 @@
1
- import { Hash } from 'viem';
2
- export interface ExperimentRecord {
3
- id: string;
4
- scenario: string;
5
- group: 'EOA' | 'AA' | 'SuperPaymaster';
6
- txHash: string;
7
- gasUsed: bigint;
8
- gasPrice: bigint;
9
- costETH: string;
10
- status: 'Success' | 'Failed';
11
- timestamp: number;
12
- meta?: any;
13
- }
14
- /**
15
- * ExperimentClient: Business-layer tool for measuring and recording execution metrics
16
- */
17
- export declare class ExperimentClient {
18
- private records;
19
- private scenarioId;
20
- private group;
21
- constructor(scenarioId: string, group: 'EOA' | 'AA' | 'SuperPaymaster');
22
- /**
23
- * Record a transaction result
24
- */
25
- recordTx(txHash: Hash, receipt: {
26
- gasUsed: any;
27
- effectiveGasPrice: any;
28
- }, status: 'Success' | 'Failed', meta?: any): ExperimentRecord;
29
- /**
30
- * Measure an async task (transaction) automatically
31
- */
32
- measureTx(taskName: string, txPromise: Promise<Hash>, publicClient: any): Promise<Hash>;
33
- getRecords(): ExperimentRecord[];
34
- }
@@ -1,58 +0,0 @@
1
- import { formatEther } from 'viem';
2
- /**
3
- * ExperimentClient: Business-layer tool for measuring and recording execution metrics
4
- */
5
- export class ExperimentClient {
6
- records = [];
7
- scenarioId;
8
- group;
9
- constructor(scenarioId, group) {
10
- this.scenarioId = scenarioId;
11
- this.group = group;
12
- }
13
- /**
14
- * Record a transaction result
15
- */
16
- recordTx(txHash, receipt, status, meta) {
17
- const gasUsed = BigInt(receipt.gasUsed || 0);
18
- const gasPrice = BigInt(receipt.effectiveGasPrice || 0);
19
- const costBN = gasUsed * gasPrice;
20
- const record = {
21
- id: `${Date.now()}-${Math.floor(Math.random() * 1000)}`,
22
- scenario: this.scenarioId,
23
- group: this.group,
24
- txHash: txHash,
25
- gasUsed: gasUsed,
26
- gasPrice: gasPrice,
27
- costETH: formatEther(costBN),
28
- status: status,
29
- timestamp: Date.now(),
30
- meta
31
- };
32
- this.records.push(record);
33
- return record;
34
- }
35
- /**
36
- * Measure an async task (transaction) automatically
37
- */
38
- async measureTx(taskName, txPromise, publicClient) {
39
- console.log(`[Experiment: ${this.group}] Executing: ${taskName}...`);
40
- const start = Date.now();
41
- try {
42
- const hash = await txPromise;
43
- const receipt = await publicClient.waitForTransactionReceipt({ hash });
44
- this.recordTx(hash, receipt, 'Success', { latency: Date.now() - start });
45
- const gasUsed = BigInt(receipt.gasUsed || 0);
46
- const gasPrice = BigInt(receipt.effectiveGasPrice || 0);
47
- console.log(` ✅ Success! Gas: ${gasUsed} | Cost: ${formatEther(gasUsed * gasPrice)} ETH`);
48
- return hash;
49
- }
50
- catch (e) {
51
- console.error(` ❌ Failed: ${taskName}`, e);
52
- throw e;
53
- }
54
- }
55
- getRecords() {
56
- return this.records;
57
- }
58
- }
@@ -1,11 +0,0 @@
1
- import { type Client, type Transport, type Chain, type Account, type PublicActions, type WalletActions, type Address } from 'viem';
2
- import { type RegistryActions, type SuperPaymasterActions, type PaymasterActions, type StakingActions, type SBTActions, type DVTActions, type XPNTsFactoryActions, type AggregatorActions } from '@aastar/core';
3
- export type AdminClient = Client<Transport, Chain, Account | undefined> & PublicActions<Transport, Chain, Account | undefined> & WalletActions<Chain, Account | undefined> & RegistryActions & SuperPaymasterActions & PaymasterActions & StakingActions & SBTActions & DVTActions & XPNTsFactoryActions & AggregatorActions;
4
- export declare function createAdminClient({ chain, transport, account, addresses }: {
5
- chain: Chain;
6
- transport: Transport;
7
- account?: Account;
8
- addresses?: {
9
- [key: string]: Address;
10
- };
11
- }): AdminClient;
@@ -1,20 +0,0 @@
1
- import { createClient, publicActions, walletActions } from 'viem';
2
- import { registryActions, superPaymasterActions, paymasterActions, stakingActions, sbtActions, dvtActions, xPNTsFactoryActions, aggregatorActions, CORE_ADDRESSES, TOKEN_ADDRESSES } from '@aastar/core';
3
- const ADDRESS_PLACEHOLDER = '0x0000000000000000000000000000000000000000';
4
- export function createAdminClient({ chain, transport, account, addresses }) {
5
- const baseClient = createClient({ chain, transport, account })
6
- .extend(publicActions)
7
- .extend(walletActions);
8
- const usedAddresses = { ...CORE_ADDRESSES, ...TOKEN_ADDRESSES, ...addresses };
9
- const actions = {
10
- ...registryActions(usedAddresses.registry)(baseClient),
11
- ...superPaymasterActions(usedAddresses.superPaymaster)(baseClient),
12
- ...paymasterActions(usedAddresses.paymasterV4)(baseClient),
13
- ...stakingActions(usedAddresses.gTokenStaking)(baseClient),
14
- ...sbtActions(usedAddresses.mySBT)(baseClient),
15
- ...dvtActions(ADDRESS_PLACEHOLDER)(baseClient),
16
- ...xPNTsFactoryActions(usedAddresses.xPNTsFactory || '0x')(baseClient),
17
- ...aggregatorActions(ADDRESS_PLACEHOLDER)(baseClient),
18
- };
19
- return Object.assign(baseClient, actions);
20
- }
@@ -1,40 +0,0 @@
1
- import { type Client, type Transport, type Chain, type Account, type Hex, type PublicActions, type WalletActions, type Address } from 'viem';
2
- import { type RegistryActions, type SBTActions } from '@aastar/core';
3
- export type CommunityClient = Client<Transport, Chain, Account | undefined> & PublicActions<Transport, Chain, Account | undefined> & WalletActions<Chain, Account | undefined> & RegistryActions & SBTActions & {
4
- /**
5
- * Query community registration status and token information
6
- * Returns null if not registered, otherwise returns community details
7
- */
8
- getCommunityInfo: (accountAddress: Address) => Promise<{
9
- hasRole: boolean;
10
- tokenAddress: Address | null;
11
- communityData: {
12
- name: string;
13
- ensName: string;
14
- website: string;
15
- description: string;
16
- } | null;
17
- }>;
18
- /**
19
- * High-level API to launch a community with automatic roleData generation
20
- */
21
- launch: (args: {
22
- name: string;
23
- tokenName: string;
24
- tokenSymbol: string;
25
- description?: string;
26
- logoURI?: string;
27
- website?: string;
28
- }) => Promise<{
29
- tokenAddress: Address;
30
- txs: Hex[];
31
- }>;
32
- };
33
- export declare function createCommunityClient({ chain, transport, account, addresses }: {
34
- chain: Chain;
35
- transport: Transport;
36
- account?: Account;
37
- addresses?: {
38
- [key: string]: Address;
39
- };
40
- }): CommunityClient;
@@ -1,300 +0,0 @@
1
- import { createClient, publicActions, walletActions, erc20Abi } from 'viem';
2
- import { registryActions, RegistryABI, sbtActions, CORE_ADDRESSES, TEST_TOKEN_ADDRESSES } from '@aastar/core';
3
- import { RoleDataFactory, RoleIds } from '../utils/roleData.js';
4
- export function createCommunityClient({ chain, transport, account, addresses }) {
5
- const client = createClient({
6
- chain,
7
- transport,
8
- account
9
- })
10
- .extend(publicActions)
11
- .extend(walletActions);
12
- const usedAddresses = { ...CORE_ADDRESSES, ...TEST_TOKEN_ADDRESSES, ...addresses };
13
- const registryActionsObj = registryActions(usedAddresses.registry)(client);
14
- const sbtActionsObj = sbtActions(usedAddresses.mySBT)(client);
15
- const launch = async (args) => {
16
- try {
17
- console.log(`🚀 Launching community: ${args.name}`);
18
- if (!account) {
19
- throw new Error('Account is required for launch()');
20
- }
21
- // Generate unique community name with timestamp
22
- const uniqueName = `${args.name}_${Date.now()}`;
23
- console.log(` 📝 Unique name: ${uniqueName}`);
24
- // Generate roleData using RoleDataFactory
25
- const roleData = RoleDataFactory.community({
26
- name: uniqueName,
27
- ensName: '',
28
- website: args.website || '',
29
- description: args.description || '',
30
- logoURI: args.logoURI || '',
31
- stakeAmount: 0n
32
- });
33
- console.log(` ✅ RoleData generated:`, roleData);
34
- console.log(` 📊 RoleData type:`, typeof roleData);
35
- console.log(` 📏 RoleData length:`, roleData?.length);
36
- // 1. Check if already has role
37
- const hasRole = await client.readContract({
38
- address: usedAddresses.registry,
39
- abi: RegistryABI,
40
- functionName: 'hasRole',
41
- args: [RoleIds.COMMUNITY, account.address]
42
- });
43
- let registerTx;
44
- if (hasRole) {
45
- console.log(` ℹ️ Account already has COMMUNITY role. Skipping registration.`);
46
- }
47
- else {
48
- // 2. Check GToken Allowance and Balance
49
- if (usedAddresses.gToken && usedAddresses.gTokenStaking) {
50
- console.log(` 💰 Checking GToken allowance...`);
51
- const balance = await client.readContract({
52
- address: usedAddresses.gToken,
53
- abi: erc20Abi,
54
- functionName: 'balanceOf',
55
- args: [account.address]
56
- });
57
- if (balance < 50000000000000000000n) { // 50 GT assumption, should ideally check minStake
58
- console.warn(` ⚠️ Warning: Low GToken balance (${balance}). Registration may fail if minStake > balance.`);
59
- }
60
- const allowance = await client.readContract({
61
- address: usedAddresses.gToken,
62
- abi: erc20Abi,
63
- functionName: 'allowance',
64
- args: [account.address, usedAddresses.gTokenStaking]
65
- });
66
- if (allowance < 50000000000000000000n) {
67
- console.log(` 🔓 Approving GToken for Staking...`);
68
- const approveTx = await client.writeContract({
69
- address: usedAddresses.gToken,
70
- abi: erc20Abi,
71
- functionName: 'approve',
72
- args: [usedAddresses.gTokenStaking, 115792089237316195423570985008687907853269984665640564039457584007913129639935n], // MaxUint256
73
- account: account
74
- });
75
- console.log(` ✅ Approved: ${approveTx}`);
76
- await client.waitForTransactionReceipt({ hash: approveTx });
77
- }
78
- }
79
- // Register community role
80
- console.log(` 📤 Registering community role...`);
81
- try {
82
- registerTx = await registryActionsObj.registerRole({
83
- roleId: RoleIds.COMMUNITY,
84
- user: account.address,
85
- data: roleData,
86
- account: account
87
- });
88
- console.log(` ✅ Community registered: ${registerTx}`);
89
- }
90
- catch (e) {
91
- // Check for RoleAlreadyGranted (just in case hasRole returned false but race condition or cache)
92
- const isRoleError = e.message?.includes('RoleAlreadyGranted') ||
93
- e.cause?.data?.errorName === 'RoleAlreadyGranted' ||
94
- e.name === 'RoleAlreadyGranted' ||
95
- e.name === 'RoleAlreadyGranted';
96
- if (isRoleError) {
97
- console.log(` ℹ️ Role already granted (caught in tx). Skipping.`);
98
- }
99
- else {
100
- throw e;
101
- }
102
- }
103
- }
104
- // Deploy xPNTs token if factory is available
105
- let tokenAddress = '0x0000000000000000000000000000000000000000';
106
- const txs = [];
107
- if (registerTx)
108
- txs.push(registerTx);
109
- if (usedAddresses.xPNTsFactory) {
110
- if (!client.account) {
111
- throw new Error("Client account is required for token deployment");
112
- }
113
- // ABI from xPNTsFactory.sol
114
- const factoryAbi = [
115
- {
116
- type: 'function',
117
- name: 'deployxPNTsToken',
118
- inputs: [
119
- { name: 'name', type: 'string' },
120
- { name: 'symbol', type: 'string' },
121
- { name: 'communityName', type: 'string' },
122
- { name: 'communityENS', type: 'string' },
123
- { name: 'exchangeRate', type: 'uint256' },
124
- { name: 'paymasterAOA', type: 'address' }
125
- ],
126
- outputs: [{ name: 'token', type: 'address' }],
127
- stateMutability: 'nonpayable'
128
- },
129
- {
130
- type: 'function',
131
- name: 'getTokenAddress',
132
- inputs: [{ name: 'community', type: 'address' }],
133
- outputs: [{ name: 'token', type: 'address' }],
134
- stateMutability: 'view'
135
- }
136
- ];
137
- // 1. Check if token already exists
138
- try {
139
- const existingToken = await client.readContract({
140
- address: usedAddresses.xPNTsFactory,
141
- abi: factoryAbi,
142
- functionName: 'getTokenAddress',
143
- args: [account.address]
144
- });
145
- if (existingToken && existingToken !== '0x0000000000000000000000000000000000000000') {
146
- console.log(` ℹ️ Found existing token at ${existingToken}`);
147
- tokenAddress = existingToken;
148
- // Return early or continue? Logic expects result.
149
- // If we found it, we don't need to deploy.
150
- return { tokenAddress, txs };
151
- }
152
- }
153
- catch (e) {
154
- console.warn(` ⚠️ Failed to check for existing token:`, e);
155
- }
156
- console.log(` 🏭 Deploying Token via Factory: ${usedAddresses.xPNTsFactory}`);
157
- try {
158
- // deployxPNTsToken(name, symbol, communityName, communityENS, exchangeRate, paymasterAOA)
159
- const { request } = await client.simulateContract({
160
- address: usedAddresses.xPNTsFactory,
161
- abi: factoryAbi,
162
- functionName: 'deployxPNTsToken',
163
- args: [
164
- args.tokenName,
165
- args.tokenSymbol,
166
- args.name, // communityName
167
- args.website || '', // communityENS (mapping website to ENS param for now)
168
- 1000000000000000000n, // exchangeRate 1e18 (1:1)
169
- '0x0000000000000000000000000000000000000000' // paymasterAOA (optional)
170
- ],
171
- account: client.account
172
- });
173
- const deployTx = await client.writeContract(request);
174
- console.log(` 📤 Deploy Token Tx: ${deployTx}`);
175
- txs.push(deployTx);
176
- const receipt = await client.waitForTransactionReceipt({ hash: deployTx });
177
- // After deployment, fetch the address again
178
- const newTokenAddress = await client.readContract({
179
- address: usedAddresses.xPNTsFactory,
180
- abi: factoryAbi,
181
- functionName: 'getTokenAddress',
182
- args: [account.address]
183
- });
184
- if (newTokenAddress) {
185
- tokenAddress = newTokenAddress;
186
- console.log(` 🪙 Token Deployed: ${tokenAddress}`);
187
- }
188
- }
189
- catch (deployError) {
190
- console.warn(' ⚠️ Failed to deploy token, but community registered:', deployError);
191
- }
192
- }
193
- return { tokenAddress, txs };
194
- }
195
- catch (error) {
196
- console.error('❌ Error in launch():', error);
197
- // 检查是否是 RoleAlreadyGranted 错误
198
- const errorMessage = error.message || '';
199
- const errorData = error.data?.errorName || '';
200
- const errorString = JSON.stringify(error);
201
- if (errorMessage.includes('RoleAlreadyGranted') ||
202
- errorData === 'RoleAlreadyGranted' ||
203
- errorString.includes('RoleAlreadyGranted')) {
204
- throw new Error(`Account ${account?.address || 'unknown'} already has COMMUNITY role. Please use a different account or exit the role first.`);
205
- }
206
- // 检查其他常见错误
207
- if (errorMessage.includes('InsufficientStake')) {
208
- throw new Error('Insufficient stake. Please ensure you have enough GToken staked.');
209
- }
210
- if (errorMessage.includes('RoleNotConfigured')) {
211
- throw new Error('COMMUNITY role is not configured in the Registry contract.');
212
- }
213
- // 重新抛出原始错误
214
- throw error;
215
- }
216
- };
217
- // State query method - check before operations
218
- const getCommunityInfo = async (accountAddress) => {
219
- try {
220
- // 1. Check if account has COMMUNITY role
221
- const hasRole = await client.readContract({
222
- address: usedAddresses.registry,
223
- abi: RegistryABI,
224
- functionName: 'hasRole',
225
- args: [RoleIds.COMMUNITY, accountAddress]
226
- });
227
- if (!hasRole) {
228
- return {
229
- hasRole: false,
230
- tokenAddress: null,
231
- communityData: null
232
- };
233
- }
234
- // 2. Get token address from factory
235
- const factoryAbi = [
236
- {
237
- inputs: [{ name: 'community', type: 'address' }],
238
- name: 'getTokenAddress',
239
- outputs: [{ name: '', type: 'address' }],
240
- stateMutability: 'view',
241
- type: 'function'
242
- }
243
- ];
244
- const tokenAddress = await client.readContract({
245
- address: usedAddresses.xPNTsFactory,
246
- abi: factoryAbi,
247
- functionName: 'getTokenAddress',
248
- args: [accountAddress]
249
- });
250
- // 3. Get community metadata from Registry
251
- const metadata = await client.readContract({
252
- address: usedAddresses.registry,
253
- abi: RegistryABI,
254
- functionName: 'roleMetadata',
255
- args: [RoleIds.COMMUNITY, accountAddress]
256
- });
257
- let communityData = {
258
- name: 'Community',
259
- ensName: '',
260
- website: '',
261
- description: '',
262
- logoURI: ''
263
- };
264
- if (metadata && metadata !== '0x') {
265
- try {
266
- // RoleMetadata is encoded as CommunityRoleData struct:
267
- // (string name, string ensName, string website, string description, string logoURI, uint256 stakeAmount)
268
- const decoded = RoleDataFactory.decodeCommunity(metadata);
269
- communityData = {
270
- name: decoded.name || 'Community',
271
- ensName: decoded.ensName || '',
272
- website: decoded.website || '',
273
- description: decoded.description || '',
274
- logoURI: decoded.logoURI || ''
275
- };
276
- }
277
- catch (e) {
278
- console.warn(' ⚠️ Failed to decode community metadata:', e);
279
- }
280
- }
281
- return {
282
- hasRole: true,
283
- tokenAddress: (tokenAddress && tokenAddress !== '0x0000000000000000000000000000000000000000') ? tokenAddress : null,
284
- communityData: (metadata && metadata !== '0x') ? communityData : null
285
- };
286
- }
287
- catch (error) {
288
- console.error('Error fetching community info:', error);
289
- return {
290
- hasRole: false,
291
- tokenAddress: null,
292
- communityData: null
293
- };
294
- }
295
- };
296
- return Object.assign(client, registryActionsObj, sbtActionsObj, {
297
- launch,
298
- getCommunityInfo
299
- });
300
- }