@solana/kora 0.2.0-beta.4 → 0.2.0-beta.6
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/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/kit/executor.d.ts +7 -0
- package/dist/src/kit/executor.js +68 -0
- package/dist/src/kit/index.d.ts +53 -0
- package/dist/src/kit/index.js +75 -0
- package/dist/src/kit/payment.d.ts +18 -0
- package/dist/src/kit/payment.js +70 -0
- package/dist/src/kit/planner.d.ts +4 -0
- package/dist/src/kit/planner.js +23 -0
- package/dist/src/plugin.js +7 -6
- package/dist/src/types/index.d.ts +21 -1
- package/dist/test/integration.test.js +43 -16
- package/dist/test/kit-client.test.d.ts +1 -0
- package/dist/test/kit-client.test.js +491 -0
- package/dist/test/setup.d.ts +1 -4
- package/dist/test/setup.js +34 -136
- package/package.json +26 -16
package/dist/test/setup.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { findAssociatedTokenPda, getCreateAssociatedTokenIdempotentInstructionAsync, getInitializeMintInstruction, getMintSize, getMintToInstruction, TOKEN_PROGRAM_ADDRESS, } from '@solana-program/token';
|
|
1
|
+
import { assertIsAddress, createKeyPairSignerFromBytes, getBase58Encoder, lamports, } from '@solana/kit';
|
|
2
|
+
import { createClient } from '@solana/kit-client-litesvm';
|
|
3
|
+
import { tokenProgram, associatedTokenProgram } from '@solana-program/token';
|
|
5
4
|
import { config } from 'dotenv';
|
|
6
5
|
import path from 'path';
|
|
7
6
|
import { KoraClient } from '../src/index.js';
|
|
8
7
|
config({ path: path.resolve(process.cwd(), '.env') });
|
|
9
8
|
const DEFAULTS = {
|
|
10
|
-
COMMITMENT: 'processed',
|
|
11
9
|
DECIMALS: 6,
|
|
12
10
|
// Make sure this matches the USDC mint in kora.toml (9BgeTKqmFsPVnfYscfM6NvsgmZxei7XfdciShQ6D3bxJ)
|
|
13
11
|
DESTINATION_ADDRESS: 'AVmDft8deQEo78bRKcGN5ZMf3hyjeLBK4Rd4xGB46yQM',
|
|
@@ -17,8 +15,6 @@ const DEFAULTS = {
|
|
|
17
15
|
KORA_SIGNER_TYPE: 'memory',
|
|
18
16
|
// Make sure this matches the kora-rpc signer address on launch (root .env)
|
|
19
17
|
SENDER_SECRET: 'tzgfgSWTE3KUA6qfRoFYLaSfJm59uUeZRDy4ybMrLn1JV2drA1mftiaEcVFvq1Lok6h6EX2C4Y9kSKLvQWyMpS5',
|
|
20
|
-
SOLANA_RPC_URL: 'http://127.0.0.1:8899',
|
|
21
|
-
SOLANA_WS_URL: 'ws://127.0.0.1:8900',
|
|
22
18
|
SOL_DROP_AMOUNT: 1_000_000_000,
|
|
23
19
|
// HhA5j2rRiPbMrpF2ZD36r69FyZf3zWmEHRNSZbbNdVjf
|
|
24
20
|
TEST_USDC_MINT_SECRET: '59kKmXphL5UJANqpFFjtH17emEq3oRNmYsx6a3P3vSGJRmhMgVdzH77bkNEi9bArRViT45e8L2TsuPxKNFoc3Qfg',
|
|
@@ -54,9 +50,6 @@ export function loadEnvironmentVariables() {
|
|
|
54
50
|
}
|
|
55
51
|
}
|
|
56
52
|
const koraRpcUrl = process.env.KORA_RPC_URL || DEFAULTS.KORA_RPC_URL;
|
|
57
|
-
const solanaRpcUrl = process.env.SOLANA_RPC_URL || DEFAULTS.SOLANA_RPC_URL;
|
|
58
|
-
const solanaWsUrl = process.env.SOLANA_WS_URL || DEFAULTS.SOLANA_WS_URL;
|
|
59
|
-
const commitment = (process.env.COMMITMENT || DEFAULTS.COMMITMENT);
|
|
60
53
|
const tokenDecimals = Number(process.env.TOKEN_DECIMALS || DEFAULTS.DECIMALS);
|
|
61
54
|
const tokenDropAmount = Number(process.env.TOKEN_DROP_AMOUNT || DEFAULTS.TOKEN_DROP_AMOUNT);
|
|
62
55
|
const solDropAmount = BigInt(process.env.SOL_DROP_AMOUNT || DEFAULTS.SOL_DROP_AMOUNT);
|
|
@@ -66,14 +59,11 @@ export function loadEnvironmentVariables() {
|
|
|
66
59
|
assertIsAddress(destinationAddress);
|
|
67
60
|
assertIsAddress(koraAddress);
|
|
68
61
|
return {
|
|
69
|
-
commitment,
|
|
70
62
|
destinationAddress,
|
|
71
63
|
koraAddress,
|
|
72
64
|
koraRpcUrl,
|
|
73
65
|
koraSignerType,
|
|
74
66
|
solDropAmount,
|
|
75
|
-
solanaRpcUrl,
|
|
76
|
-
solanaWsUrl,
|
|
77
67
|
testUsdcMintSecret,
|
|
78
68
|
testWalletSecret,
|
|
79
69
|
tokenDecimals,
|
|
@@ -90,129 +80,46 @@ async function createKeyPairSigners() {
|
|
|
90
80
|
usdcMint,
|
|
91
81
|
};
|
|
92
82
|
}
|
|
93
|
-
const createDefaultTransaction = async (client, feePayer, computeLimit = MAX_COMPUTE_UNIT_LIMIT, feeMicroLamports = 1n) => {
|
|
94
|
-
const { value: latestBlockhash } = await client.rpc.getLatestBlockhash().send();
|
|
95
|
-
return pipe(createTransactionMessage({ version: 0 }), tx => setTransactionMessageFeePayerSigner(feePayer, tx), tx => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), tx => updateOrAppendSetComputeUnitPriceInstruction(feeMicroLamports, tx), tx => updateOrAppendSetComputeUnitLimitInstruction(computeLimit, tx));
|
|
96
|
-
};
|
|
97
|
-
const signAndSendTransaction = async (client, transactionMessage, commitment) => {
|
|
98
|
-
const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);
|
|
99
|
-
const signature = getSignatureFromTransaction(signedTransaction);
|
|
100
|
-
assertIsSendableTransaction(signedTransaction);
|
|
101
|
-
assertIsTransactionWithBlockhashLifetime(signedTransaction);
|
|
102
|
-
await sendAndConfirmTransactionFactory(client)(signedTransaction, { commitment, skipPreflight: true });
|
|
103
|
-
return signature;
|
|
104
|
-
};
|
|
105
|
-
function safeStringify(obj) {
|
|
106
|
-
return JSON.stringify(obj, (key, value) => {
|
|
107
|
-
if (typeof value === 'bigint') {
|
|
108
|
-
return value.toString();
|
|
109
|
-
}
|
|
110
|
-
return value;
|
|
111
|
-
}, 2);
|
|
112
|
-
}
|
|
113
|
-
async function sendAndConfirmInstructions(client, payer, instructions, description, commitment = loadEnvironmentVariables().commitment) {
|
|
114
|
-
try {
|
|
115
|
-
const signature = await pipe(await createDefaultTransaction(client, payer, 200_000), tx => appendTransactionMessageInstructions(instructions, tx), tx => signAndSendTransaction(client, tx, commitment));
|
|
116
|
-
return signature;
|
|
117
|
-
}
|
|
118
|
-
catch (error) {
|
|
119
|
-
console.error(safeStringify(error));
|
|
120
|
-
throw new Error(`Failed to ${description.toLowerCase()}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
async function initializeToken({ client, mintAuthority, payer, owner, mint, dropAmount, decimals, otherAtaWallets, }) {
|
|
124
|
-
// Get Owner ATA
|
|
125
|
-
const [ata] = await findAssociatedTokenPda({
|
|
126
|
-
mint: mint.address,
|
|
127
|
-
owner: owner.address,
|
|
128
|
-
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
129
|
-
});
|
|
130
|
-
// Get Mint size & rent
|
|
131
|
-
const mintSpace = BigInt(getMintSize());
|
|
132
|
-
const mintRent = await client.rpc.getMinimumBalanceForRentExemption(mintSpace).send();
|
|
133
|
-
// Create instructions for new token mint
|
|
134
|
-
const baseInstructions = [
|
|
135
|
-
// Create the Mint Account
|
|
136
|
-
getCreateAccountInstruction({
|
|
137
|
-
lamports: mintRent,
|
|
138
|
-
newAccount: mint,
|
|
139
|
-
payer,
|
|
140
|
-
programAddress: TOKEN_PROGRAM_ADDRESS,
|
|
141
|
-
space: mintSpace,
|
|
142
|
-
}),
|
|
143
|
-
// Initialize the Mint
|
|
144
|
-
getInitializeMintInstruction({
|
|
145
|
-
decimals,
|
|
146
|
-
mint: mint.address,
|
|
147
|
-
mintAuthority: mintAuthority.address,
|
|
148
|
-
}),
|
|
149
|
-
// Create Associated Token Account
|
|
150
|
-
await getCreateAssociatedTokenIdempotentInstructionAsync({
|
|
151
|
-
mint: mint.address,
|
|
152
|
-
owner: owner.address,
|
|
153
|
-
payer,
|
|
154
|
-
}),
|
|
155
|
-
// Mint To the Destination Associated Token Account
|
|
156
|
-
getMintToInstruction({
|
|
157
|
-
amount: BigInt(dropAmount * 10 ** decimals),
|
|
158
|
-
mint: mint.address,
|
|
159
|
-
mintAuthority,
|
|
160
|
-
token: ata,
|
|
161
|
-
}),
|
|
162
|
-
];
|
|
163
|
-
// Generate Create ATA instructions for other token accounts we wish to add
|
|
164
|
-
const otherAtaInstructions = otherAtaWallets
|
|
165
|
-
? await Promise.all(otherAtaWallets.map(async (wallet) => await getCreateAssociatedTokenIdempotentInstructionAsync({
|
|
166
|
-
mint: mint.address,
|
|
167
|
-
owner: wallet,
|
|
168
|
-
payer,
|
|
169
|
-
})))
|
|
170
|
-
: [];
|
|
171
|
-
const alreadyExists = await mintExists(client, mint.address);
|
|
172
|
-
const instructions = alreadyExists ? [...otherAtaInstructions] : [...baseInstructions, ...otherAtaInstructions];
|
|
173
|
-
await sendAndConfirmInstructions(client, payer, instructions, 'Initialize token and ATAs', 'finalized');
|
|
174
|
-
}
|
|
175
83
|
async function setupTestSuite() {
|
|
176
|
-
const { koraAddress, koraRpcUrl, tokenDecimals, tokenDropAmount, solDropAmount
|
|
177
|
-
// Load auth config from environment if not provided
|
|
84
|
+
const { koraAddress, koraRpcUrl, tokenDecimals, tokenDropAmount, solDropAmount } = loadEnvironmentVariables();
|
|
178
85
|
const authConfig = process.env.ENABLE_AUTH === 'true'
|
|
179
86
|
? {
|
|
180
87
|
apiKey: process.env.KORA_API_KEY || 'test-api-key-123',
|
|
181
88
|
hmacSecret: process.env.KORA_HMAC_SECRET || 'test-hmac-secret-456',
|
|
182
89
|
}
|
|
183
90
|
: undefined;
|
|
184
|
-
// Create Solana client
|
|
185
|
-
const rpc = createSolanaRpc(solanaRpcUrl);
|
|
186
|
-
const rpcSubscriptions = createSolanaRpcSubscriptions(solanaWsUrl);
|
|
187
|
-
const airdrop = airdropFactory({ rpc, rpcSubscriptions });
|
|
188
|
-
const client = { rpc, rpcSubscriptions };
|
|
189
|
-
// Get or create keypairs
|
|
190
91
|
const { testWallet, usdcMint, destinationAddress } = await createKeyPairSigners();
|
|
191
|
-
const
|
|
192
|
-
// Airdrop SOL
|
|
193
|
-
await
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
92
|
+
const client = await createClient({ payer: testWallet }).use(tokenProgram()).use(associatedTokenProgram());
|
|
93
|
+
// Airdrop SOL via LiteSVM
|
|
94
|
+
await client.airdrop(koraAddress, lamports(solDropAmount));
|
|
95
|
+
await client.airdrop(testWallet.address, lamports(solDropAmount));
|
|
96
|
+
// Create mint
|
|
97
|
+
await client.token.instructions
|
|
98
|
+
.createMint({
|
|
99
|
+
newMint: usdcMint,
|
|
100
|
+
decimals: tokenDecimals,
|
|
101
|
+
mintAuthority: testWallet.address,
|
|
102
|
+
})
|
|
103
|
+
.sendTransaction();
|
|
104
|
+
// Mint tokens to testWallet's ATA (auto-creates ATA)
|
|
105
|
+
await client.token.instructions
|
|
106
|
+
.mintToATA({
|
|
107
|
+
mint: usdcMint.address,
|
|
108
|
+
owner: testWallet.address,
|
|
109
|
+
mintAuthority: testWallet,
|
|
110
|
+
amount: BigInt(tokenDropAmount * 10 ** tokenDecimals),
|
|
208
111
|
decimals: tokenDecimals,
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
112
|
+
})
|
|
113
|
+
.sendTransaction();
|
|
114
|
+
// Create ATAs for kora and destination wallets
|
|
115
|
+
for (const owner of [koraAddress, destinationAddress]) {
|
|
116
|
+
await client.associatedToken.instructions
|
|
117
|
+
.createAssociatedTokenIdempotent({
|
|
118
|
+
owner,
|
|
119
|
+
mint: usdcMint.address,
|
|
120
|
+
})
|
|
121
|
+
.sendTransaction();
|
|
122
|
+
}
|
|
216
123
|
return {
|
|
217
124
|
destinationAddress,
|
|
218
125
|
koraAddress,
|
|
@@ -222,13 +129,4 @@ async function setupTestSuite() {
|
|
|
222
129
|
usdcMint: usdcMint.address,
|
|
223
130
|
};
|
|
224
131
|
}
|
|
225
|
-
const mintExists = async (client, mint) => {
|
|
226
|
-
try {
|
|
227
|
-
const mintAccount = await client.rpc.getAccountInfo(mint).send();
|
|
228
|
-
return mintAccount.value !== null;
|
|
229
|
-
}
|
|
230
|
-
catch {
|
|
231
|
-
return false;
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
132
|
export default setupTestSuite;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solana/kora",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.6",
|
|
4
4
|
"description": "TypeScript SDK for Kora RPC",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -16,31 +16,42 @@
|
|
|
16
16
|
],
|
|
17
17
|
"author": "",
|
|
18
18
|
"license": "MIT",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/solana-foundation/kora",
|
|
22
|
+
"directory": "sdks/ts"
|
|
23
|
+
},
|
|
19
24
|
"peerDependencies": {
|
|
20
|
-
"@solana-program/
|
|
21
|
-
"@solana/
|
|
25
|
+
"@solana-program/compute-budget": "^0.15.0",
|
|
26
|
+
"@solana-program/token": "^0.12.0",
|
|
27
|
+
"@solana/kit": "^6.3.0",
|
|
28
|
+
"@solana/kit-plugin-instruction-plan": "^0.7.0",
|
|
29
|
+
"@solana/kit-plugin-payer": "^0.6.0",
|
|
30
|
+
"@solana/kit-plugin-rpc": "^0.7.0"
|
|
22
31
|
},
|
|
23
32
|
"devDependencies": {
|
|
24
|
-
"@
|
|
25
|
-
"@solana-program/system": "^0.
|
|
26
|
-
"@solana-
|
|
27
|
-
"@solana/
|
|
28
|
-
"@solana/kit": "^5.4.0",
|
|
33
|
+
"@eslint/js": "^9.39.3",
|
|
34
|
+
"@solana-program/system": "^0.12.0",
|
|
35
|
+
"@solana/eslint-config-solana": "6.0.0",
|
|
36
|
+
"@solana/kit-client-litesvm": "^0.7.0",
|
|
29
37
|
"@solana/prettier-config-solana": "^0.0.6",
|
|
30
38
|
"@types/jest": "^29.5.12",
|
|
31
39
|
"@types/node": "^20.17.27",
|
|
32
|
-
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
|
33
|
-
"@typescript-eslint/parser": "^8.38.0",
|
|
34
40
|
"dotenv": "^16.4.5",
|
|
35
|
-
"eslint": "^9.
|
|
41
|
+
"eslint": "^9.39.3",
|
|
42
|
+
"eslint-plugin-jest": "^29.15.0",
|
|
43
|
+
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
44
|
+
"eslint-plugin-sort-keys-fix": "^1.1.2",
|
|
45
|
+
"eslint-plugin-typescript-sort-keys": "^3.3.0",
|
|
46
|
+
"globals": "^16.5.0",
|
|
36
47
|
"jest": "^29.7.0",
|
|
37
48
|
"prettier": "^3.2.5",
|
|
38
49
|
"ts-jest": "^29.1.2",
|
|
39
50
|
"ts-node": "^10.9.2",
|
|
40
51
|
"typedoc": "^0.28.9",
|
|
41
52
|
"typedoc-plugin-markdown": "^4.8.0",
|
|
42
|
-
"typescript": "^5.
|
|
43
|
-
"
|
|
53
|
+
"typescript": "^5.9.3",
|
|
54
|
+
"typescript-eslint": "^8.56.1"
|
|
44
55
|
},
|
|
45
56
|
"scripts": {
|
|
46
57
|
"build": "tsc",
|
|
@@ -50,13 +61,12 @@
|
|
|
50
61
|
"test:coverage": "jest --coverage",
|
|
51
62
|
"test:integration": "pnpm test integration.test.ts",
|
|
52
63
|
"test:integration:auth": "ENABLE_AUTH=true pnpm test integration.test.ts",
|
|
64
|
+
"test:integration:free": "FREE_PRICING=true pnpm test integration.test.ts",
|
|
53
65
|
"test:integration:privy": "KORA_SIGNER_TYPE=privy pnpm test integration.test.ts",
|
|
54
66
|
"test:integration:turnkey": "KORA_SIGNER_TYPE=turnkey pnpm test integration.test.ts",
|
|
55
67
|
"test:unit": "pnpm test unit.test.ts",
|
|
56
|
-
"test:ci:integration": "node scripts/test-with-validator.js",
|
|
57
|
-
"test:ci:integration:auth": "ENABLE_AUTH=true node scripts/test-with-validator.js",
|
|
58
68
|
"test:ci:unit": "jest test/unit.test.ts",
|
|
59
|
-
"lint": "eslint src
|
|
69
|
+
"lint": "eslint src/",
|
|
60
70
|
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
61
71
|
"format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
62
72
|
"type-check": "tsc --noEmit",
|