@sign-global/tokentable-core 1.4.0 → 1.5.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sign-global/tokentable-core",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -38,7 +38,9 @@
38
38
  "nanoid": "^5.0.9",
39
39
  "@mysten/dapp-kit": "^0.16.3",
40
40
  "@mysten/sui": "^1.29.1",
41
- "@mysten/wallet-standard": "^0.16.10"
41
+ "@mysten/wallet-standard": "^0.16.10",
42
+ "@aptos-labs/ts-sdk": "^4.0.0",
43
+ "@aptos-labs/wallet-adapter-react": "^7.0.4"
42
44
  },
43
45
  "publishConfig": {
44
46
  "access": "public"
@@ -13,6 +13,7 @@ import {
13
13
  arbitrum
14
14
  } from 'viem/chains';
15
15
  import {
16
+ aptosTestNet,
16
17
  mevmDevNet,
17
18
  signBrBTestnet,
18
19
  solanaDevNet,
@@ -113,6 +114,10 @@ export const ChainConfig = {
113
114
  [suiMainNet.id]: {
114
115
  contractAddress: '0x3f73ec78d3e8a99277496edb6183d6075490983c2a29542a1c3f709aa31169b5',
115
116
  rpcUrl: suiMainNet.rpcUrls.default.http[0]
117
+ },
118
+ [aptosTestNet.id]: {
119
+ contractAddress: '0x0ee860c2c1dc9e6d7c013cfc78cecfc226dfffa403b0ca212b38d958bc1048c9',
120
+ rpcUrl: aptosTestNet.rpcUrls.default.http[0]
116
121
  }
117
122
  };
118
123
 
@@ -89,10 +89,10 @@ export const solanaDevNet = {
89
89
  },
90
90
  rpcUrls: {
91
91
  public: {
92
- http: ['https://devnet.helius-rpc.com/?api-key=92a10901-e587-4f65-a180-4a63b7305966']
92
+ http: ['https://serene-empty-film.solana-devnet.quiknode.pro/7fcc62232b14dc8a6a154597ee028ebf00e0c195']
93
93
  },
94
94
  default: {
95
- http: ['https://devnet.helius-rpc.com/?api-key=92a10901-e587-4f65-a180-4a63b7305966']
95
+ http: ['https://serene-empty-film.solana-devnet.quiknode.pro/7fcc62232b14dc8a6a154597ee028ebf00e0c195']
96
96
  }
97
97
  },
98
98
  blockExplorers: {
@@ -115,10 +115,10 @@ export const solanaMainNet = {
115
115
  },
116
116
  rpcUrls: {
117
117
  public: {
118
- http: ['https://neat-falling-dream.solana-mainnet.quiknode.pro/55dbcc2244d010e047c4ab1e3b7964cc6204505d']
118
+ http: ['https://serene-empty-film.solana-mainnet.quiknode.pro/7fcc62232b14dc8a6a154597ee028ebf00e0c195']
119
119
  },
120
120
  default: {
121
- http: ['https://neat-falling-dream.solana-mainnet.quiknode.pro/55dbcc2244d010e047c4ab1e3b7964cc6204505d']
121
+ http: ['https://serene-empty-film.solana-mainnet.quiknode.pro/7fcc62232b14dc8a6a154597ee028ebf00e0c195']
122
122
  }
123
123
  },
124
124
  blockExplorers: {
@@ -203,3 +203,29 @@ export const suiMainNet = {
203
203
  },
204
204
  testnet: false
205
205
  };
206
+
207
+ export const aptosTestNet = {
208
+ id: 2,
209
+ name: 'Aptos Testnet',
210
+ network: 'Aptos Testnet',
211
+ nativeCurrency: {
212
+ decimals: 8,
213
+ name: 'Aptos',
214
+ symbol: 'APT'
215
+ },
216
+ rpcUrls: {
217
+ public: {
218
+ http: ['https://api.testnet.aptoslabs.com/v1']
219
+ },
220
+ default: {
221
+ http: ['https://api.testnet.aptoslabs.com/v1']
222
+ }
223
+ },
224
+ blockExplorers: {
225
+ default: {
226
+ name: 'aptos scan',
227
+ url: 'hhttps://explorer.aptoslabs.com/'
228
+ }
229
+ },
230
+ testnet: true
231
+ };
@@ -0,0 +1,55 @@
1
+ import { AptosAirdropContractClient } from './AptosAirdropClient';
2
+ import { AptosBaseDistributorContractClient } from './AptosBaseDistributorClient';
3
+ import { AptosContractInfo } from './AptosContractClient';
4
+
5
+ export class AirdropService {
6
+ options: Omit<AptosContractInfo, 'module'>;
7
+ constructor(options: Omit<AptosContractInfo, 'module'>) {
8
+ this.options = options;
9
+ }
10
+
11
+ private get airdropClient(): AptosAirdropContractClient {
12
+ if (!this.options) {
13
+ throw new Error('options is empty');
14
+ }
15
+
16
+ return new AptosAirdropContractClient(this.options);
17
+ }
18
+
19
+ private get baseClient(): AptosBaseDistributorContractClient {
20
+ if (!this.options) {
21
+ throw new Error('options is empty');
22
+ }
23
+ return new AptosBaseDistributorContractClient(this.options);
24
+ }
25
+
26
+ async isLeafUsed(leaf: string): Promise<boolean> {
27
+ return this.baseClient.isLeafUsed(leaf);
28
+ }
29
+
30
+ async batchFetchClaimed(leafs: string[]) {
31
+ return this.baseClient.batchFetchClaimed(leafs);
32
+ }
33
+
34
+ async claim({ proof, group, data, value }: { proof: string[]; group: string; data: string; value?: bigint }) {
35
+ return this.airdropClient.claim({
36
+ proof,
37
+ group,
38
+ data,
39
+ value
40
+ });
41
+ }
42
+
43
+ async getVersion() {
44
+ const res = await this.baseClient.getContractInfo();
45
+ return res.version;
46
+ }
47
+
48
+ async getClaimFee(contractAddress: string, amount: bigint) {
49
+ return this.baseClient.getClaimFee(contractAddress, amount);
50
+ }
51
+
52
+ async getPaused() {
53
+ return this.baseClient.getPaused();
54
+ }
55
+ }
@@ -0,0 +1,27 @@
1
+ import { AptosContractClientBase, AptosContractInfo } from './AptosContractClient';
2
+ import { getChainConfig } from '../../common';
3
+
4
+ export class AptosAirdropContractClient extends AptosContractClientBase {
5
+ airdropAddress: string;
6
+ constructor(options: Omit<AptosContractInfo, 'module'>) {
7
+ const chainConfig = getChainConfig(options.chainId as any);
8
+ super({
9
+ ...options,
10
+ address: chainConfig.contractAddress,
11
+ module: 'merkle_distributor_with_fees'
12
+ });
13
+ this.airdropAddress = options.address;
14
+ }
15
+
16
+ private hexToBytes(hexStr: string): number[] {
17
+ const hex = hexStr.startsWith('0x') ? hexStr.slice(2) : hexStr;
18
+ return Array.from(Buffer.from(hex, 'hex'));
19
+ }
20
+
21
+ async claim({ proof, group, data, value }: { proof: string[]; group: string; data: string; value?: bigint }) {
22
+ const dataBytes = this.hexToBytes(data);
23
+ const proofBytes = proof.map((p) => this.hexToBytes(p));
24
+
25
+ return await this.invokeContractWrite('claim', [this.airdropAddress, proofBytes, dataBytes]);
26
+ }
27
+ }
@@ -0,0 +1,81 @@
1
+ import { AptosContractClientBase, AptosContractInfo } from './AptosContractClient';
2
+ import { getChainConfig } from '../../common';
3
+
4
+ export class AptosBaseDistributorContractClient extends AptosContractClientBase {
5
+ airdropAddress: string;
6
+ constructor(options: Omit<AptosContractInfo, 'module'>) {
7
+ const chainConfig = getChainConfig(options.chainId as any);
8
+ super({
9
+ ...options,
10
+ address: chainConfig.contractAddress,
11
+ module: 'base_distributor'
12
+ });
13
+ this.airdropAddress = options.address;
14
+ }
15
+
16
+ async getContractInfo() {
17
+ const data = await this.invokeContractRead('get_distribution_info', [this.airdropAddress]);
18
+ console.log('data', data);
19
+ const [root, token, startTime, endTime, owner, version, paused] = data;
20
+ return {
21
+ root,
22
+ token,
23
+ startTime: Number(startTime),
24
+ endTime: Number(endTime),
25
+ owner,
26
+ version: version,
27
+ paused
28
+ };
29
+ }
30
+
31
+ async deposit({ amount, token }: { amount: bigint; token: string }): Promise<string> {
32
+ return await this.signTransaction({
33
+ functionName: `0x1::primary_fungible_store::transfer`,
34
+ functionArguments: [token, this.airdropAddress, amount],
35
+ typeArguments: ['0x1::fungible_asset::Metadata']
36
+ });
37
+ }
38
+
39
+ async isLeafUsed(leaf: string): Promise<boolean> {
40
+ const leafBytes = leaf.startsWith('0x')
41
+ ? Array.from(Buffer.from(leaf.slice(2), 'hex'))
42
+ : Array.from(Buffer.from(leaf, 'hex'));
43
+ const res = await this.invokeContractRead('is_leaf_used', [this.airdropAddress, leafBytes]);
44
+ console.log('res', res);
45
+ return res[0];
46
+ }
47
+
48
+ async batchFetchClaimed(leafs: string[]) {
49
+ const res = await Promise.all(
50
+ leafs.map(async (leaf) => {
51
+ return this.isLeafUsed(leaf);
52
+ })
53
+ );
54
+ return res.map((info) => ({
55
+ result: info || false,
56
+ status: 'success'
57
+ }));
58
+ }
59
+
60
+ private hexToBytes(hexStr: string): number[] {
61
+ const hex = hexStr.startsWith('0x') ? hexStr.slice(2) : hexStr;
62
+ return Array.from(Buffer.from(hex, 'hex'));
63
+ }
64
+
65
+ async claim({ proof, data }: { proof: string[]; group: string; data: string; value?: bigint; extraData?: string }) {
66
+ const groupBytes = this.hexToBytes('');
67
+ const dataBytes = this.hexToBytes(data);
68
+ const proofBytes = proof.map((p) => this.hexToBytes(p));
69
+
70
+ return await this.invokeContractWrite('claim', [this.airdropAddress, proofBytes, groupBytes, dataBytes]);
71
+ }
72
+
73
+ async getPaused() {
74
+ const res = await this.getContractInfo();
75
+ return res.paused;
76
+ }
77
+
78
+ async getClaimFee(contractAddress: string, amount: bigint) {
79
+ return 0;
80
+ }
81
+ }
@@ -0,0 +1,109 @@
1
+ import { Aptos, AptosConfig, Network } from '@aptos-labs/ts-sdk';
2
+ import { useWallet } from '@aptos-labs/wallet-adapter-react';
3
+
4
+ export type AptosContractInfo = {
5
+ address: string;
6
+ chainId: string;
7
+ account?: ReturnType<typeof useWallet>;
8
+ module: string;
9
+ chainRpc: string;
10
+ };
11
+
12
+ export class AptosContractClientBase {
13
+ protected address: string;
14
+ protected chainId: string;
15
+ protected wallet?: ReturnType<typeof useWallet>;
16
+ protected client: Aptos;
17
+ protected module: string;
18
+
19
+ constructor(contractInfo: AptosContractInfo) {
20
+ this.address = contractInfo.address;
21
+ this.chainId = contractInfo.chainId;
22
+ this.wallet = contractInfo.account;
23
+ this.module = contractInfo.module;
24
+ this.client = this.initClient(contractInfo.chainRpc);
25
+ }
26
+
27
+ private initClient(chainRpc: string): Aptos {
28
+ const chainIdMap = {
29
+ '2': Network.TESTNET,
30
+ '1': Network.MAINNET
31
+ };
32
+ const config = new AptosConfig({
33
+ network: chainIdMap[this.chainId as keyof typeof chainIdMap],
34
+ fullnode: chainRpc
35
+ });
36
+
37
+ return new Aptos(config);
38
+ }
39
+
40
+ protected async invokeContractRead(method: string, args: any[]): Promise<any> {
41
+ try {
42
+ const viewPayload = {
43
+ function: `${this.address}::${this.module}::${method}` as `${string}::${string}::${string}`,
44
+ functionArguments: args
45
+ };
46
+
47
+ return await this.client.view({ payload: viewPayload });
48
+ } catch (error) {
49
+ console.error(`Error invoking read method ${method}:`, error);
50
+ throw error;
51
+ }
52
+ }
53
+
54
+ protected async invokeContractWrite(method: string, args: any[]): Promise<string> {
55
+ if (!this.wallet) {
56
+ throw new Error('Account not connected');
57
+ }
58
+
59
+ try {
60
+ const response = await this.wallet.signAndSubmitTransaction({
61
+ sender: this.wallet.account?.address,
62
+ data: {
63
+ function: `${this.address}::${this.module}::${method}`,
64
+ functionArguments: args
65
+ }
66
+ });
67
+ await this.client.waitForTransaction({
68
+ transactionHash: response.hash
69
+ });
70
+ return response.hash;
71
+ } catch (error) {
72
+ console.error(`Error invoking write method ${method}:`, error);
73
+
74
+ throw error;
75
+ }
76
+ }
77
+
78
+ async signTransaction({
79
+ functionName,
80
+ functionArguments,
81
+ typeArguments
82
+ }: {
83
+ functionName: `${string}::${string}::${string}`;
84
+ functionArguments: any[];
85
+ typeArguments?: string[];
86
+ }) {
87
+ if (!this.wallet) {
88
+ throw new Error('Account not connected');
89
+ }
90
+
91
+ try {
92
+ const response = await this.wallet.signAndSubmitTransaction({
93
+ sender: this.wallet.account?.address,
94
+ data: {
95
+ function: functionName,
96
+ functionArguments: functionArguments,
97
+ typeArguments: typeArguments || []
98
+ }
99
+ });
100
+ const res = await this.client.waitForTransaction({
101
+ transactionHash: response.hash
102
+ });
103
+
104
+ return response.hash;
105
+ } catch (error) {
106
+ throw error;
107
+ }
108
+ }
109
+ }
@@ -0,0 +1,223 @@
1
+ export const FEE_COLLECTOR_ABI = {
2
+ "address": "0x90f5a927d597d49b4fb64a48f3dc34695687e389136b04c42f9b9e7fe7fe59a0",
3
+ "name": "fee_collector",
4
+ "friends": [],
5
+ "exposed_functions": [
6
+ {
7
+ "name": "version",
8
+ "visibility": "public",
9
+ "is_entry": false,
10
+ "is_view": true,
11
+ "generic_type_params": [],
12
+ "params": [],
13
+ "return": [
14
+ "0x1::string::String"
15
+ ]
16
+ },
17
+ {
18
+ "name": "get_fee",
19
+ "visibility": "public",
20
+ "is_entry": false,
21
+ "is_view": true,
22
+ "generic_type_params": [],
23
+ "params": [
24
+ "address"
25
+ ],
26
+ "return": [
27
+ "u64"
28
+ ]
29
+ },
30
+ {
31
+ "name": "get_fee_token",
32
+ "visibility": "public",
33
+ "is_entry": false,
34
+ "is_view": true,
35
+ "generic_type_params": [],
36
+ "params": [
37
+ "address"
38
+ ],
39
+ "return": [
40
+ "address"
41
+ ]
42
+ },
43
+ {
44
+ "name": "set_custom_fee_fixed",
45
+ "visibility": "public",
46
+ "is_entry": true,
47
+ "is_view": false,
48
+ "generic_type_params": [],
49
+ "params": [
50
+ "&signer",
51
+ "address",
52
+ "u64"
53
+ ],
54
+ "return": []
55
+ },
56
+ {
57
+ "name": "set_custom_fee_token",
58
+ "visibility": "public",
59
+ "is_entry": true,
60
+ "is_view": false,
61
+ "generic_type_params": [],
62
+ "params": [
63
+ "&signer",
64
+ "address",
65
+ "address"
66
+ ],
67
+ "return": []
68
+ },
69
+ {
70
+ "name": "set_default_fee",
71
+ "visibility": "public",
72
+ "is_entry": true,
73
+ "is_view": false,
74
+ "generic_type_params": [],
75
+ "params": [
76
+ "&signer",
77
+ "u64"
78
+ ],
79
+ "return": []
80
+ },
81
+ {
82
+ "name": "set_default_fee_token",
83
+ "visibility": "public",
84
+ "is_entry": true,
85
+ "is_view": false,
86
+ "generic_type_params": [],
87
+ "params": [
88
+ "&signer",
89
+ "address"
90
+ ],
91
+ "return": []
92
+ },
93
+ {
94
+ "name": "withdraw_fee",
95
+ "visibility": "public",
96
+ "is_entry": true,
97
+ "is_view": false,
98
+ "generic_type_params": [],
99
+ "params": [
100
+ "&signer",
101
+ "0x1::object::Object<0x1::fungible_asset::Metadata>",
102
+ "u64"
103
+ ],
104
+ "return": []
105
+ }
106
+ ],
107
+ "structs": [
108
+ {
109
+ "name": "CustomFeeSetFixed",
110
+ "is_native": false,
111
+ "is_event": true,
112
+ "abilities": [
113
+ "drop",
114
+ "store"
115
+ ],
116
+ "generic_type_params": [],
117
+ "fields": [
118
+ {
119
+ "name": "distributor_address",
120
+ "type": "address"
121
+ },
122
+ {
123
+ "name": "fixed_fee",
124
+ "type": "u64"
125
+ }
126
+ ]
127
+ },
128
+ {
129
+ "name": "CustomFeeSetToken",
130
+ "is_native": false,
131
+ "is_event": true,
132
+ "abilities": [
133
+ "drop",
134
+ "store"
135
+ ],
136
+ "generic_type_params": [],
137
+ "fields": [
138
+ {
139
+ "name": "distributor_address",
140
+ "type": "address"
141
+ },
142
+ {
143
+ "name": "token_address",
144
+ "type": "address"
145
+ }
146
+ ]
147
+ },
148
+ {
149
+ "name": "DefaultFeeSet",
150
+ "is_native": false,
151
+ "is_event": true,
152
+ "abilities": [
153
+ "drop",
154
+ "store"
155
+ ],
156
+ "generic_type_params": [],
157
+ "fields": [
158
+ {
159
+ "name": "fee",
160
+ "type": "u64"
161
+ }
162
+ ]
163
+ },
164
+ {
165
+ "name": "DefaultFeeTokenSet",
166
+ "is_native": false,
167
+ "is_event": true,
168
+ "abilities": [
169
+ "drop",
170
+ "store"
171
+ ],
172
+ "generic_type_params": [],
173
+ "fields": [
174
+ {
175
+ "name": "token_address",
176
+ "type": "address"
177
+ }
178
+ ]
179
+ },
180
+ {
181
+ "name": "FeeCollectorData",
182
+ "is_native": false,
183
+ "is_event": false,
184
+ "abilities": [
185
+ "key"
186
+ ],
187
+ "generic_type_params": [],
188
+ "fields": [
189
+ {
190
+ "name": "default_fee",
191
+ "type": "u64"
192
+ },
193
+ {
194
+ "name": "default_fee_token",
195
+ "type": "address"
196
+ },
197
+ {
198
+ "name": "custom_fee_tokens",
199
+ "type": "0x1::table::Table<address, address>"
200
+ },
201
+ {
202
+ "name": "custom_fees_fixed",
203
+ "type": "0x1::table::Table<address, u64>"
204
+ }
205
+ ]
206
+ },
207
+ {
208
+ "name": "ModuleData",
209
+ "is_native": false,
210
+ "is_event": false,
211
+ "abilities": [
212
+ "key"
213
+ ],
214
+ "generic_type_params": [],
215
+ "fields": [
216
+ {
217
+ "name": "signer_cap",
218
+ "type": "0x1::account::SignerCapability"
219
+ }
220
+ ]
221
+ }
222
+ ]
223
+ } as const
@@ -0,0 +1,18 @@
1
+ // 统一导出所有ABI模块
2
+ export { OWNABLE_ABI } from './ownable';
3
+ export { MD_CREATE2_ABI } from './md_create2';
4
+ export { FEE_COLLECTOR_ABI } from './fee_collector';
5
+ export { MERKLE_VERIFIER_ABI } from './merkle_verifier';
6
+ export { MERKLE_DISTRIBUTOR_ABI } from './merkle_distributor';
7
+
8
+ // 合约地址常量
9
+ export const CONTRACT_ADDRESS = '0x90f5a927d597d49b4fb64a48f3dc34695687e389136b04c42f9b9e7fe7fe59a0';
10
+
11
+ // 模块名称映射
12
+ export const MODULE_NAMES = {
13
+ OWNABLE: 'ownable',
14
+ MD_CREATE2: 'md_create2',
15
+ FEE_COLLECTOR: 'fee_collector',
16
+ MERKLE_VERIFIER: 'merkle_verifier',
17
+ MERKLE_DISTRIBUTOR: 'merkle_distributor'
18
+ } as const;