@sign-global/tokentable-core 1.0.0 → 1.1.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/CHANGELOG.md +18 -0
- package/README.md +72 -0
- package/dist/index.d.mts +10 -5
- package/dist/index.d.ts +10 -5
- package/dist/index.js +32 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +32 -20
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -2
- package/src/constants/chain-config.ts +2 -2
- package/src/contracts/evm/AirdropService.ts +18 -13
- package/src/services/airdrop/index.ts +3 -1
- package/src/test/setup.ts +24 -0
- package/src/types/index.ts +8 -2
- package/src/utils/__tests__/web3.test.ts +326 -0
- package/src/utils/api-client.ts +2 -2
- package/src/utils/utils.ts +8 -3
- package/vitest.config.ts +14 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @sign-global/tokentable-core
|
|
2
2
|
|
|
3
|
+
## 1.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- feat: update Arbitrum chain configuration
|
|
8
|
+
|
|
9
|
+
## 0.0.0-beta-20250625021659
|
|
10
|
+
|
|
11
|
+
### Major Changes
|
|
12
|
+
|
|
13
|
+
- ✨ feat: add beta version script and improve claim fee calculation
|
|
14
|
+
|
|
15
|
+
## 0.0.0-beta-20250624084326
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- ✨ feat: add fee handling for TokenTableMerkleDistributorWithFees
|
|
20
|
+
|
|
3
21
|
## 1.0.0
|
|
4
22
|
|
|
5
23
|
### Major Changes
|
package/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# TokenTable Core Package
|
|
2
|
+
|
|
3
|
+
Core utilities and functions for the TokenTable SDK.
|
|
4
|
+
|
|
5
|
+
## Development
|
|
6
|
+
|
|
7
|
+
### Testing
|
|
8
|
+
|
|
9
|
+
This package uses [Vitest](https://vitest.dev/) for testing.
|
|
10
|
+
|
|
11
|
+
#### Running Tests
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Run tests once
|
|
15
|
+
pnpm test:run
|
|
16
|
+
|
|
17
|
+
# Run tests in watch mode
|
|
18
|
+
pnpm test
|
|
19
|
+
|
|
20
|
+
# Run tests with UI
|
|
21
|
+
pnpm vitest --ui
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
#### Test Structure
|
|
25
|
+
|
|
26
|
+
Tests are located in `src/**/__tests__/` directories following the pattern `*.test.ts`.
|
|
27
|
+
|
|
28
|
+
#### Current Test Coverage
|
|
29
|
+
|
|
30
|
+
- `getOrCreateAssociatedTokenAccount` - Comprehensive tests for Solana associated token account creation
|
|
31
|
+
- Tests existing account retrieval
|
|
32
|
+
- Tests new account creation when account doesn't exist
|
|
33
|
+
- Tests error handling for invalid mint/owner
|
|
34
|
+
- Tests custom parameter handling
|
|
35
|
+
- Tests unexpected error propagation
|
|
36
|
+
|
|
37
|
+
### Building
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Build the package
|
|
41
|
+
pnpm build
|
|
42
|
+
|
|
43
|
+
# Build in watch mode
|
|
44
|
+
pnpm build:watch
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Cleaning
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Clean build artifacts
|
|
51
|
+
pnpm clean
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Testing Philosophy
|
|
55
|
+
|
|
56
|
+
The tests use comprehensive mocking to isolate the unit under test while ensuring all code paths are covered. Key testing principles:
|
|
57
|
+
|
|
58
|
+
1. **Isolation**: External dependencies are mocked to focus on the function logic
|
|
59
|
+
2. **Coverage**: All branches and error conditions are tested
|
|
60
|
+
3. **Realistic Data**: Valid Solana public keys and realistic mock data are used
|
|
61
|
+
4. **Error Handling**: Both expected and unexpected errors are tested
|
|
62
|
+
|
|
63
|
+
## Dependencies
|
|
64
|
+
|
|
65
|
+
This package depends on:
|
|
66
|
+
- `@solana/web3.js` - Solana blockchain interaction
|
|
67
|
+
- `@solana/spl-token` - SPL Token program utilities
|
|
68
|
+
- Various other blockchain and utility libraries
|
|
69
|
+
|
|
70
|
+
Dev dependencies include:
|
|
71
|
+
- `vitest` - Testing framework
|
|
72
|
+
- `jsdom` - DOM environment for tests
|
package/dist/index.d.mts
CHANGED
|
@@ -74,7 +74,7 @@ declare const ChainConfig: {
|
|
|
74
74
|
};
|
|
75
75
|
42161: {
|
|
76
76
|
contractAddress: string;
|
|
77
|
-
rpcUrl:
|
|
77
|
+
rpcUrl: string;
|
|
78
78
|
};
|
|
79
79
|
80085: {
|
|
80
80
|
contractAddress: string;
|
|
@@ -1803,6 +1803,7 @@ type IAirdropClaim = {
|
|
|
1803
1803
|
data: string;
|
|
1804
1804
|
leaf: string;
|
|
1805
1805
|
claimed?: boolean;
|
|
1806
|
+
fees: string;
|
|
1806
1807
|
claimId?: string;
|
|
1807
1808
|
claimable?: boolean;
|
|
1808
1809
|
proofHash: string;
|
|
@@ -1812,9 +1813,13 @@ type IAirdropClaim = {
|
|
|
1812
1813
|
expired?: boolean;
|
|
1813
1814
|
project: IProject;
|
|
1814
1815
|
};
|
|
1816
|
+
interface IExtraData {
|
|
1817
|
+
isLegacy: boolean;
|
|
1818
|
+
attestationId: bigint;
|
|
1819
|
+
}
|
|
1815
1820
|
interface IAirdropClaimData extends IAirdropClaim {
|
|
1816
|
-
extraData
|
|
1817
|
-
value
|
|
1821
|
+
extraData?: IExtraData;
|
|
1822
|
+
value?: bigint | string;
|
|
1818
1823
|
}
|
|
1819
1824
|
type IAirdropSignatureClaim = {
|
|
1820
1825
|
percent: number;
|
|
@@ -2052,7 +2057,7 @@ declare function fetchTokenVersion(tokenAddress: string, options: FetchTokenMeta
|
|
|
2052
2057
|
declare const clusterApiUrl: (cluster?: Cluster) => string;
|
|
2053
2058
|
|
|
2054
2059
|
declare const getCustomNaNoId: () => string;
|
|
2055
|
-
declare const safeParseJSON: (str: string) =>
|
|
2060
|
+
declare const safeParseJSON: <T = any>(str: string | null | undefined, defaultValue?: T) => T;
|
|
2056
2061
|
declare const isBeforeByUnix: (unix: number) => boolean;
|
|
2057
2062
|
declare const delay: (ms: number) => Promise<unknown>;
|
|
2058
2063
|
declare function retry<T>(fn: () => Promise<T>, options: {
|
|
@@ -2101,4 +2106,4 @@ declare const getAvailableClaimAmountForSignature: ({ contractAddress, chainId,
|
|
|
2101
2106
|
}[];
|
|
2102
2107
|
}) => Promise<string | 0>;
|
|
2103
2108
|
|
|
2104
|
-
export { AirdropSigIdentityTypeEnum, ApiClient, type ApiClientOptions, type ApiRequestOptions, CONST, ChainConfig, type ChainId, ChainType, ETokenType, ErrorCode, AirdropService$2 as EvmAirdropService, EvmAirdropVersionEnum, type EvmContractClientOption, SignatureAirdropService$1 as EvmSignatureAirdropService, type FetchTokenMetadataOptions, type FetchTokenVersionOptions, type IAirdropClaim, type IAirdropClaimData, type IAirdropData, type IAirdropOptions, type IAirdropService, type IAirdropSignatureClaim, type IAirdropSignatureData, type IAirdropSignatureIdentity, type IClaimSignature, type IContractConfig, type IProject, type IProjectExtra, type IWalletClient, type Identity, AirdropService$1 as SolanaAirdropService, SignatureAirdropService as SolanaSignatureAirdropService, SplTokenVersion, type SupportedChainType, SupportedChains, type ThemeConfig, AirdropService as TonAirdropService, TonAirdropVersionEnum, TonWalletService, ZERO_ADDRESS, apiClient, batchCheckClaimedForSignature, bindWallet, checkEligibility, checkGetSignatures, cleanUrlParams, clusterApiUrl, connectGoogleApi, connectTwitter, delay, disconnectRecipient, fetchTokenVersion, flipAddressType, getAirdropContractConfig, getAirdropPro, getAirdropProject, getAirdropProjectId, getAirdropQuery, getAvailableClaimAmountForSignature, getChainById, getChainConfig, getChainRpc, getCustomNaNoId, getJettonInfo, getOrCreateAssociatedTokenAccount, getTonProjectIdByAddress, hexStrToU8Array, isBeforeByUnix, isGreaterThan, isMobile, mevmDevNet, retry, safeParseJSON, safePlus, signBrBTestnet, solanaDevNet, solanaMainNet, tonMainNet, tonTestNet };
|
|
2109
|
+
export { AirdropSigIdentityTypeEnum, ApiClient, type ApiClientOptions, type ApiRequestOptions, CONST, ChainConfig, type ChainId, ChainType, ETokenType, ErrorCode, AirdropService$2 as EvmAirdropService, EvmAirdropVersionEnum, type EvmContractClientOption, SignatureAirdropService$1 as EvmSignatureAirdropService, type FetchTokenMetadataOptions, type FetchTokenVersionOptions, type IAirdropClaim, type IAirdropClaimData, type IAirdropData, type IAirdropOptions, type IAirdropService, type IAirdropSignatureClaim, type IAirdropSignatureData, type IAirdropSignatureIdentity, type IClaimSignature, type IContractConfig, type IExtraData, type IProject, type IProjectExtra, type IWalletClient, type Identity, AirdropService$1 as SolanaAirdropService, SignatureAirdropService as SolanaSignatureAirdropService, SplTokenVersion, type SupportedChainType, SupportedChains, type ThemeConfig, AirdropService as TonAirdropService, TonAirdropVersionEnum, TonWalletService, ZERO_ADDRESS, apiClient, batchCheckClaimedForSignature, bindWallet, checkEligibility, checkGetSignatures, cleanUrlParams, clusterApiUrl, connectGoogleApi, connectTwitter, delay, disconnectRecipient, fetchTokenVersion, flipAddressType, getAirdropContractConfig, getAirdropPro, getAirdropProject, getAirdropProjectId, getAirdropQuery, getAvailableClaimAmountForSignature, getChainById, getChainConfig, getChainRpc, getCustomNaNoId, getJettonInfo, getOrCreateAssociatedTokenAccount, getTonProjectIdByAddress, hexStrToU8Array, isBeforeByUnix, isGreaterThan, isMobile, mevmDevNet, retry, safeParseJSON, safePlus, signBrBTestnet, solanaDevNet, solanaMainNet, tonMainNet, tonTestNet };
|
package/dist/index.d.ts
CHANGED
|
@@ -74,7 +74,7 @@ declare const ChainConfig: {
|
|
|
74
74
|
};
|
|
75
75
|
42161: {
|
|
76
76
|
contractAddress: string;
|
|
77
|
-
rpcUrl:
|
|
77
|
+
rpcUrl: string;
|
|
78
78
|
};
|
|
79
79
|
80085: {
|
|
80
80
|
contractAddress: string;
|
|
@@ -1803,6 +1803,7 @@ type IAirdropClaim = {
|
|
|
1803
1803
|
data: string;
|
|
1804
1804
|
leaf: string;
|
|
1805
1805
|
claimed?: boolean;
|
|
1806
|
+
fees: string;
|
|
1806
1807
|
claimId?: string;
|
|
1807
1808
|
claimable?: boolean;
|
|
1808
1809
|
proofHash: string;
|
|
@@ -1812,9 +1813,13 @@ type IAirdropClaim = {
|
|
|
1812
1813
|
expired?: boolean;
|
|
1813
1814
|
project: IProject;
|
|
1814
1815
|
};
|
|
1816
|
+
interface IExtraData {
|
|
1817
|
+
isLegacy: boolean;
|
|
1818
|
+
attestationId: bigint;
|
|
1819
|
+
}
|
|
1815
1820
|
interface IAirdropClaimData extends IAirdropClaim {
|
|
1816
|
-
extraData
|
|
1817
|
-
value
|
|
1821
|
+
extraData?: IExtraData;
|
|
1822
|
+
value?: bigint | string;
|
|
1818
1823
|
}
|
|
1819
1824
|
type IAirdropSignatureClaim = {
|
|
1820
1825
|
percent: number;
|
|
@@ -2052,7 +2057,7 @@ declare function fetchTokenVersion(tokenAddress: string, options: FetchTokenMeta
|
|
|
2052
2057
|
declare const clusterApiUrl: (cluster?: Cluster) => string;
|
|
2053
2058
|
|
|
2054
2059
|
declare const getCustomNaNoId: () => string;
|
|
2055
|
-
declare const safeParseJSON: (str: string) =>
|
|
2060
|
+
declare const safeParseJSON: <T = any>(str: string | null | undefined, defaultValue?: T) => T;
|
|
2056
2061
|
declare const isBeforeByUnix: (unix: number) => boolean;
|
|
2057
2062
|
declare const delay: (ms: number) => Promise<unknown>;
|
|
2058
2063
|
declare function retry<T>(fn: () => Promise<T>, options: {
|
|
@@ -2101,4 +2106,4 @@ declare const getAvailableClaimAmountForSignature: ({ contractAddress, chainId,
|
|
|
2101
2106
|
}[];
|
|
2102
2107
|
}) => Promise<string | 0>;
|
|
2103
2108
|
|
|
2104
|
-
export { AirdropSigIdentityTypeEnum, ApiClient, type ApiClientOptions, type ApiRequestOptions, CONST, ChainConfig, type ChainId, ChainType, ETokenType, ErrorCode, AirdropService$2 as EvmAirdropService, EvmAirdropVersionEnum, type EvmContractClientOption, SignatureAirdropService$1 as EvmSignatureAirdropService, type FetchTokenMetadataOptions, type FetchTokenVersionOptions, type IAirdropClaim, type IAirdropClaimData, type IAirdropData, type IAirdropOptions, type IAirdropService, type IAirdropSignatureClaim, type IAirdropSignatureData, type IAirdropSignatureIdentity, type IClaimSignature, type IContractConfig, type IProject, type IProjectExtra, type IWalletClient, type Identity, AirdropService$1 as SolanaAirdropService, SignatureAirdropService as SolanaSignatureAirdropService, SplTokenVersion, type SupportedChainType, SupportedChains, type ThemeConfig, AirdropService as TonAirdropService, TonAirdropVersionEnum, TonWalletService, ZERO_ADDRESS, apiClient, batchCheckClaimedForSignature, bindWallet, checkEligibility, checkGetSignatures, cleanUrlParams, clusterApiUrl, connectGoogleApi, connectTwitter, delay, disconnectRecipient, fetchTokenVersion, flipAddressType, getAirdropContractConfig, getAirdropPro, getAirdropProject, getAirdropProjectId, getAirdropQuery, getAvailableClaimAmountForSignature, getChainById, getChainConfig, getChainRpc, getCustomNaNoId, getJettonInfo, getOrCreateAssociatedTokenAccount, getTonProjectIdByAddress, hexStrToU8Array, isBeforeByUnix, isGreaterThan, isMobile, mevmDevNet, retry, safeParseJSON, safePlus, signBrBTestnet, solanaDevNet, solanaMainNet, tonMainNet, tonTestNet };
|
|
2109
|
+
export { AirdropSigIdentityTypeEnum, ApiClient, type ApiClientOptions, type ApiRequestOptions, CONST, ChainConfig, type ChainId, ChainType, ETokenType, ErrorCode, AirdropService$2 as EvmAirdropService, EvmAirdropVersionEnum, type EvmContractClientOption, SignatureAirdropService$1 as EvmSignatureAirdropService, type FetchTokenMetadataOptions, type FetchTokenVersionOptions, type IAirdropClaim, type IAirdropClaimData, type IAirdropData, type IAirdropOptions, type IAirdropService, type IAirdropSignatureClaim, type IAirdropSignatureData, type IAirdropSignatureIdentity, type IClaimSignature, type IContractConfig, type IExtraData, type IProject, type IProjectExtra, type IWalletClient, type Identity, AirdropService$1 as SolanaAirdropService, SignatureAirdropService as SolanaSignatureAirdropService, SplTokenVersion, type SupportedChainType, SupportedChains, type ThemeConfig, AirdropService as TonAirdropService, TonAirdropVersionEnum, TonWalletService, ZERO_ADDRESS, apiClient, batchCheckClaimedForSignature, bindWallet, checkEligibility, checkGetSignatures, cleanUrlParams, clusterApiUrl, connectGoogleApi, connectTwitter, delay, disconnectRecipient, fetchTokenVersion, flipAddressType, getAirdropContractConfig, getAirdropPro, getAirdropProject, getAirdropProjectId, getAirdropQuery, getAvailableClaimAmountForSignature, getChainById, getChainConfig, getChainRpc, getCustomNaNoId, getJettonInfo, getOrCreateAssociatedTokenAccount, getTonProjectIdByAddress, hexStrToU8Array, isBeforeByUnix, isGreaterThan, isMobile, mevmDevNet, retry, safeParseJSON, safePlus, signBrBTestnet, solanaDevNet, solanaMainNet, tonMainNet, tonTestNet };
|
package/dist/index.js
CHANGED
|
@@ -277,8 +277,8 @@ var ChainConfig = {
|
|
|
277
277
|
rpcUrl: "https://zetachain-mainnet.g.alchemy.com/v2/1tmk0FrhwTJHXh0XIyae7_SXw1lDCjgs"
|
|
278
278
|
},
|
|
279
279
|
[import_chains.arbitrum.id]: {
|
|
280
|
-
contractAddress: "
|
|
281
|
-
rpcUrl:
|
|
280
|
+
contractAddress: "0xeD09c23677D02f4f486E55f0f081cfc114EEa53b",
|
|
281
|
+
rpcUrl: "https://arb-mainnet.g.alchemy.com/v2/udrqNPSB6i5n5L6QSM31Ng72h_hFOrVT"
|
|
282
282
|
},
|
|
283
283
|
[import_chains.berachainTestnet.id]: {
|
|
284
284
|
contractAddress: "",
|
|
@@ -3899,11 +3899,16 @@ var getCustomNaNoId = () => {
|
|
|
3899
3899
|
const nanoid = (0, import_nanoid.customAlphabet)("1234567890abcdefghijklmnopqrstuvwxyz", 10);
|
|
3900
3900
|
return nanoid();
|
|
3901
3901
|
};
|
|
3902
|
-
var safeParseJSON = (str) => {
|
|
3902
|
+
var safeParseJSON = (str, defaultValue = {}) => {
|
|
3903
|
+
if (!str || typeof str !== "string") {
|
|
3904
|
+
return defaultValue;
|
|
3905
|
+
}
|
|
3903
3906
|
try {
|
|
3904
|
-
|
|
3907
|
+
const parsed = JSON.parse(str);
|
|
3908
|
+
return parsed !== null && parsed !== void 0 ? parsed : defaultValue;
|
|
3905
3909
|
} catch (error) {
|
|
3906
|
-
|
|
3910
|
+
console.warn("Failed to parse JSON:", error);
|
|
3911
|
+
return defaultValue;
|
|
3907
3912
|
}
|
|
3908
3913
|
};
|
|
3909
3914
|
var isBeforeByUnix = (unix) => {
|
|
@@ -3971,7 +3976,7 @@ var ApiClient = class _ApiClient {
|
|
|
3971
3976
|
}
|
|
3972
3977
|
const res = await fetch(finalUrl, init);
|
|
3973
3978
|
const [status, resData] = await Promise.all([res.status, res.json()]);
|
|
3974
|
-
if (status < 200
|
|
3979
|
+
if (status < 200 || status >= 300 || resData?.success !== true) {
|
|
3975
3980
|
return Promise.reject(resData);
|
|
3976
3981
|
}
|
|
3977
3982
|
return resData.data;
|
|
@@ -4150,22 +4155,27 @@ var AirdropService = class {
|
|
|
4150
4155
|
return this.airdropV3FeeClient.getFeelessThreshold();
|
|
4151
4156
|
}
|
|
4152
4157
|
async getClaimFee(address, amount) {
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
}
|
|
4157
|
-
const feeClient = this.getFeeClient(feeCollector);
|
|
4158
|
-
const fee = await feeClient.getFee(address, amount);
|
|
4159
|
-
const version = await this.getVersion();
|
|
4160
|
-
if (version === "0.3.0" /* V3 */) {
|
|
4161
|
-
const threshold = await this.getFeelessThreshold();
|
|
4162
|
-
if (isGreaterThan(Number(amount), Number(threshold))) {
|
|
4163
|
-
return fee;
|
|
4164
|
-
} else {
|
|
4158
|
+
try {
|
|
4159
|
+
const feeCollector = await this.feeCollectors(this.options.contractAddress);
|
|
4160
|
+
if (!feeCollector || feeCollector === ZERO_ADDRESS) {
|
|
4165
4161
|
return void 0;
|
|
4166
4162
|
}
|
|
4163
|
+
const feeClient = this.getFeeClient(feeCollector);
|
|
4164
|
+
const fee = await feeClient.getFee(address, amount);
|
|
4165
|
+
const version = await this.getVersion();
|
|
4166
|
+
if (version === "0.3.0" /* V3 */) {
|
|
4167
|
+
const threshold = await this.getFeelessThreshold();
|
|
4168
|
+
if (isGreaterThan(Number(amount), Number(threshold))) {
|
|
4169
|
+
return fee;
|
|
4170
|
+
} else {
|
|
4171
|
+
return void 0;
|
|
4172
|
+
}
|
|
4173
|
+
}
|
|
4174
|
+
return fee;
|
|
4175
|
+
} catch (error) {
|
|
4176
|
+
console.error("Failed to get claim fee:", error);
|
|
4177
|
+
throw new Error(`Failed to calculate claim fee: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
4167
4178
|
}
|
|
4168
|
-
return fee;
|
|
4169
4179
|
}
|
|
4170
4180
|
async getKycThreshold() {
|
|
4171
4181
|
const kycClient = await this.getKycClient();
|
|
@@ -10480,7 +10490,9 @@ var createApiClient = (baseURL) => {
|
|
|
10480
10490
|
var getAirdropProject = async (projectId, baseURL) => {
|
|
10481
10491
|
const client = createApiClient(baseURL);
|
|
10482
10492
|
const res = await client.get(`/airdrop-open/projects/${projectId}`);
|
|
10483
|
-
if (!res)
|
|
10493
|
+
if (!res) {
|
|
10494
|
+
throw new Error(`Project not found: ${projectId}`);
|
|
10495
|
+
}
|
|
10484
10496
|
const projectConfig = res?.themeConf;
|
|
10485
10497
|
const blockCountries = safeParseJSON(projectConfig?.blockCountries);
|
|
10486
10498
|
return {
|