@sign-global/tokentable 0.0.5 → 0.0.7

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 (54) hide show
  1. package/dist/cjs/airdrop/index.d.ts +10 -12
  2. package/dist/cjs/airdrop/index.js +118 -110
  3. package/dist/cjs/airdrop/index.js.map +1 -1
  4. package/dist/cjs/airdrop/services/index.d.ts +6 -1
  5. package/dist/cjs/airdrop/services/index.js +6 -1
  6. package/dist/cjs/airdrop/services/index.js.map +1 -1
  7. package/dist/cjs/airdrop/strategies/AirdropStrategyFactory.d.ts +13 -0
  8. package/dist/cjs/airdrop/strategies/AirdropStrategyFactory.js +22 -0
  9. package/dist/cjs/airdrop/strategies/AirdropStrategyFactory.js.map +1 -0
  10. package/dist/cjs/airdrop/strategies/EvmAirdropStrategy.d.ts +26 -0
  11. package/dist/cjs/airdrop/strategies/EvmAirdropStrategy.js +79 -0
  12. package/dist/cjs/airdrop/strategies/EvmAirdropStrategy.js.map +1 -0
  13. package/dist/cjs/airdrop/strategies/IAirdropStrategy.d.ts +27 -0
  14. package/dist/cjs/airdrop/strategies/IAirdropStrategy.js +3 -0
  15. package/dist/cjs/airdrop/strategies/IAirdropStrategy.js.map +1 -0
  16. package/dist/cjs/airdrop/strategies/StrategyCache.d.ts +10 -0
  17. package/dist/cjs/airdrop/strategies/StrategyCache.js +32 -0
  18. package/dist/cjs/airdrop/strategies/StrategyCache.js.map +1 -0
  19. package/dist/cjs/airdrop/strategies/TonAirdropStrategy.d.ts +26 -0
  20. package/dist/cjs/airdrop/strategies/TonAirdropStrategy.js +64 -0
  21. package/dist/cjs/airdrop/strategies/TonAirdropStrategy.js.map +1 -0
  22. package/dist/cjs/airdrop/types/index.d.ts +5 -0
  23. package/dist/esm/airdrop/index.d.ts +10 -12
  24. package/dist/esm/airdrop/index.js +120 -112
  25. package/dist/esm/airdrop/index.js.map +1 -1
  26. package/dist/esm/airdrop/services/index.d.ts +6 -1
  27. package/dist/esm/airdrop/services/index.js +4 -0
  28. package/dist/esm/airdrop/services/index.js.map +1 -1
  29. package/dist/esm/airdrop/strategies/AirdropStrategyFactory.d.ts +13 -0
  30. package/dist/esm/airdrop/strategies/AirdropStrategyFactory.js +18 -0
  31. package/dist/esm/airdrop/strategies/AirdropStrategyFactory.js.map +1 -0
  32. package/dist/esm/airdrop/strategies/EvmAirdropStrategy.d.ts +26 -0
  33. package/dist/esm/airdrop/strategies/EvmAirdropStrategy.js +75 -0
  34. package/dist/esm/airdrop/strategies/EvmAirdropStrategy.js.map +1 -0
  35. package/dist/esm/airdrop/strategies/IAirdropStrategy.d.ts +27 -0
  36. package/dist/esm/airdrop/strategies/IAirdropStrategy.js +2 -0
  37. package/dist/esm/airdrop/strategies/IAirdropStrategy.js.map +1 -0
  38. package/dist/esm/airdrop/strategies/StrategyCache.d.ts +10 -0
  39. package/dist/esm/airdrop/strategies/StrategyCache.js +28 -0
  40. package/dist/esm/airdrop/strategies/StrategyCache.js.map +1 -0
  41. package/dist/esm/airdrop/strategies/TonAirdropStrategy.d.ts +26 -0
  42. package/dist/esm/airdrop/strategies/TonAirdropStrategy.js +60 -0
  43. package/dist/esm/airdrop/strategies/TonAirdropStrategy.js.map +1 -0
  44. package/dist/esm/airdrop/types/index.d.ts +5 -0
  45. package/package.json +1 -1
  46. package/src/airdrop/index.ts +144 -140
  47. package/src/airdrop/services/index.ts +6 -1
  48. package/src/airdrop/strategies/AirdropStrategyFactory.ts +29 -0
  49. package/src/airdrop/strategies/EvmAirdropStrategy.ts +85 -0
  50. package/src/airdrop/strategies/IAirdropStrategy.ts +25 -0
  51. package/src/airdrop/strategies/StrategyCache.ts +34 -0
  52. package/src/airdrop/strategies/TonAirdropStrategy.ts +72 -0
  53. package/src/airdrop/tests/index.test.ts +85 -0
  54. package/src/airdrop/types/index.ts +6 -0
