@thru/thru-sdk 0.1.19 → 0.1.21
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/README.md +19 -0
- package/dist/{chunk-PH7P5EEU.js → chunk-SHMREHP5.js} +13 -9
- package/dist/chunk-SHMREHP5.js.map +1 -0
- package/dist/client.d.ts +2 -1
- package/dist/client.js +3 -2
- package/dist/client.js.map +1 -1
- package/dist/metafile-esm.json +1 -1
- package/dist/sdk.d.ts +3 -3
- package/dist/sdk.js +1 -1
- package/dist/{transactions-BzD9hYlc.d.ts → transactions-CLezIeXO.d.ts} +20 -18
- package/package.json +7 -3
- package/buf.gen.yaml +0 -12
- package/buf.lock +0 -9
- package/buf.yaml +0 -15
- package/dist/chunk-PH7P5EEU.js.map +0 -1
- package/proto/thru/common/v1/consensus.proto +0 -73
- package/proto/thru/common/v1/errors.proto +0 -65
- package/proto/thru/common/v1/filters.proto +0 -60
- package/proto/thru/common/v1/pagination.proto +0 -45
- package/proto/thru/core/v1/account.proto +0 -137
- package/proto/thru/core/v1/block.proto +0 -80
- package/proto/thru/core/v1/state.proto +0 -35
- package/proto/thru/core/v1/transaction.proto +0 -136
- package/proto/thru/core/v1/types.proto +0 -50
- package/proto/thru/services/v1/command_service.proto +0 -70
- package/proto/thru/services/v1/query_service.proto +0 -344
- package/proto/thru/services/v1/streaming_service.proto +0 -126
- package/thru-ts-client-sdk/__tests__/helpers/test-utils.ts +0 -228
- package/thru-ts-client-sdk/client.ts +0 -10
- package/thru-ts-client-sdk/core/__tests__/bound-client.test.ts +0 -354
- package/thru-ts-client-sdk/core/__tests__/client.test.ts +0 -53
- package/thru-ts-client-sdk/core/bound-client.ts +0 -156
- package/thru-ts-client-sdk/core/client.ts +0 -38
- package/thru-ts-client-sdk/defaults.ts +0 -26
- package/thru-ts-client-sdk/modules/__tests__/accounts.test.ts +0 -406
- package/thru-ts-client-sdk/modules/__tests__/blocks.test.ts +0 -199
- package/thru-ts-client-sdk/modules/__tests__/events.test.ts +0 -74
- package/thru-ts-client-sdk/modules/__tests__/height.test.ts +0 -39
- package/thru-ts-client-sdk/modules/__tests__/helpers.test.ts +0 -288
- package/thru-ts-client-sdk/modules/__tests__/keys.test.ts +0 -55
- package/thru-ts-client-sdk/modules/__tests__/proofs.test.ts +0 -119
- package/thru-ts-client-sdk/modules/__tests__/streaming.test.ts +0 -152
- package/thru-ts-client-sdk/modules/__tests__/transactions.test.ts +0 -730
- package/thru-ts-client-sdk/modules/__tests__/version.test.ts +0 -40
- package/thru-ts-client-sdk/modules/accounts.ts +0 -141
- package/thru-ts-client-sdk/modules/blocks.ts +0 -75
- package/thru-ts-client-sdk/modules/events.ts +0 -20
- package/thru-ts-client-sdk/modules/height.ts +0 -9
- package/thru-ts-client-sdk/modules/helpers.ts +0 -131
- package/thru-ts-client-sdk/modules/keys.ts +0 -29
- package/thru-ts-client-sdk/modules/proofs.ts +0 -20
- package/thru-ts-client-sdk/modules/streaming.ts +0 -133
- package/thru-ts-client-sdk/modules/transactions.ts +0 -374
- package/thru-ts-client-sdk/modules/version.ts +0 -10
- package/thru-ts-client-sdk/proto/buf/validate/validate_pb.ts +0 -4761
- package/thru-ts-client-sdk/proto/google/api/annotations_pb.ts +0 -39
- package/thru-ts-client-sdk/proto/google/api/client_pb.ts +0 -953
- package/thru-ts-client-sdk/proto/google/api/field_behavior_pb.ts +0 -157
- package/thru-ts-client-sdk/proto/google/api/http_pb.ts +0 -474
- package/thru-ts-client-sdk/proto/google/api/launch_stage_pb.ts +0 -118
- package/thru-ts-client-sdk/proto/thru/common/v1/consensus_pb.ts +0 -162
- package/thru-ts-client-sdk/proto/thru/common/v1/errors_pb.ts +0 -129
- package/thru-ts-client-sdk/proto/thru/common/v1/filters_pb.ts +0 -129
- package/thru-ts-client-sdk/proto/thru/common/v1/pagination_pb.ts +0 -79
- package/thru-ts-client-sdk/proto/thru/core/v1/account_pb.ts +0 -359
- package/thru-ts-client-sdk/proto/thru/core/v1/block_pb.ts +0 -259
- package/thru-ts-client-sdk/proto/thru/core/v1/state_pb.ts +0 -103
- package/thru-ts-client-sdk/proto/thru/core/v1/transaction_pb.ts +0 -528
- package/thru-ts-client-sdk/proto/thru/core/v1/types_pb.ts +0 -100
- package/thru-ts-client-sdk/proto/thru/services/v1/command_service_pb.ts +0 -146
- package/thru-ts-client-sdk/proto/thru/services/v1/query_service_pb.ts +0 -819
- package/thru-ts-client-sdk/proto/thru/services/v1/streaming_service_pb.ts +0 -390
- package/thru-ts-client-sdk/sdk.ts +0 -42
- package/thru-ts-client-sdk/test-scripts/counter.ts +0 -469
- package/thru-ts-client-sdk/test-scripts/create-account.ts +0 -74
- package/thru-ts-client-sdk/test-scripts/get-height.ts +0 -52
- package/thru-ts-client-sdk/transactions/Transaction.ts +0 -240
- package/thru-ts-client-sdk/transactions/TransactionBuilder.ts +0 -53
- package/thru-ts-client-sdk/transactions/__tests__/TransactionBuilder.test.ts +0 -411
- package/thru-ts-client-sdk/transactions/__tests__/utils.test.ts +0 -214
- package/thru-ts-client-sdk/transactions/index.ts +0 -3
- package/thru-ts-client-sdk/transactions/types.ts +0 -74
- package/thru-ts-client-sdk/transactions/utils.ts +0 -132
- package/thru-ts-client-sdk/types/types.ts +0 -8
- package/thru-ts-client-sdk/utils/utils.ts +0 -27
- package/tsconfig.json +0 -9
- package/tsup.config.ts +0 -14
- package/vitest.config.ts +0 -31
|
@@ -1,730 +0,0 @@
|
|
|
1
|
-
import { create } from "@bufbuild/protobuf";
|
|
2
|
-
import { describe, expect, it, vi } from "vitest";
|
|
3
|
-
import {
|
|
4
|
-
createMockAccount,
|
|
5
|
-
createMockContext,
|
|
6
|
-
createMockHeightResponse,
|
|
7
|
-
generateTestAddress,
|
|
8
|
-
generateTestPubkey,
|
|
9
|
-
generateTestSignature,
|
|
10
|
-
generateTestSignatureString,
|
|
11
|
-
} from "../../__tests__/helpers/test-utils";
|
|
12
|
-
import { ConsensusStatus } from "../../proto/thru/common/v1/consensus_pb";
|
|
13
|
-
import { FilterSchema } from "../../proto/thru/common/v1/filters_pb";
|
|
14
|
-
import { PageRequestSchema } from "../../proto/thru/common/v1/pagination_pb";
|
|
15
|
-
import { TransactionSchema, TransactionView } from "../../proto/thru/core/v1/transaction_pb";
|
|
16
|
-
import { TransactionStatusSchema } from "../../proto/thru/services/v1/query_service_pb";
|
|
17
|
-
import { Transaction } from "../../transactions/Transaction";
|
|
18
|
-
import {
|
|
19
|
-
batchSendTransactions,
|
|
20
|
-
buildAndSignTransaction,
|
|
21
|
-
buildTransaction,
|
|
22
|
-
getRawTransaction,
|
|
23
|
-
getTransaction,
|
|
24
|
-
getTransactionStatus,
|
|
25
|
-
listTransactionsForAccount,
|
|
26
|
-
sendTransaction,
|
|
27
|
-
} from "../transactions";
|
|
28
|
-
|
|
29
|
-
describe("transactions", () => {
|
|
30
|
-
describe("getTransaction", () => {
|
|
31
|
-
it("should return transaction with valid signature", async () => {
|
|
32
|
-
const ctx = createMockContext();
|
|
33
|
-
const mockTransaction = create(TransactionSchema, {
|
|
34
|
-
signature: { value: generateTestSignature() },
|
|
35
|
-
});
|
|
36
|
-
vi.spyOn(ctx.query, "getTransaction").mockResolvedValue(mockTransaction);
|
|
37
|
-
|
|
38
|
-
const signature = generateTestSignature();
|
|
39
|
-
const result = await getTransaction(ctx, signature);
|
|
40
|
-
|
|
41
|
-
expect(result).toBe(mockTransaction);
|
|
42
|
-
expect(ctx.query.getTransaction).toHaveBeenCalledTimes(1);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("should accept signature as Uint8Array", async () => {
|
|
46
|
-
const ctx = createMockContext();
|
|
47
|
-
const mockTransaction = create(TransactionSchema, {});
|
|
48
|
-
vi.spyOn(ctx.query, "getTransaction").mockResolvedValue(mockTransaction);
|
|
49
|
-
|
|
50
|
-
const signature = generateTestSignature();
|
|
51
|
-
await getTransaction(ctx, signature);
|
|
52
|
-
|
|
53
|
-
const callArgs = (ctx.query.getTransaction as any).mock.calls[0][0];
|
|
54
|
-
expect(callArgs.signature.value).toEqual(signature);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it("should accept signature as string", async () => {
|
|
58
|
-
const ctx = createMockContext();
|
|
59
|
-
const mockTransaction = create(TransactionSchema, {});
|
|
60
|
-
vi.spyOn(ctx.query, "getTransaction").mockResolvedValue(mockTransaction);
|
|
61
|
-
|
|
62
|
-
const signatureString = generateTestSignatureString();
|
|
63
|
-
await getTransaction(ctx, signatureString);
|
|
64
|
-
|
|
65
|
-
const callArgs = (ctx.query.getTransaction as any).mock.calls[0][0];
|
|
66
|
-
expect(callArgs.signature.value.length).toBe(64);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("should use default view when not provided", async () => {
|
|
70
|
-
const ctx = createMockContext();
|
|
71
|
-
const mockTransaction = create(TransactionSchema, {});
|
|
72
|
-
vi.spyOn(ctx.query, "getTransaction").mockResolvedValue(mockTransaction);
|
|
73
|
-
|
|
74
|
-
await getTransaction(ctx, generateTestSignature());
|
|
75
|
-
|
|
76
|
-
const callArgs = (ctx.query.getTransaction as any).mock.calls[0][0];
|
|
77
|
-
expect(callArgs.view).toBe(TransactionView.FULL);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("should use custom view when provided", async () => {
|
|
81
|
-
const ctx = createMockContext();
|
|
82
|
-
const mockTransaction = create(TransactionSchema, {});
|
|
83
|
-
vi.spyOn(ctx.query, "getTransaction").mockResolvedValue(mockTransaction);
|
|
84
|
-
|
|
85
|
-
await getTransaction(ctx, generateTestSignature(), { view: TransactionView.SIGNATURE_ONLY });
|
|
86
|
-
|
|
87
|
-
const callArgs = (ctx.query.getTransaction as any).mock.calls[0][0];
|
|
88
|
-
expect(callArgs.view).toBe(TransactionView.SIGNATURE_ONLY);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("should use default minConsensus", async () => {
|
|
92
|
-
const ctx = createMockContext();
|
|
93
|
-
const mockTransaction = create(TransactionSchema, {});
|
|
94
|
-
vi.spyOn(ctx.query, "getTransaction").mockResolvedValue(mockTransaction);
|
|
95
|
-
|
|
96
|
-
await getTransaction(ctx, generateTestSignature());
|
|
97
|
-
|
|
98
|
-
const callArgs = (ctx.query.getTransaction as any).mock.calls[0][0];
|
|
99
|
-
expect(callArgs.minConsensus).toBe(ConsensusStatus.UNSPECIFIED);
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
describe("getRawTransaction", () => {
|
|
104
|
-
it("should return raw transaction", async () => {
|
|
105
|
-
const ctx = createMockContext();
|
|
106
|
-
const mockRawTransaction = {
|
|
107
|
-
signature: { value: generateTestSignature() },
|
|
108
|
-
rawTransaction: new Uint8Array([1, 2, 3]),
|
|
109
|
-
};
|
|
110
|
-
vi.spyOn(ctx.query, "getRawTransaction").mockResolvedValue(mockRawTransaction as any);
|
|
111
|
-
|
|
112
|
-
const signature = generateTestSignature();
|
|
113
|
-
const result = await getRawTransaction(ctx, signature);
|
|
114
|
-
|
|
115
|
-
expect(result).toBe(mockRawTransaction);
|
|
116
|
-
expect(ctx.query.getRawTransaction).toHaveBeenCalledTimes(1);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it("should use default version context and minConsensus", async () => {
|
|
120
|
-
const ctx = createMockContext();
|
|
121
|
-
const mockRawTransaction = { signature: { value: generateTestSignature() } };
|
|
122
|
-
vi.spyOn(ctx.query, "getRawTransaction").mockResolvedValue(mockRawTransaction as any);
|
|
123
|
-
|
|
124
|
-
await getRawTransaction(ctx, generateTestSignature());
|
|
125
|
-
|
|
126
|
-
const callArgs = (ctx.query.getRawTransaction as any).mock.calls[0][0];
|
|
127
|
-
expect(callArgs.versionContext).toBeDefined();
|
|
128
|
-
expect(callArgs.minConsensus).toBe(ConsensusStatus.UNSPECIFIED);
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
describe("getTransactionStatus", () => {
|
|
133
|
-
it("should return transaction status", async () => {
|
|
134
|
-
const ctx = createMockContext();
|
|
135
|
-
const mockStatus = create(TransactionStatusSchema, {
|
|
136
|
-
signature: { value: generateTestSignature() },
|
|
137
|
-
consensusStatus: ConsensusStatus.FINALIZED,
|
|
138
|
-
});
|
|
139
|
-
vi.spyOn(ctx.query, "getTransactionStatus").mockResolvedValue(mockStatus);
|
|
140
|
-
|
|
141
|
-
const signature = generateTestSignature();
|
|
142
|
-
const result = await getTransactionStatus(ctx, signature);
|
|
143
|
-
|
|
144
|
-
expect(result).toBe(mockStatus);
|
|
145
|
-
expect(ctx.query.getTransactionStatus).toHaveBeenCalledTimes(1);
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
describe("buildTransaction", () => {
|
|
150
|
-
it("should build transaction with minimal options", async () => {
|
|
151
|
-
const ctx = createMockContext();
|
|
152
|
-
const mockAccount = createMockAccount({
|
|
153
|
-
meta: { nonce: 5n },
|
|
154
|
-
});
|
|
155
|
-
const mockHeight = createMockHeightResponse({ finalized: 1000n });
|
|
156
|
-
|
|
157
|
-
vi.spyOn(ctx.query, "getAccount").mockResolvedValue(mockAccount);
|
|
158
|
-
vi.spyOn(ctx.query, "getHeight").mockResolvedValue(mockHeight);
|
|
159
|
-
|
|
160
|
-
const publicKey = generateTestPubkey(0x01);
|
|
161
|
-
const transaction = await buildTransaction(ctx, {
|
|
162
|
-
feePayer: { publicKey },
|
|
163
|
-
program: generateTestPubkey(0x02),
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
expect(transaction).toBeInstanceOf(Transaction);
|
|
167
|
-
expect(transaction.feePayer).toEqual(publicKey);
|
|
168
|
-
expect(transaction.nonce).toBe(5n);
|
|
169
|
-
expect(transaction.startSlot).toBe(1000n);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it("should use provided nonce instead of fetching", async () => {
|
|
173
|
-
const ctx = createMockContext();
|
|
174
|
-
const mockHeight = createMockHeightResponse({ finalized: 1000n });
|
|
175
|
-
vi.spyOn(ctx.query, "getHeight").mockResolvedValue(mockHeight);
|
|
176
|
-
|
|
177
|
-
const publicKey = generateTestPubkey(0x01);
|
|
178
|
-
const transaction = await buildTransaction(ctx, {
|
|
179
|
-
feePayer: { publicKey },
|
|
180
|
-
program: generateTestPubkey(0x02),
|
|
181
|
-
header: {
|
|
182
|
-
nonce: 10n,
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
expect(transaction.nonce).toBe(10n);
|
|
187
|
-
expect(ctx.query.getAccount).not.toHaveBeenCalled();
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
it("should use provided startSlot instead of fetching", async () => {
|
|
191
|
-
const ctx = createMockContext();
|
|
192
|
-
const mockAccount = createMockAccount({
|
|
193
|
-
meta: { nonce: 5n },
|
|
194
|
-
});
|
|
195
|
-
vi.spyOn(ctx.query, "getAccount").mockResolvedValue(mockAccount);
|
|
196
|
-
|
|
197
|
-
const publicKey = generateTestPubkey(0x01);
|
|
198
|
-
const transaction = await buildTransaction(ctx, {
|
|
199
|
-
feePayer: { publicKey },
|
|
200
|
-
program: generateTestPubkey(0x02),
|
|
201
|
-
header: {
|
|
202
|
-
startSlot: 2000n,
|
|
203
|
-
},
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
expect(transaction.startSlot).toBe(2000n);
|
|
207
|
-
expect(ctx.query.getHeight).not.toHaveBeenCalled();
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it("should use default header values when not provided", async () => {
|
|
211
|
-
const ctx = createMockContext();
|
|
212
|
-
const mockAccount = createMockAccount({
|
|
213
|
-
meta: { nonce: 5n },
|
|
214
|
-
});
|
|
215
|
-
const mockHeight = createMockHeightResponse({ finalized: 1000n });
|
|
216
|
-
|
|
217
|
-
vi.spyOn(ctx.query, "getAccount").mockResolvedValue(mockAccount);
|
|
218
|
-
vi.spyOn(ctx.query, "getHeight").mockResolvedValue(mockHeight);
|
|
219
|
-
|
|
220
|
-
const publicKey = generateTestPubkey(0x01);
|
|
221
|
-
const transaction = await buildTransaction(ctx, {
|
|
222
|
-
feePayer: { publicKey },
|
|
223
|
-
program: generateTestPubkey(0x02),
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
expect(transaction.fee).toBe(1n); // DEFAULT_FEE
|
|
227
|
-
expect(transaction.expiryAfter).toBe(100); // DEFAULT_EXPIRY_AFTER
|
|
228
|
-
expect(transaction.requestedComputeUnits).toBe(300_000_000); // DEFAULT_COMPUTE_UNITS
|
|
229
|
-
expect(transaction.requestedStateUnits).toBe(10_000); // DEFAULT_STATE_UNITS
|
|
230
|
-
expect(transaction.requestedMemoryUnits).toBe(10_000); // DEFAULT_MEMORY_UNITS
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
it("should accept program as string", async () => {
|
|
234
|
-
const ctx = createMockContext();
|
|
235
|
-
const mockAccount = createMockAccount({
|
|
236
|
-
meta: { nonce: 5n },
|
|
237
|
-
});
|
|
238
|
-
const mockHeight = createMockHeightResponse({ finalized: 1000n });
|
|
239
|
-
|
|
240
|
-
vi.spyOn(ctx.query, "getAccount").mockResolvedValue(mockAccount);
|
|
241
|
-
vi.spyOn(ctx.query, "getHeight").mockResolvedValue(mockHeight);
|
|
242
|
-
|
|
243
|
-
const publicKey = generateTestPubkey(0x01);
|
|
244
|
-
const programAddress = generateTestAddress(0x02);
|
|
245
|
-
const transaction = await buildTransaction(ctx, {
|
|
246
|
-
feePayer: { publicKey },
|
|
247
|
-
program: programAddress,
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
expect(transaction.program.length).toBe(32);
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
it("should throw error when account nonce is unavailable", async () => {
|
|
254
|
-
const ctx = createMockContext();
|
|
255
|
-
const mockHeight = createMockHeightResponse({ finalized: 1000n });
|
|
256
|
-
|
|
257
|
-
// Mock account with meta that has undefined nonce
|
|
258
|
-
// Since nonce is required in protobuf, we need to manually create an object
|
|
259
|
-
// that simulates the case where meta.nonce is undefined
|
|
260
|
-
const mockAccount = {
|
|
261
|
-
address: { value: generateTestPubkey(0x01) },
|
|
262
|
-
meta: {
|
|
263
|
-
version: 1,
|
|
264
|
-
flags: {},
|
|
265
|
-
dataSize: 0,
|
|
266
|
-
seq: 0n,
|
|
267
|
-
owner: { value: generateTestPubkey(0x02) },
|
|
268
|
-
balance: 0n,
|
|
269
|
-
// nonce is explicitly undefined
|
|
270
|
-
nonce: undefined,
|
|
271
|
-
},
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
vi.spyOn(ctx.query, "getAccount").mockResolvedValue(mockAccount as any);
|
|
275
|
-
vi.spyOn(ctx.query, "getHeight").mockResolvedValue(mockHeight);
|
|
276
|
-
|
|
277
|
-
const publicKey = generateTestPubkey(0x01);
|
|
278
|
-
|
|
279
|
-
await expect(
|
|
280
|
-
buildTransaction(ctx, {
|
|
281
|
-
feePayer: { publicKey },
|
|
282
|
-
program: generateTestPubkey(0x02),
|
|
283
|
-
})
|
|
284
|
-
).rejects.toThrow("Fee payer account nonce is unavailable");
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
it("should accept instruction data as Uint8Array", async () => {
|
|
288
|
-
const ctx = createMockContext();
|
|
289
|
-
const mockAccount = createMockAccount({
|
|
290
|
-
meta: { nonce: 5n },
|
|
291
|
-
});
|
|
292
|
-
const mockHeight = createMockHeightResponse({ finalized: 1000n });
|
|
293
|
-
|
|
294
|
-
vi.spyOn(ctx.query, "getAccount").mockResolvedValue(mockAccount);
|
|
295
|
-
vi.spyOn(ctx.query, "getHeight").mockResolvedValue(mockHeight);
|
|
296
|
-
|
|
297
|
-
const instructionData = new Uint8Array([0x01, 0x02, 0x03]);
|
|
298
|
-
const transaction = await buildTransaction(ctx, {
|
|
299
|
-
feePayer: { publicKey: generateTestPubkey(0x01) },
|
|
300
|
-
program: generateTestPubkey(0x02),
|
|
301
|
-
instructionData,
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
expect(transaction.instructionData).toEqual(instructionData);
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
it("should accept instruction data as function", async () => {
|
|
308
|
-
const ctx = createMockContext();
|
|
309
|
-
const mockAccount = createMockAccount({
|
|
310
|
-
meta: { nonce: 5n },
|
|
311
|
-
});
|
|
312
|
-
const mockHeight = createMockHeightResponse({ finalized: 1000n });
|
|
313
|
-
|
|
314
|
-
vi.spyOn(ctx.query, "getAccount").mockResolvedValue(mockAccount);
|
|
315
|
-
vi.spyOn(ctx.query, "getHeight").mockResolvedValue(mockHeight);
|
|
316
|
-
|
|
317
|
-
const instructionDataFn = (context: any) => {
|
|
318
|
-
// Function that uses context to generate instruction data
|
|
319
|
-
return new Uint8Array([context.accounts.length]);
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
const transaction = await buildTransaction(ctx, {
|
|
323
|
-
feePayer: { publicKey: generateTestPubkey(0x01) },
|
|
324
|
-
program: generateTestPubkey(0x02),
|
|
325
|
-
instructionData: instructionDataFn,
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
expect(transaction.instructionData).toBeDefined();
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
it("should build transaction with instructionData function using context builder", async () => {
|
|
332
|
-
const ctx = createMockContext();
|
|
333
|
-
const mockAccount = createMockAccount({
|
|
334
|
-
meta: { nonce: 5n },
|
|
335
|
-
});
|
|
336
|
-
const mockHeight = createMockHeightResponse({ finalized: 1000n });
|
|
337
|
-
|
|
338
|
-
vi.spyOn(ctx.query, "getAccount").mockResolvedValue(mockAccount);
|
|
339
|
-
vi.spyOn(ctx.query, "getHeight").mockResolvedValue(mockHeight);
|
|
340
|
-
|
|
341
|
-
const feePayer = generateTestPubkey(0x01);
|
|
342
|
-
const program = generateTestPubkey(0x02);
|
|
343
|
-
const readWriteAccount1 = generateTestPubkey(0x03);
|
|
344
|
-
const readWriteAccount2 = generateTestPubkey(0x04);
|
|
345
|
-
const readOnlyAccount = generateTestPubkey(0x05);
|
|
346
|
-
|
|
347
|
-
// Instruction data function that uses the context to:
|
|
348
|
-
// 1. Access the accounts array
|
|
349
|
-
// 2. Use getAccountIndex to find account positions
|
|
350
|
-
// 3. Build instruction data with account indices
|
|
351
|
-
const instructionDataFn = (context: {
|
|
352
|
-
accounts: Uint8Array[];
|
|
353
|
-
getAccountIndex: (pubkey: Uint8Array) => number;
|
|
354
|
-
}) => {
|
|
355
|
-
// Verify context has all accounts in correct order
|
|
356
|
-
expect(context.accounts.length).toBe(5); // feePayer, program, 2 readWrite, 1 readOnly
|
|
357
|
-
expect(context.accounts[0]).toEqual(feePayer);
|
|
358
|
-
expect(context.accounts[1]).toEqual(program);
|
|
359
|
-
expect(context.accounts[2]).toEqual(readWriteAccount1);
|
|
360
|
-
expect(context.accounts[3]).toEqual(readWriteAccount2);
|
|
361
|
-
expect(context.accounts[4]).toEqual(readOnlyAccount);
|
|
362
|
-
|
|
363
|
-
// Use getAccountIndex to find account positions
|
|
364
|
-
const feePayerIndex = context.getAccountIndex(feePayer);
|
|
365
|
-
const programIndex = context.getAccountIndex(program);
|
|
366
|
-
const readWrite1Index = context.getAccountIndex(readWriteAccount1);
|
|
367
|
-
const readOnlyIndex = context.getAccountIndex(readOnlyAccount);
|
|
368
|
-
|
|
369
|
-
// Verify indices are correct
|
|
370
|
-
expect(feePayerIndex).toBe(0);
|
|
371
|
-
expect(programIndex).toBe(1);
|
|
372
|
-
expect(readWrite1Index).toBe(2);
|
|
373
|
-
expect(readOnlyIndex).toBe(4);
|
|
374
|
-
|
|
375
|
-
// Build instruction data using account indices (common pattern)
|
|
376
|
-
// Example: [instructionDiscriminator, accountIndex1, accountIndex2, ...]
|
|
377
|
-
const instructionData = new Uint8Array([
|
|
378
|
-
0x42, // instruction discriminator
|
|
379
|
-
feePayerIndex,
|
|
380
|
-
programIndex,
|
|
381
|
-
readWrite1Index,
|
|
382
|
-
readOnlyIndex,
|
|
383
|
-
]);
|
|
384
|
-
|
|
385
|
-
return instructionData;
|
|
386
|
-
};
|
|
387
|
-
|
|
388
|
-
const transaction = await buildTransaction(ctx, {
|
|
389
|
-
feePayer: { publicKey: feePayer },
|
|
390
|
-
program,
|
|
391
|
-
accounts: {
|
|
392
|
-
readWrite: [readWriteAccount1, readWriteAccount2],
|
|
393
|
-
readOnly: [readOnlyAccount],
|
|
394
|
-
},
|
|
395
|
-
instructionData: instructionDataFn,
|
|
396
|
-
});
|
|
397
|
-
|
|
398
|
-
expect(transaction.instructionData).toBeDefined();
|
|
399
|
-
expect(transaction.instructionData!.length).toBe(5);
|
|
400
|
-
expect(transaction.instructionData![0]).toBe(0x42); // discriminator
|
|
401
|
-
expect(transaction.instructionData![1]).toBe(0); // feePayer index
|
|
402
|
-
expect(transaction.instructionData![2]).toBe(1); // program index
|
|
403
|
-
expect(transaction.instructionData![3]).toBe(2); // readWrite1 index
|
|
404
|
-
expect(transaction.instructionData![4]).toBe(4); // readOnly index
|
|
405
|
-
|
|
406
|
-
// Verify accounts are in the transaction
|
|
407
|
-
expect(transaction.readWriteAccounts).toHaveLength(2);
|
|
408
|
-
expect(transaction.readOnlyAccounts).toHaveLength(1);
|
|
409
|
-
});
|
|
410
|
-
|
|
411
|
-
it("should throw error in instructionData function when account not found via getAccountIndex", async () => {
|
|
412
|
-
const ctx = createMockContext();
|
|
413
|
-
const mockAccount = createMockAccount({
|
|
414
|
-
meta: { nonce: 5n },
|
|
415
|
-
});
|
|
416
|
-
const mockHeight = createMockHeightResponse({ finalized: 1000n });
|
|
417
|
-
|
|
418
|
-
vi.spyOn(ctx.query, "getAccount").mockResolvedValue(mockAccount);
|
|
419
|
-
vi.spyOn(ctx.query, "getHeight").mockResolvedValue(mockHeight);
|
|
420
|
-
|
|
421
|
-
const feePayer = generateTestPubkey(0x01);
|
|
422
|
-
const program = generateTestPubkey(0x02);
|
|
423
|
-
const unknownAccount = generateTestPubkey(0x99); // Not in transaction accounts
|
|
424
|
-
|
|
425
|
-
const instructionDataFn = (context: {
|
|
426
|
-
accounts: Uint8Array[];
|
|
427
|
-
getAccountIndex: (pubkey: Uint8Array) => number;
|
|
428
|
-
}) => {
|
|
429
|
-
// Try to get index of an account not in the transaction
|
|
430
|
-
expect(() => context.getAccountIndex(unknownAccount)).toThrow(
|
|
431
|
-
"Account not found in transaction accounts"
|
|
432
|
-
);
|
|
433
|
-
return new Uint8Array([0x01]);
|
|
434
|
-
};
|
|
435
|
-
|
|
436
|
-
const transaction = await buildTransaction(ctx, {
|
|
437
|
-
feePayer: { publicKey: feePayer },
|
|
438
|
-
program,
|
|
439
|
-
instructionData: instructionDataFn,
|
|
440
|
-
});
|
|
441
|
-
|
|
442
|
-
expect(transaction.instructionData).toBeDefined();
|
|
443
|
-
});
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
describe("buildAndSignTransaction", () => {
|
|
447
|
-
it("should build and sign transaction", async () => {
|
|
448
|
-
const ctx = createMockContext();
|
|
449
|
-
const mockAccount = createMockAccount({
|
|
450
|
-
meta: { nonce: 5n },
|
|
451
|
-
});
|
|
452
|
-
const mockHeight = createMockHeightResponse({ finalized: 1000n });
|
|
453
|
-
|
|
454
|
-
vi.spyOn(ctx.query, "getAccount").mockResolvedValue(mockAccount);
|
|
455
|
-
vi.spyOn(ctx.query, "getHeight").mockResolvedValue(mockHeight);
|
|
456
|
-
|
|
457
|
-
const publicKey = generateTestPubkey(0x01);
|
|
458
|
-
const privateKey = new Uint8Array(32);
|
|
459
|
-
privateKey.fill(0x42);
|
|
460
|
-
|
|
461
|
-
const result = await buildAndSignTransaction(ctx, {
|
|
462
|
-
feePayer: {
|
|
463
|
-
publicKey,
|
|
464
|
-
privateKey,
|
|
465
|
-
},
|
|
466
|
-
program: generateTestPubkey(0x02),
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
expect(result.transaction).toBeInstanceOf(Transaction);
|
|
470
|
-
expect(result.signature.length).toBe(64);
|
|
471
|
-
expect(result.rawTransaction.length).toBeGreaterThan(0);
|
|
472
|
-
});
|
|
473
|
-
|
|
474
|
-
it("should throw error when private key is missing", async () => {
|
|
475
|
-
const ctx = createMockContext();
|
|
476
|
-
const mockAccount = createMockAccount({
|
|
477
|
-
meta: { nonce: 5n },
|
|
478
|
-
});
|
|
479
|
-
const mockHeight = createMockHeightResponse({ finalized: 1000n });
|
|
480
|
-
|
|
481
|
-
vi.spyOn(ctx.query, "getAccount").mockResolvedValue(mockAccount);
|
|
482
|
-
vi.spyOn(ctx.query, "getHeight").mockResolvedValue(mockHeight);
|
|
483
|
-
|
|
484
|
-
const publicKey = generateTestPubkey(0x01);
|
|
485
|
-
|
|
486
|
-
await expect(
|
|
487
|
-
buildAndSignTransaction(ctx, {
|
|
488
|
-
feePayer: {
|
|
489
|
-
publicKey,
|
|
490
|
-
// No privateKey
|
|
491
|
-
},
|
|
492
|
-
program: generateTestPubkey(0x02),
|
|
493
|
-
} as any)
|
|
494
|
-
).rejects.toThrow("Fee payer private key is required to sign the transaction");
|
|
495
|
-
});
|
|
496
|
-
});
|
|
497
|
-
|
|
498
|
-
describe("sendTransaction", () => {
|
|
499
|
-
it("should send transaction object", async () => {
|
|
500
|
-
const ctx = createMockContext();
|
|
501
|
-
const mockSignature = generateTestSignature();
|
|
502
|
-
const mockResponse = {
|
|
503
|
-
signature: { value: mockSignature },
|
|
504
|
-
};
|
|
505
|
-
vi.spyOn(ctx.command, "sendTransaction").mockResolvedValue(mockResponse as any);
|
|
506
|
-
|
|
507
|
-
const transaction = new Transaction({
|
|
508
|
-
feePayer: generateTestPubkey(0x01),
|
|
509
|
-
program: generateTestPubkey(0x02),
|
|
510
|
-
header: {
|
|
511
|
-
fee: 1n,
|
|
512
|
-
nonce: 2n,
|
|
513
|
-
startSlot: 3n,
|
|
514
|
-
},
|
|
515
|
-
});
|
|
516
|
-
|
|
517
|
-
const result = await sendTransaction(ctx, transaction);
|
|
518
|
-
|
|
519
|
-
expect(typeof result).toBe("string");
|
|
520
|
-
expect(result.startsWith("ts")).toBe(true);
|
|
521
|
-
expect(ctx.command.sendTransaction).toHaveBeenCalledTimes(1);
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
it("should send raw transaction bytes", async () => {
|
|
525
|
-
const ctx = createMockContext();
|
|
526
|
-
const mockSignature = generateTestSignature();
|
|
527
|
-
const mockResponse = {
|
|
528
|
-
signature: { value: mockSignature },
|
|
529
|
-
};
|
|
530
|
-
vi.spyOn(ctx.command, "sendTransaction").mockResolvedValue(mockResponse as any);
|
|
531
|
-
|
|
532
|
-
const rawTransaction = new Uint8Array([1, 2, 3, 4]);
|
|
533
|
-
const result = await sendTransaction(ctx, rawTransaction);
|
|
534
|
-
|
|
535
|
-
expect(typeof result).toBe("string");
|
|
536
|
-
expect(ctx.command.sendTransaction).toHaveBeenCalledTimes(1);
|
|
537
|
-
const callArgs = (ctx.command.sendTransaction as any).mock.calls[0][0];
|
|
538
|
-
expect(callArgs.rawTransaction).toEqual(rawTransaction);
|
|
539
|
-
});
|
|
540
|
-
|
|
541
|
-
it("should throw error when signature is missing from response", async () => {
|
|
542
|
-
const ctx = createMockContext();
|
|
543
|
-
const mockResponse = {
|
|
544
|
-
// No signature
|
|
545
|
-
};
|
|
546
|
-
vi.spyOn(ctx.command, "sendTransaction").mockResolvedValue(mockResponse as any);
|
|
547
|
-
|
|
548
|
-
const transaction = new Transaction({
|
|
549
|
-
feePayer: generateTestPubkey(0x01),
|
|
550
|
-
program: generateTestPubkey(0x02),
|
|
551
|
-
header: {
|
|
552
|
-
fee: 1n,
|
|
553
|
-
nonce: 2n,
|
|
554
|
-
startSlot: 3n,
|
|
555
|
-
},
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
await expect(sendTransaction(ctx, transaction)).rejects.toThrow(
|
|
559
|
-
"No signature returned from sendTransaction"
|
|
560
|
-
);
|
|
561
|
-
});
|
|
562
|
-
});
|
|
563
|
-
|
|
564
|
-
describe("listTransactionsForAccount", () => {
|
|
565
|
-
it("should list transactions for account", async () => {
|
|
566
|
-
const ctx = createMockContext();
|
|
567
|
-
const mockResponse = {
|
|
568
|
-
signatures: [
|
|
569
|
-
{ value: generateTestSignature(0x01) },
|
|
570
|
-
{ value: generateTestSignature(0x02) },
|
|
571
|
-
],
|
|
572
|
-
};
|
|
573
|
-
vi.spyOn(ctx.query, "listTransactionsForAccount").mockResolvedValue(mockResponse as any);
|
|
574
|
-
|
|
575
|
-
const account = generateTestPubkey();
|
|
576
|
-
const result = await listTransactionsForAccount(ctx, account);
|
|
577
|
-
|
|
578
|
-
expect(result).toBe(mockResponse);
|
|
579
|
-
expect(ctx.query.listTransactionsForAccount).toHaveBeenCalledTimes(1);
|
|
580
|
-
const callArgs = (ctx.query.listTransactionsForAccount as any).mock.calls[0][0];
|
|
581
|
-
expect(callArgs.account?.value).toEqual(account);
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
it("should accept account as Uint8Array", async () => {
|
|
585
|
-
const ctx = createMockContext();
|
|
586
|
-
const mockResponse = { signatures: [] };
|
|
587
|
-
vi.spyOn(ctx.query, "listTransactionsForAccount").mockResolvedValue(mockResponse as any);
|
|
588
|
-
|
|
589
|
-
const account = generateTestPubkey();
|
|
590
|
-
await listTransactionsForAccount(ctx, account);
|
|
591
|
-
|
|
592
|
-
const callArgs = (ctx.query.listTransactionsForAccount as any).mock.calls[0][0];
|
|
593
|
-
expect(callArgs.account?.value).toEqual(account);
|
|
594
|
-
});
|
|
595
|
-
|
|
596
|
-
it("should accept account as string", async () => {
|
|
597
|
-
const ctx = createMockContext();
|
|
598
|
-
const mockResponse = { signatures: [] };
|
|
599
|
-
vi.spyOn(ctx.query, "listTransactionsForAccount").mockResolvedValue(mockResponse as any);
|
|
600
|
-
|
|
601
|
-
const accountString = generateTestAddress();
|
|
602
|
-
await listTransactionsForAccount(ctx, accountString);
|
|
603
|
-
|
|
604
|
-
const callArgs = (ctx.query.listTransactionsForAccount as any).mock.calls[0][0];
|
|
605
|
-
expect(callArgs.account?.value.length).toBe(32);
|
|
606
|
-
});
|
|
607
|
-
|
|
608
|
-
it("should pass page options", async () => {
|
|
609
|
-
const ctx = createMockContext();
|
|
610
|
-
const mockResponse = { signatures: [] };
|
|
611
|
-
vi.spyOn(ctx.query, "listTransactionsForAccount").mockResolvedValue(mockResponse as any);
|
|
612
|
-
|
|
613
|
-
const account = generateTestPubkey();
|
|
614
|
-
const page = create(PageRequestSchema, { pageSize: 20, pageToken: "token123" });
|
|
615
|
-
await listTransactionsForAccount(ctx, account, { page });
|
|
616
|
-
|
|
617
|
-
const callArgs = (ctx.query.listTransactionsForAccount as any).mock.calls[0][0];
|
|
618
|
-
expect(callArgs.page?.pageSize).toBe(20);
|
|
619
|
-
expect(callArgs.page?.pageToken).toBe("token123");
|
|
620
|
-
});
|
|
621
|
-
|
|
622
|
-
it("should pass filter options", async () => {
|
|
623
|
-
const ctx = createMockContext();
|
|
624
|
-
const mockResponse = { signatures: [] };
|
|
625
|
-
vi.spyOn(ctx.query, "listTransactionsForAccount").mockResolvedValue(mockResponse as any);
|
|
626
|
-
|
|
627
|
-
const account = generateTestPubkey();
|
|
628
|
-
const filter = create(FilterSchema, { expression: "meta.value > 0" });
|
|
629
|
-
await listTransactionsForAccount(ctx, account, { filter });
|
|
630
|
-
|
|
631
|
-
const callArgs = (ctx.query.listTransactionsForAccount as any).mock.calls[0][0];
|
|
632
|
-
expect(callArgs.filter?.expression).toBe("meta.value > 0");
|
|
633
|
-
});
|
|
634
|
-
});
|
|
635
|
-
|
|
636
|
-
describe("batchSendTransactions", () => {
|
|
637
|
-
it("should send batch of transactions", async () => {
|
|
638
|
-
const ctx = createMockContext();
|
|
639
|
-
const mockResponse = {
|
|
640
|
-
signatures: [
|
|
641
|
-
{ value: generateTestSignature(0x01) },
|
|
642
|
-
{ value: generateTestSignature(0x02) },
|
|
643
|
-
],
|
|
644
|
-
};
|
|
645
|
-
vi.spyOn(ctx.command, "batchSendTransactions").mockResolvedValue(mockResponse as any);
|
|
646
|
-
|
|
647
|
-
const transactions = [
|
|
648
|
-
new Uint8Array([1, 2, 3]),
|
|
649
|
-
new Uint8Array([4, 5, 6]),
|
|
650
|
-
];
|
|
651
|
-
const result = await batchSendTransactions(ctx, transactions);
|
|
652
|
-
|
|
653
|
-
expect(result).toBe(mockResponse);
|
|
654
|
-
expect(ctx.command.batchSendTransactions).toHaveBeenCalledTimes(1);
|
|
655
|
-
const callArgs = (ctx.command.batchSendTransactions as any).mock.calls[0][0];
|
|
656
|
-
expect(callArgs.rawTransactions).toHaveLength(2);
|
|
657
|
-
expect(callArgs.rawTransactions[0]).toEqual(transactions[0]);
|
|
658
|
-
expect(callArgs.rawTransactions[1]).toEqual(transactions[1]);
|
|
659
|
-
});
|
|
660
|
-
|
|
661
|
-
it("should convert Transaction objects to raw bytes", async () => {
|
|
662
|
-
const ctx = createMockContext();
|
|
663
|
-
const mockResponse = { signatures: [{ value: generateTestSignature() }] };
|
|
664
|
-
vi.spyOn(ctx.command, "batchSendTransactions").mockResolvedValue(mockResponse as any);
|
|
665
|
-
|
|
666
|
-
const transaction = new Transaction({
|
|
667
|
-
feePayer: generateTestPubkey(0x01),
|
|
668
|
-
program: generateTestPubkey(0x02),
|
|
669
|
-
header: {
|
|
670
|
-
fee: 1n,
|
|
671
|
-
nonce: 2n,
|
|
672
|
-
startSlot: 3n,
|
|
673
|
-
},
|
|
674
|
-
});
|
|
675
|
-
|
|
676
|
-
await batchSendTransactions(ctx, [transaction]);
|
|
677
|
-
|
|
678
|
-
const callArgs = (ctx.command.batchSendTransactions as any).mock.calls[0][0];
|
|
679
|
-
expect(callArgs.rawTransactions).toHaveLength(1);
|
|
680
|
-
expect(callArgs.rawTransactions[0]).toBeInstanceOf(Uint8Array);
|
|
681
|
-
});
|
|
682
|
-
|
|
683
|
-
it("should handle mixed Transaction objects and raw bytes", async () => {
|
|
684
|
-
const ctx = createMockContext();
|
|
685
|
-
const mockResponse = { signatures: [] };
|
|
686
|
-
vi.spyOn(ctx.command, "batchSendTransactions").mockResolvedValue(mockResponse as any);
|
|
687
|
-
|
|
688
|
-
const transaction = new Transaction({
|
|
689
|
-
feePayer: generateTestPubkey(0x01),
|
|
690
|
-
program: generateTestPubkey(0x02),
|
|
691
|
-
header: {
|
|
692
|
-
fee: 1n,
|
|
693
|
-
nonce: 2n,
|
|
694
|
-
startSlot: 3n,
|
|
695
|
-
},
|
|
696
|
-
});
|
|
697
|
-
const rawBytes = new Uint8Array([1, 2, 3]);
|
|
698
|
-
|
|
699
|
-
await batchSendTransactions(ctx, [transaction, rawBytes]);
|
|
700
|
-
|
|
701
|
-
const callArgs = (ctx.command.batchSendTransactions as any).mock.calls[0][0];
|
|
702
|
-
expect(callArgs.rawTransactions).toHaveLength(2);
|
|
703
|
-
expect(callArgs.rawTransactions[0]).toBeInstanceOf(Uint8Array);
|
|
704
|
-
expect(callArgs.rawTransactions[1]).toBe(rawBytes);
|
|
705
|
-
});
|
|
706
|
-
|
|
707
|
-
it("should pass numRetries option", async () => {
|
|
708
|
-
const ctx = createMockContext();
|
|
709
|
-
const mockResponse = { signatures: [] };
|
|
710
|
-
vi.spyOn(ctx.command, "batchSendTransactions").mockResolvedValue(mockResponse as any);
|
|
711
|
-
|
|
712
|
-
await batchSendTransactions(ctx, [new Uint8Array([1])], { numRetries: 5 });
|
|
713
|
-
|
|
714
|
-
const callArgs = (ctx.command.batchSendTransactions as any).mock.calls[0][0];
|
|
715
|
-
expect(callArgs.numRetries).toBe(5);
|
|
716
|
-
});
|
|
717
|
-
|
|
718
|
-
it("should default numRetries to 0 when not provided", async () => {
|
|
719
|
-
const ctx = createMockContext();
|
|
720
|
-
const mockResponse = { signatures: [] };
|
|
721
|
-
vi.spyOn(ctx.command, "batchSendTransactions").mockResolvedValue(mockResponse as any);
|
|
722
|
-
|
|
723
|
-
await batchSendTransactions(ctx, [new Uint8Array([1])]);
|
|
724
|
-
|
|
725
|
-
const callArgs = (ctx.command.batchSendTransactions as any).mock.calls[0][0];
|
|
726
|
-
expect(callArgs.numRetries).toBe(0);
|
|
727
|
-
});
|
|
728
|
-
});
|
|
729
|
-
});
|
|
730
|
-
|