@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.
- package/LICENSE +21 -0
- package/__tests__/CommunityClient.test.ts +205 -0
- package/__tests__/UserClient.test.ts +294 -0
- package/__tests__/index.test.ts +16 -0
- package/__tests__/mocks/client.ts +22 -0
- package/coverage/CommunityClient.ts.html +790 -0
- package/coverage/UserClient.ts.html +1423 -0
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/coverage-final.json +3 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +131 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dist/CommunityClient.d.ts +65 -0
- package/dist/CommunityClient.js +188 -0
- package/dist/UserClient.d.ts +87 -0
- package/dist/UserClient.js +395 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/testAccountManager.d.ts +142 -0
- package/dist/testAccountManager.js +267 -0
- package/package.json +26 -0
- package/src/CommunityClient.ts +235 -0
- package/src/UserClient.ts +447 -0
- package/src/index.ts +2 -0
- package/src/testAccountManager.ts +374 -0
- package/tsconfig.json +10 -0
|
@@ -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
|
+
}
|