@@ -1,6 +1,6 @@
1
1
  import { apiClient } from '../../utils/api-client';
2
2
  import { safeParseJSON } from '../../utils/utils';
3
- import { IAirdropData, IProject } from '../types';
3
+ import { IAirdropData, IContractConfig, IProject } from '../types';
4
4
 
5
5
  export { TonWalletService } from './wallet-service/ton';
6
6
 
@@ -54,6 +54,11 @@ export const getAirdropQuery = async (
54
54
  return client.post(`/airdrop-open/query`, data);
55
55
  };
56
56
 
57
+ export const getAirdropContractConfig = async (data: { chainId: string; chainType: string; contractAddress: string }, baseURL?: string): Promise<IContractConfig> => {
58
+ const client = createApiClient(baseURL);
59
+ return client.post(`/airdrop-open/contract/config`, data);
60
+ };
61
+
57
62
  export const getJettonInfo = async (
58
63
  data: { address: string; isTestnet: 'true' | 'false' },
59
64
  baseURL?: string
@@ -0,0 +1,29 @@
1
+ import { ChainType, IWalletClient } from '../types';
2
+ import { EvmAirdropStrategy } from './EvmAirdropStrategy';
3
+ import { IAirdropStrategy, IAirdropStrategyConstructor } from './IAirdropStrategy';
4
+ import { TonAirdropStrategy } from './TonAirdropStrategy';
5
+ import { TonClient } from '@ton/ton';
6
+
7
+ export class AirdropStrategyFactory {
8
+ private static strategyMap: Record<ChainType, IAirdropStrategyConstructor> = {
9
+ [ChainType.Evm]: EvmAirdropStrategy,
10
+ [ChainType.Ton]: TonAirdropStrategy
11
+ };
12
+
13
+ static createStrategy(params: {
14
+ chainType: ChainType;
15
+ contractAddress: string;
16
+ chainId: string | number;
17
+ walletClient?: IWalletClient;
18
+ tonClient?: TonClient;
19
+ }): IAirdropStrategy {
20
+ const { chainType, ...strategyParams } = params;
21
+ const StrategyClass = this.strategyMap[chainType];
22
+
23
+ if (!StrategyClass) {
24
+ throw new Error(`Unsupported chain type: ${chainType}`);
25
+ }
26
+
27
+ return new StrategyClass(strategyParams);
28
+ }
29
+ }
@@ -0,0 +1,85 @@
1
+ import { AirdropService as EvmAirdropService } from '../core/evm/AirdropService';
2
+ import { ChainId, IWalletClient } from '../types';
3
+ import { IAirdropStrategy } from './IAirdropStrategy';
4
+ import { WalletClient as ViemWalletClient } from 'viem';
5
+
6
+ export class EvmAirdropStrategy implements IAirdropStrategy {
7
+ private service: EvmAirdropService | undefined;
8
+ private readonly contractAddress: string;
9
+ private readonly chainId: ChainId;
10
+ private walletClient?: ViemWalletClient;
11
+ private cachedVersion: string | null = null;
12
+
13
+ constructor(params: {
14
+ contractAddress: string;
15
+ chainId: string | number;
16
+ walletClient?: IWalletClient;
17
+ }) {
18
+ this.contractAddress = params.contractAddress;
19
+ this.chainId = Number(params.chainId) as ChainId;
20
+ if (params.walletClient) {
21
+ this.walletClient = params.walletClient as ViemWalletClient;
22
+ }
23
+ }
24
+
25
+ async initialize(walletClient?: IWalletClient): Promise<void> {
26
+ if (walletClient) {
27
+ this.walletClient = walletClient as ViemWalletClient;
28
+ }
29
+ this.service = new EvmAirdropService({
30
+ contractAddress: this.contractAddress,
31
+ chainId: this.chainId,
32
+ walletClient: this.walletClient
33
+ });
34
+ }
35
+
36
+ isInitialized(): boolean {
37
+ return !!this.service;
38
+ }
39
+
40
+ async getVersion(): Promise<string> {
41
+ if (this.cachedVersion) {
42
+ return this.cachedVersion;
43
+ }
44
+ if (!this.service) throw new Error('Strategy not initialized');
45
+ this.cachedVersion = await this.service.getVersion();
46
+ return this.cachedVersion;
47
+ }
48
+
49
+ async claim(claimData: any): Promise<any> {
50
+ if (!this.service) throw new Error('Strategy not initialized');
51
+ const { proof, group, data, value, extraData } = claimData;
52
+ return this.service.claim({
53
+ proof,
54
+ group,
55
+ data,
56
+ value,
57
+ extraData
58
+ });
59
+ }
60
+
61
+ async checkClaimed(claimData: any): Promise<boolean> {
62
+ if (!this.service) throw new Error('Strategy not initialized');
63
+ return this.service.isLeafUsed(claimData.leaf);
64
+ }
65
+
66
+ async batchCheckClaimed(leafs: string[]): Promise<{ result: boolean; status: string }[]> {
67
+ if (!this.service) throw new Error('Strategy not initialized');
68
+ return this.service.batchFetchClaimed(leafs);
69
+ }
70
+
71
+ async getNFT(): Promise<string> {
72
+ if (!this.service) throw new Error('Strategy not initialized');
73
+ return this.service.getNFT() as unknown as string;
74
+ }
75
+
76
+ async getKycThreshold(): Promise<bigint> {
77
+ if (!this.service) throw new Error('Strategy not initialized');
78
+ return this.service.getKycThreshold();
79
+ }
80
+
81
+ async getClaimFee(contractAddress: string, amount: bigint): Promise<bigint> {
82
+ if (!this.service) throw new Error('Strategy not initialized');
83
+ return this.service.getClaimFee(contractAddress, amount) as unknown as bigint;
84
+ }
85
+ }
@@ -0,0 +1,25 @@
1
+ import { IWalletClient } from '../types';
2
+ import { TonClient } from '@ton/ton';
3
+
4
+ export interface IAirdropStrategy {
5
+ getVersion(): Promise<string>;
6
+ claim(claimData: any, options?: { onLoading?: () => void }): Promise<any>;
7
+ checkClaimed(claimData: any): Promise<boolean>;
8
+ isInitialized(): boolean;
9
+ initialize(walletClient?: IWalletClient): Promise<void>;
10
+ getPaused?(): Promise<boolean>;
11
+ // EVM specific methods
12
+ batchCheckClaimed?(leafs: string[]): Promise<Array<{ result: boolean; status: string }>>;
13
+ getNFT?(): Promise<string>;
14
+ getKycThreshold?(): Promise<bigint>;
15
+ getClaimFee?(contractAddress: string, amount: bigint): Promise<string | bigint>;
16
+ }
17
+
18
+ export interface IAirdropStrategyConstructor {
19
+ new (params: {
20
+ contractAddress: string;
21
+ chainId: string | number;
22
+ walletClient?: IWalletClient;
23
+ tonClient?: TonClient;
24
+ }): IAirdropStrategy;
25
+ }
@@ -0,0 +1,34 @@
1
+ import { IAirdropStrategy } from './IAirdropStrategy';
2
+
3
+ export class StrategyCache {
4
+ private readOnlyStrategies: Map<string, IAirdropStrategy> = new Map();
5
+ private walletStrategies: Map<string, IAirdropStrategy> = new Map();
6
+
7
+ private getCacheKey(contractAddress: string, chainId: string | number, chainType: string): string {
8
+ return `${chainType}:${contractAddress}:${chainId}`;
9
+ }
10
+
11
+ getStrategy(contractAddress: string, chainId: string | number, chainType: string, hasWallet: boolean = false): IAirdropStrategy | undefined {
12
+ const cache = hasWallet ? this.walletStrategies : this.readOnlyStrategies;
13
+ const cacheKey = this.getCacheKey(contractAddress, chainId, chainType);
14
+ return cache.get(cacheKey);
15
+ }
16
+
17
+ setStrategy(contractAddress: string, chainId: string | number, chainType: string, strategy: IAirdropStrategy, hasWallet: boolean = false): void {
18
+ const cache = hasWallet ? this.walletStrategies : this.readOnlyStrategies;
19
+ const cacheKey = this.getCacheKey(contractAddress, chainId, chainType);
20
+ cache.set(cacheKey, strategy);
21
+ }
22
+
23
+ clearStrategy(contractAddress: string, chainId: string | number, chainType: string, hasWallet?: boolean): void {
24
+ const cacheKey = this.getCacheKey(contractAddress, chainId, chainType);
25
+ if (hasWallet === undefined || hasWallet) {
26
+ this.walletStrategies.delete(cacheKey);
27
+ }
28
+ if (hasWallet === undefined || !hasWallet) {
29
+ this.readOnlyStrategies.delete(cacheKey);
30
+ }
31
+ }
32
+ }
33
+
34
+ export const strategyCache = new StrategyCache();
@@ -0,0 +1,72 @@
1
+ import { TonClient } from '@ton/ton';
2
+ import { TonConnectUI } from '@tonconnect/ui-react';
3
+ import { AirdropService as TonAirdropService } from '../core/ton/AirdropService';
4
+ import { IWalletClient } from '../types';
5
+ import { IAirdropStrategy } from './IAirdropStrategy';
6
+
7
+ export class TonAirdropStrategy implements IAirdropStrategy {
8
+ private service: TonAirdropService | undefined;
9
+ private readonly contractAddress: string;
10
+ private readonly chainId: string;
11
+ private readonly tonClient?: TonClient;
12
+ private walletClient?: TonConnectUI;
13
+ private cachedVersion: string | null = null;
14
+
15
+ constructor(params: {
16
+ contractAddress: string;
17
+ chainId: string | number;
18
+ walletClient?: IWalletClient;
19
+ tonClient?: TonClient;
20
+ }) {
21
+ this.contractAddress = params.contractAddress;
22
+ this.chainId = params.chainId.toString();
23
+ this.tonClient = params.tonClient;
24
+ if (params.walletClient) {
25
+ this.walletClient = params.walletClient as TonConnectUI;
26
+ }
27
+ }
28
+
29
+ async initialize(walletClient?: IWalletClient): Promise<void> {
30
+ if (walletClient) {
31
+ this.walletClient = walletClient as TonConnectUI;
32
+ }
33
+ this.service = new TonAirdropService({
34
+ address: this.contractAddress,
35
+ chainId: this.chainId,
36
+ walletClient: this.walletClient,
37
+ tonClient: this.tonClient
38
+ });
39
+ }
40
+
41
+ isInitialized(): boolean {
42
+ return !!this.service;
43
+ }
44
+
45
+ async getVersion(): Promise<string> {
46
+ if (!this.service) throw new Error('Strategy not initialized');
47
+ if (!this.cachedVersion) {
48
+ this.cachedVersion = await this.service.getVersion();
49
+ }
50
+ return this.cachedVersion;
51
+ }
52
+
53
+ async claim(claimData: any, options?: { onLoading?: () => void }): Promise<any> {
54
+ if (!this.service) throw new Error('Strategy not initialized');
55
+ return this.service.claim(claimData, options);
56
+ }
57
+
58
+ async checkClaimed(claimData: any): Promise<boolean> {
59
+ if (!this.service) throw new Error('Strategy not initialized');
60
+ return this.service.checkClaimed(claimData);
61
+ }
62
+
63
+ async getPaused(): Promise<boolean> {
64
+ if (!this.service) throw new Error('Strategy not initialized');
65
+ return this.service.getPaused();
66
+ }
67
+
68
+ async getClaimFee(contractAddress: string, amount: bigint): Promise<string> {
69
+ if (!this.service) throw new Error('Strategy not initialized');
70
+ return this.service.getClaimFee(contractAddress, amount);
71
+ }
72
+ }
@@ -48,7 +48,18 @@ describe('AirdropClient', () => {
48
48
  expect(version).toBeDefined();
49
49
  });
50
50
 
51
+ it('should get paused', async () => {
52
+ const client = new AirdropClient({
53
+ projectId: 'AD_PeMV2dboWAui',
54
+ endpoint: mockEndpoint
55
+ });
56
+ const paused = await client.getPaused();
57
+ console.log(paused);
58
+ expect(paused).toBeDefined();
59
+ });
60
+
51
61
  it('should get claim fee', async () => {
62
+ // evm
52
63
  const client = new AirdropClient({
53
64
  projectId: 'AD_50lczFu9Yhvq',
54
65
  endpoint: mockEndpoint
@@ -58,6 +69,15 @@ describe('AirdropClient', () => {
58
69
  expect(fee).toBeDefined();
59
70
  });
60
71
 
72
+ it('should get paused throw error', async () => {
73
+ // evm
74
+ const client = new AirdropClient({
75
+ projectId: 'AD_50lczFu9Yhvq',
76
+ endpoint: mockEndpoint
77
+ });
78
+ await expect(client.getPaused()).rejects.toThrow();
79
+ });
80
+
61
81
  //AD_S4dSTEXQN96i
62
82
 
63
83
  it('should work on native v1', async () => {
@@ -87,6 +107,71 @@ describe('AirdropClient', () => {
87
107
  });
88
108
  });
89
109
 
110
+ describe('getStrategy', () => {
111
+ let client: AirdropClient;
112
+ const mockWalletClient = {
113
+ connected: true,
114
+ account: { address: '0xMockAddress' },
115
+ network: { name: 'mock', chainId: 1 },
116
+ connector: { name: 'mock' },
117
+ sendTransaction: jest.fn()
118
+ } as any;
119
+
120
+ beforeEach(async () => {
121
+ client = new AirdropClient({
122
+ projectId: 'AD_TEV94wvkxkvn',
123
+ endpoint: mockEndpoint
124
+ });
125
+ // Clear strategy cache before each test
126
+ jest.clearAllMocks();
127
+ });
128
+
129
+ it('should get strategy without wallet client (read-only mode)', async () => {
130
+ const strategy = await client.getStrategy();
131
+ expect(strategy).toBeDefined();
132
+ // Verify it's in read-only mode
133
+ expect((strategy as any).walletClient).toBeUndefined();
134
+ });
135
+
136
+ it('should get strategy with wallet client (interactive mode)', async () => {
137
+ const strategy = await client.getStrategy(mockWalletClient);
138
+ expect(strategy).toBeDefined();
139
+ expect((strategy as any).walletClient).toBeDefined();
140
+ });
141
+
142
+ it('should use cached strategy when available', async () => {
143
+ // First call to get strategy
144
+ const strategy1 = await client.getStrategy(mockWalletClient);
145
+
146
+ // Second call should return cached strategy
147
+ const strategy2 = await client.getStrategy(mockWalletClient);
148
+
149
+ // Both should be the same instance
150
+ expect(strategy1).toBe(strategy2);
151
+ });
152
+
153
+ it('should reinitialize wallet client even with cached strategy', async () => {
154
+ // Get strategy with first wallet client
155
+ const strategy1 = await client.getStrategy(mockWalletClient);
156
+
157
+ // Create new mock wallet client
158
+ const newMockWalletClient = {
159
+ connected: true,
160
+ account: { address: '0xNewMockAddress' },
161
+ network: { name: 'mock', chainId: 1 },
162
+ connector: { name: 'mock' },
163
+ sendTransaction: jest.fn()
164
+ } as any;
165
+
166
+ // Get strategy with new wallet client
167
+ const strategy2 = await client.getStrategy(newMockWalletClient);
168
+
169
+ // Should be same strategy instance but reinitialized with new wallet
170
+ expect((strategy2 as any).walletClient).toBeDefined();
171
+ expect((strategy2 as any).walletClient).toBe(newMockWalletClient);
172
+ });
173
+ });
174
+
90
175
  // describe('catch error', () => {
91
176
  // it('throw error when projectId is not provided', async () => {
92
177
  // client = new AirdropClient({
@@ -133,3 +133,9 @@ type SlugOptions = BaseAirdropOptions & {
133
133
  };
134
134
 
135
135
  export type IAirdropOptions = ProjectIdOptions | SlugOptions;
136
+
137
+ export interface IContractConfig {
138
+ version?: string | null;
139
+ paused: boolean | null;
140
+ claimFee?: string | null;
141
+ }