@aastar/enduser 0.16.11

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.
@@ -0,0 +1,210 @@
1
+ /* eslint-disable */
2
+ var addSorting = (function() {
3
+ 'use strict';
4
+ var cols,
5
+ currentSort = {
6
+ index: 0,
7
+ desc: false
8
+ };
9
+
10
+ // returns the summary table element
11
+ function getTable() {
12
+ return document.querySelector('.coverage-summary');
13
+ }
14
+ // returns the thead element of the summary table
15
+ function getTableHeader() {
16
+ return getTable().querySelector('thead tr');
17
+ }
18
+ // returns the tbody element of the summary table
19
+ function getTableBody() {
20
+ return getTable().querySelector('tbody');
21
+ }
22
+ // returns the th element for nth column
23
+ function getNthColumn(n) {
24
+ return getTableHeader().querySelectorAll('th')[n];
25
+ }
26
+
27
+ function onFilterInput() {
28
+ const searchValue = document.getElementById('fileSearch').value;
29
+ const rows = document.getElementsByTagName('tbody')[0].children;
30
+
31
+ // Try to create a RegExp from the searchValue. If it fails (invalid regex),
32
+ // it will be treated as a plain text search
33
+ let searchRegex;
34
+ try {
35
+ searchRegex = new RegExp(searchValue, 'i'); // 'i' for case-insensitive
36
+ } catch (error) {
37
+ searchRegex = null;
38
+ }
39
+
40
+ for (let i = 0; i < rows.length; i++) {
41
+ const row = rows[i];
42
+ let isMatch = false;
43
+
44
+ if (searchRegex) {
45
+ // If a valid regex was created, use it for matching
46
+ isMatch = searchRegex.test(row.textContent);
47
+ } else {
48
+ // Otherwise, fall back to the original plain text search
49
+ isMatch = row.textContent
50
+ .toLowerCase()
51
+ .includes(searchValue.toLowerCase());
52
+ }
53
+
54
+ row.style.display = isMatch ? '' : 'none';
55
+ }
56
+ }
57
+
58
+ // loads the search box
59
+ function addSearchBox() {
60
+ var template = document.getElementById('filterTemplate');
61
+ var templateClone = template.content.cloneNode(true);
62
+ templateClone.getElementById('fileSearch').oninput = onFilterInput;
63
+ template.parentElement.appendChild(templateClone);
64
+ }
65
+
66
+ // loads all columns
67
+ function loadColumns() {
68
+ var colNodes = getTableHeader().querySelectorAll('th'),
69
+ colNode,
70
+ cols = [],
71
+ col,
72
+ i;
73
+
74
+ for (i = 0; i < colNodes.length; i += 1) {
75
+ colNode = colNodes[i];
76
+ col = {
77
+ key: colNode.getAttribute('data-col'),
78
+ sortable: !colNode.getAttribute('data-nosort'),
79
+ type: colNode.getAttribute('data-type') || 'string'
80
+ };
81
+ cols.push(col);
82
+ if (col.sortable) {
83
+ col.defaultDescSort = col.type === 'number';
84
+ colNode.innerHTML =
85
+ colNode.innerHTML + '<span class="sorter"></span>';
86
+ }
87
+ }
88
+ return cols;
89
+ }
90
+ // attaches a data attribute to every tr element with an object
91
+ // of data values keyed by column name
92
+ function loadRowData(tableRow) {
93
+ var tableCols = tableRow.querySelectorAll('td'),
94
+ colNode,
95
+ col,
96
+ data = {},
97
+ i,
98
+ val;
99
+ for (i = 0; i < tableCols.length; i += 1) {
100
+ colNode = tableCols[i];
101
+ col = cols[i];
102
+ val = colNode.getAttribute('data-value');
103
+ if (col.type === 'number') {
104
+ val = Number(val);
105
+ }
106
+ data[col.key] = val;
107
+ }
108
+ return data;
109
+ }
110
+ // loads all row data
111
+ function loadData() {
112
+ var rows = getTableBody().querySelectorAll('tr'),
113
+ i;
114
+
115
+ for (i = 0; i < rows.length; i += 1) {
116
+ rows[i].data = loadRowData(rows[i]);
117
+ }
118
+ }
119
+ // sorts the table using the data for the ith column
120
+ function sortByIndex(index, desc) {
121
+ var key = cols[index].key,
122
+ sorter = function(a, b) {
123
+ a = a.data[key];
124
+ b = b.data[key];
125
+ return a < b ? -1 : a > b ? 1 : 0;
126
+ },
127
+ finalSorter = sorter,
128
+ tableBody = document.querySelector('.coverage-summary tbody'),
129
+ rowNodes = tableBody.querySelectorAll('tr'),
130
+ rows = [],
131
+ i;
132
+
133
+ if (desc) {
134
+ finalSorter = function(a, b) {
135
+ return -1 * sorter(a, b);
136
+ };
137
+ }
138
+
139
+ for (i = 0; i < rowNodes.length; i += 1) {
140
+ rows.push(rowNodes[i]);
141
+ tableBody.removeChild(rowNodes[i]);
142
+ }
143
+
144
+ rows.sort(finalSorter);
145
+
146
+ for (i = 0; i < rows.length; i += 1) {
147
+ tableBody.appendChild(rows[i]);
148
+ }
149
+ }
150
+ // removes sort indicators for current column being sorted
151
+ function removeSortIndicators() {
152
+ var col = getNthColumn(currentSort.index),
153
+ cls = col.className;
154
+
155
+ cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, '');
156
+ col.className = cls;
157
+ }
158
+ // adds sort indicators for current column being sorted
159
+ function addSortIndicators() {
160
+ getNthColumn(currentSort.index).className += currentSort.desc
161
+ ? ' sorted-desc'
162
+ : ' sorted';
163
+ }
164
+ // adds event listeners for all sorter widgets
165
+ function enableUI() {
166
+ var i,
167
+ el,
168
+ ithSorter = function ithSorter(i) {
169
+ var col = cols[i];
170
+
171
+ return function() {
172
+ var desc = col.defaultDescSort;
173
+
174
+ if (currentSort.index === i) {
175
+ desc = !currentSort.desc;
176
+ }
177
+ sortByIndex(i, desc);
178
+ removeSortIndicators();
179
+ currentSort.index = i;
180
+ currentSort.desc = desc;
181
+ addSortIndicators();
182
+ };
183
+ };
184
+ for (i = 0; i < cols.length; i += 1) {
185
+ if (cols[i].sortable) {
186
+ // add the click event handler on the th so users
187
+ // dont have to click on those tiny arrows
188
+ el = getNthColumn(i).querySelector('.sorter').parentElement;
189
+ if (el.addEventListener) {
190
+ el.addEventListener('click', ithSorter(i));
191
+ } else {
192
+ el.attachEvent('onclick', ithSorter(i));
193
+ }
194
+ }
195
+ }
196
+ }
197
+ // adds sorting functionality to the UI
198
+ return function() {
199
+ if (!getTable()) {
200
+ return;
201
+ }
202
+ cols = loadColumns();
203
+ loadData();
204
+ addSearchBox();
205
+ addSortIndicators();
206
+ enableUI();
207
+ };
208
+ })();
209
+
210
+ window.addEventListener('load', addSorting);
@@ -0,0 +1,65 @@
1
+ import { type Address, type Hash } from 'viem';
2
+ import { BaseClient, type ClientConfig, type TransactionOptions } from '@aastar/core';
3
+ export interface CommunityClientConfig extends ClientConfig {
4
+ sbtAddress?: Address;
5
+ factoryAddress?: Address;
6
+ reputationAddress?: Address;
7
+ }
8
+ export interface CreateCommunityParams {
9
+ name: string;
10
+ tokenSymbol: string;
11
+ ensName?: string;
12
+ description?: string;
13
+ }
14
+ export interface CommunityInfo {
15
+ address: Address;
16
+ }
17
+ /**
18
+ * Client for Community Managers (`ROLE_COMMUNITY`)
19
+ */
20
+ export declare class CommunityClient extends BaseClient {
21
+ sbtAddress?: Address;
22
+ factoryAddress?: Address;
23
+ reputationAddress?: Address;
24
+ constructor(config: CommunityClientConfig);
25
+ /**
26
+ * Create a new Community Token (xPNTs) and register it.
27
+ * Note: In the current architecture, creating a community often involves:
28
+ * 1. Registering the ROLE_COMMUNITY on Registry (if not exists) -> usually manual or self-register
29
+ * 2. Deploying a Token (xPNTs) via Factory
30
+ * 3. Linking the Token to the Community in Registry
31
+ */
32
+ createCommunityToken(params: CreateCommunityParams, options?: TransactionOptions): Promise<Hash>;
33
+ /**
34
+ * Register self as a Community Manager.
35
+ * This method handles all necessary steps:
36
+ * 1. Checks and approves GToken to GTokenStaking
37
+ * 2. Encodes CommunityRoleData with provided parameters
38
+ * 3. Calls registerRoleSelf on Registry
39
+ *
40
+ * @param params Community registration parameters
41
+ * @param options Transaction options
42
+ * @returns Transaction hash
43
+ */
44
+ registerAsCommunity(params: {
45
+ name: string;
46
+ ensName?: string;
47
+ website?: string;
48
+ description?: string;
49
+ logoURI?: string;
50
+ stakeAmount?: bigint;
51
+ }, options?: TransactionOptions): Promise<Hash>;
52
+ /**
53
+ * Airdrop SBTs to users to make them members
54
+ */
55
+ airdropSBT(users: Address[], roleId: bigint, options?: TransactionOptions): Promise<Hash>;
56
+ setReputationRule(ruleId: bigint, ruleConfig: any, options?: TransactionOptions): Promise<Hash>;
57
+ /**
58
+ * Revoke membership (Burn SBT)
59
+ */
60
+ revokeMembership(userAddr: Address, options?: TransactionOptions): Promise<Hash>;
61
+ /**
62
+ * Transfer ownership of the Community Token
63
+ */
64
+ transferCommunityTokenOwnership(tokenAddress: Address, newOwner: Address, options?: TransactionOptions): Promise<Hash>;
65
+ }
@@ -0,0 +1,188 @@
1
+ import { parseEther, encodeAbiParameters, parseAbiParameters } from 'viem';
2
+ import { BaseClient } from '@aastar/core';
3
+ import { registryActions, sbtActions, xPNTsFactoryActions, reputationActions, tokenActions } from '@aastar/core';
4
+ /**
5
+ * Client for Community Managers (`ROLE_COMMUNITY`)
6
+ */
7
+ export class CommunityClient extends BaseClient {
8
+ sbtAddress;
9
+ factoryAddress;
10
+ reputationAddress;
11
+ constructor(config) {
12
+ super(config);
13
+ this.sbtAddress = config.sbtAddress;
14
+ this.factoryAddress = config.factoryAddress;
15
+ this.reputationAddress = config.reputationAddress;
16
+ }
17
+ // ========================================
18
+ // 1. 社区创建与配置
19
+ // ========================================
20
+ /**
21
+ * Create a new Community Token (xPNTs) and register it.
22
+ * Note: In the current architecture, creating a community often involves:
23
+ * 1. Registering the ROLE_COMMUNITY on Registry (if not exists) -> usually manual or self-register
24
+ * 2. Deploying a Token (xPNTs) via Factory
25
+ * 3. Linking the Token to the Community in Registry
26
+ */
27
+ async createCommunityToken(params, options) {
28
+ try {
29
+ if (!this.factoryAddress) {
30
+ throw new Error('Factory address required for this client');
31
+ }
32
+ const factory = xPNTsFactoryActions(this.factoryAddress);
33
+ // 1. Deploy Token
34
+ // Note: The address calculation should be handled via event parsing or predictive deployment
35
+ // For now, returning the transaction hash as per L1 pattern
36
+ return await factory(this.client).createToken({
37
+ name: params.name,
38
+ symbol: params.tokenSymbol,
39
+ community: '0x0000000000000000000000000000000000000000', // Default empty community mapping
40
+ account: options?.account
41
+ });
42
+ }
43
+ catch (error) {
44
+ // Error is likely already an AAStarError from L1, but we wrap it for context
45
+ throw error;
46
+ }
47
+ }
48
+ /**
49
+ * Register self as a Community Manager.
50
+ * This method handles all necessary steps:
51
+ * 1. Checks and approves GToken to GTokenStaking
52
+ * 2. Encodes CommunityRoleData with provided parameters
53
+ * 3. Calls registerRoleSelf on Registry
54
+ *
55
+ * @param params Community registration parameters
56
+ * @param options Transaction options
57
+ * @returns Transaction hash
58
+ */
59
+ async registerAsCommunity(params, options) {
60
+ try {
61
+ const registryAddr = this.requireRegistry();
62
+ const registry = registryActions(registryAddr);
63
+ const gTokenStakingAddr = this.requireGTokenStaking();
64
+ const gTokenAddr = this.requireGToken();
65
+ // 1. Get ROLE_COMMUNITY
66
+ const roleCommunity = await registry(this.getStartPublicClient()).ROLE_COMMUNITY();
67
+ // 2. Prepare stake amount (default 30 GToken as per Registry config)
68
+ const stakeAmount = params.stakeAmount || parseEther('30');
69
+ // 3. Check and approve GToken to GTokenStaking if needed
70
+ const gToken = tokenActions();
71
+ const allowance = await gToken(this.getStartPublicClient()).allowance({
72
+ token: gTokenAddr,
73
+ owner: this.getAddress(),
74
+ spender: gTokenStakingAddr
75
+ });
76
+ if (allowance < stakeAmount) {
77
+ const approveHash = await gToken(this.client).approve({
78
+ token: gTokenAddr,
79
+ spender: gTokenStakingAddr,
80
+ amount: stakeAmount * BigInt(2), // Approve 2x for future use
81
+ account: options?.account
82
+ });
83
+ await this.getStartPublicClient().waitForTransactionReceipt({ hash: approveHash });
84
+ }
85
+ // 4. Encode CommunityRoleData
86
+ // struct CommunityRoleData { string name; string ensName; string website; string description; string logoURI; uint256 stakeAmount; }
87
+ const communityData = encodeAbiParameters(parseAbiParameters('string, string, string, string, string, uint256'), [
88
+ params.name,
89
+ params.ensName || '',
90
+ params.website || '',
91
+ params.description || `${params.name} Community`,
92
+ params.logoURI || '',
93
+ stakeAmount
94
+ ]);
95
+ // 5. Register role
96
+ return await registry(this.client).registerRoleSelf({
97
+ roleId: roleCommunity,
98
+ data: communityData,
99
+ account: options?.account
100
+ });
101
+ }
102
+ catch (error) {
103
+ throw error;
104
+ }
105
+ }
106
+ // ========================================
107
+ // 2. 成员管理
108
+ // ========================================
109
+ /**
110
+ * Airdrop SBTs to users to make them members
111
+ */
112
+ async airdropSBT(users, roleId, options) {
113
+ try {
114
+ if (!this.sbtAddress)
115
+ throw new Error('SBT address required for this client');
116
+ const sbt = sbtActions(this.sbtAddress);
117
+ if (users.length === 1) {
118
+ // Convert roleId to Hex (bytes32)
119
+ const roleIdHex = `0x${roleId.toString(16).padStart(64, '0')}`;
120
+ return await sbt(this.client).mintForRole({
121
+ user: users[0],
122
+ roleId: roleIdHex,
123
+ roleData: '0x',
124
+ account: options?.account
125
+ });
126
+ }
127
+ throw new Error('Batch airdrop not fully implemented in L1 yet, use single user');
128
+ }
129
+ catch (error) {
130
+ throw error;
131
+ }
132
+ }
133
+ // ========================================
134
+ // 3. 信誉系统
135
+ // ========================================
136
+ async setReputationRule(ruleId, ruleConfig, options) {
137
+ try {
138
+ if (!this.reputationAddress)
139
+ throw new Error('Reputation address required for this client');
140
+ const reputation = reputationActions(this.reputationAddress);
141
+ const ruleIdHex = `0x${ruleId.toString(16).padStart(64, '0')}`;
142
+ return await reputation(this.client).setReputationRule({
143
+ ruleId: ruleIdHex,
144
+ rule: ruleConfig,
145
+ account: options?.account
146
+ });
147
+ }
148
+ catch (error) {
149
+ throw error;
150
+ }
151
+ }
152
+ // ========================================
153
+ // 4. 管理功能
154
+ // ========================================
155
+ /**
156
+ * Revoke membership (Burn SBT)
157
+ */
158
+ async revokeMembership(userAddr, options) {
159
+ try {
160
+ if (!this.sbtAddress)
161
+ throw new Error('SBT address required for this client');
162
+ const sbt = sbtActions(this.sbtAddress);
163
+ return await sbt(this.client).burnSBT({
164
+ user: userAddr,
165
+ account: options?.account
166
+ });
167
+ }
168
+ catch (error) {
169
+ throw error;
170
+ }
171
+ }
172
+ /**
173
+ * Transfer ownership of the Community Token
174
+ */
175
+ async transferCommunityTokenOwnership(tokenAddress, newOwner, options) {
176
+ try {
177
+ const token = tokenActions()(this.client);
178
+ return await token.transferOwnership({
179
+ token: tokenAddress,
180
+ newOwner,
181
+ account: options?.account
182
+ });
183
+ }
184
+ catch (error) {
185
+ throw error;
186
+ }
187
+ }
188
+ }
@@ -0,0 +1,87 @@
1
+ import { type Address, type Hash, type Hex } from 'viem';
2
+ import { BaseClient, type ClientConfig, type TransactionOptions } from '@aastar/core';
3
+ export interface UserClientConfig extends ClientConfig {
4
+ accountAddress: Address;
5
+ sbtAddress?: Address;
6
+ entryPointAddress?: Address;
7
+ superPaymasterAddress?: Address;
8
+ gTokenStakingAddress?: Address;
9
+ registryAddress?: Address;
10
+ gTokenAddress?: Address;
11
+ }
12
+ export declare class UserClient extends BaseClient {
13
+ accountAddress: Address;
14
+ sbtAddress?: Address;
15
+ entryPointAddress?: Address;
16
+ gTokenStakingAddress?: Address;
17
+ registryAddress?: Address;
18
+ gTokenAddress?: Address;
19
+ constructor(config: UserClientConfig);
20
+ /**
21
+ * Get the nonce of the account from EntryPoint (more reliable for 4337)
22
+ */
23
+ getNonce(key?: bigint): Promise<bigint>;
24
+ /**
25
+ * Get the owner of the AA account
26
+ */
27
+ getOwner(): Promise<Address>;
28
+ /**
29
+ * Execute a transaction from the AA account
30
+ */
31
+ execute(target: Address, value: bigint, data: Hex, options?: TransactionOptions): Promise<Hash>;
32
+ /**
33
+ * Execute a batch of transactions
34
+ */
35
+ executeBatch(targets: Address[], values: bigint[], datas: Hex[], options?: TransactionOptions): Promise<Hash>;
36
+ /**
37
+ * Get user's SBT balance
38
+ */
39
+ getSBTBalance(): Promise<bigint>;
40
+ /**
41
+ * Self-mint SBT for a role (user self-service)
42
+ */
43
+ mintSBT(roleId: Hex, options?: TransactionOptions): Promise<Hash>;
44
+ /**
45
+ * Transfer GToken or any ERC20
46
+ */
47
+ transferToken(token: Address, to: Address, amount: bigint, options?: TransactionOptions): Promise<Hash>;
48
+ /**
49
+ * Get Token Balance
50
+ */
51
+ getTokenBalance(token: Address): Promise<bigint>;
52
+ /**
53
+ * Delegate stake to a role (Delegate to an operator/community)
54
+ */
55
+ stakeForRole(roleId: Hex, amount: bigint, options?: TransactionOptions): Promise<Hash>;
56
+ /**
57
+ * Unstake from a role
58
+ */
59
+ unstakeFromRole(roleId: Hex, options?: TransactionOptions): Promise<Hash>;
60
+ /**
61
+ * Get staked balance for a specific role
62
+ */
63
+ getStakedBalance(roleId: Hex): Promise<bigint>;
64
+ /**
65
+ * Exit a specific role (Cleanup registry status)
66
+ */
67
+ exitRole(roleId: Hex, options?: TransactionOptions): Promise<Hash>;
68
+ /**
69
+ * Leave a community (Burn SBT and clean up)
70
+ */
71
+ leaveCommunity(community: Address, options?: TransactionOptions): Promise<Hash>;
72
+ /**
73
+ * Register as EndUser (One-click: Approve + Register)
74
+ * Handles GToken approval to Staking contract and Role registration.
75
+ */
76
+ registerAsEndUser(communityAddress: Address, stakeAmount: bigint, options?: TransactionOptions): Promise<Hash>;
77
+ /**
78
+ * Execute a transaction with Gasless Sponsorship
79
+ */
80
+ executeGasless(params: {
81
+ target: Address;
82
+ value: bigint;
83
+ data: Hex;
84
+ paymaster: Address;
85
+ paymasterType: 'V4' | 'Super';
86
+ }, options?: TransactionOptions): Promise<Hash>;
87
+ }