@rialo/spl-token 0.3.0-alpha.0 → 0.3.0-alpha.1

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/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  var tsCdk = require('@rialo/ts-cdk');
4
4
 
5
- // src/client/spl-token-client.ts
5
+ // src/builders/mint-builder.ts
6
6
 
7
7
  // src/constants.ts
8
8
  var TOKEN_2022_PROGRAM_ID = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
@@ -85,157 +85,501 @@ var TokenInstruction = /* @__PURE__ */ ((TokenInstruction2) => {
85
85
  TokenInstruction2[TokenInstruction2["InitializeAccount3"] = 18] = "InitializeAccount3";
86
86
  TokenInstruction2[TokenInstruction2["InitializeMultisig2"] = 19] = "InitializeMultisig2";
87
87
  TokenInstruction2[TokenInstruction2["InitializeMint2"] = 20] = "InitializeMint2";
88
+ TokenInstruction2[TokenInstruction2["TransferFeeExtension"] = 26] = "TransferFeeExtension";
89
+ TokenInstruction2[TokenInstruction2["InitializeNonTransferableMint"] = 32] = "InitializeNonTransferableMint";
90
+ TokenInstruction2[TokenInstruction2["InitializePermanentDelegate"] = 35] = "InitializePermanentDelegate";
91
+ TokenInstruction2[TokenInstruction2["TransferHookExtension"] = 36] = "TransferHookExtension";
92
+ TokenInstruction2[TokenInstruction2["MetadataPointerExtension"] = 39] = "MetadataPointerExtension";
88
93
  return TokenInstruction2;
89
94
  })(TokenInstruction || {});
90
95
  var TLV_TYPE_SIZE = 2;
91
96
  var TLV_LENGTH_SIZE = 2;
92
- var MINT_EXTENSIONS_OFFSET = MINT_SIZE + 1;
97
+ var MINT_EXTENSIONS_OFFSET = TOKEN_ACCOUNT_SIZE + 1;
98
+ var TOKEN_ACCOUNT_EXTENSIONS_OFFSET = TOKEN_ACCOUNT_SIZE + 1;
93
99
 
94
- // src/errors.ts
95
- var SplTokenErrorCode = /* @__PURE__ */ ((SplTokenErrorCode2) => {
96
- SplTokenErrorCode2["INVALID_MINT"] = "INVALID_MINT";
97
- SplTokenErrorCode2["INVALID_TOKEN_ACCOUNT"] = "INVALID_TOKEN_ACCOUNT";
98
- SplTokenErrorCode2["TOKEN_ACCOUNT_NOT_FOUND"] = "TOKEN_ACCOUNT_NOT_FOUND";
99
- SplTokenErrorCode2["MINT_NOT_FOUND"] = "MINT_NOT_FOUND";
100
- SplTokenErrorCode2["ACCOUNT_FROZEN"] = "ACCOUNT_FROZEN";
101
- SplTokenErrorCode2["INSUFFICIENT_BALANCE"] = "INSUFFICIENT_BALANCE";
102
- SplTokenErrorCode2["INVALID_EXTENSION"] = "INVALID_EXTENSION";
103
- SplTokenErrorCode2["PDA_DERIVATION_FAILED"] = "PDA_DERIVATION_FAILED";
104
- SplTokenErrorCode2["INVALID_METADATA"] = "INVALID_METADATA";
105
- SplTokenErrorCode2["ACCOUNT_NOT_INITIALIZED"] = "ACCOUNT_NOT_INITIALIZED";
106
- return SplTokenErrorCode2;
107
- })(SplTokenErrorCode || {});
108
- var SplTokenError = class _SplTokenError extends Error {
109
- code;
110
- details;
111
- constructor({ code, message, details }) {
112
- super(message);
113
- this.name = "SplTokenError";
114
- this.code = code;
115
- this.details = details;
116
- if (Error.captureStackTrace) {
117
- Error.captureStackTrace(this, _SplTokenError);
118
- }
100
+ // node_modules/@noble/hashes/utils.js
101
+ function isBytes(a) {
102
+ return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
103
+ }
104
+ function abytes(value, length, title = "") {
105
+ const bytes = isBytes(value);
106
+ const len = value?.length;
107
+ const needsLen = length !== void 0;
108
+ if (!bytes || needsLen) {
109
+ const prefix = title && `"${title}" `;
110
+ const ofLen = "";
111
+ const got = bytes ? `length=${len}` : `type=${typeof value}`;
112
+ throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
119
113
  }
120
- /**
121
- * Creates an invalid mint error.
122
- *
123
- * @param options - Error options containing the reason
124
- */
125
- static invalidMint({ reason }) {
126
- return new _SplTokenError({
127
- code: "INVALID_MINT" /* INVALID_MINT */,
128
- message: `Invalid mint: ${reason}`
129
- });
114
+ return value;
115
+ }
116
+ function aexists(instance, checkFinished = true) {
117
+ if (instance.destroyed)
118
+ throw new Error("Hash instance has been destroyed");
119
+ if (checkFinished && instance.finished)
120
+ throw new Error("Hash#digest() has already been called");
121
+ }
122
+ function aoutput(out, instance) {
123
+ abytes(out, void 0, "digestInto() output");
124
+ const min = instance.outputLen;
125
+ if (out.length < min) {
126
+ throw new Error('"digestInto() output" expected to be of length >=' + min);
130
127
  }
131
- /**
132
- * Creates an invalid token account error.
133
- *
134
- * @param options - Error options containing the reason
135
- */
136
- static invalidTokenAccount({ reason }) {
137
- return new _SplTokenError({
138
- code: "INVALID_TOKEN_ACCOUNT" /* INVALID_TOKEN_ACCOUNT */,
139
- message: `Invalid token account: ${reason}`
140
- });
128
+ }
129
+ function clean(...arrays) {
130
+ for (let i = 0; i < arrays.length; i++) {
131
+ arrays[i].fill(0);
141
132
  }
142
- /**
143
- * Creates a token account not found error.
144
- *
145
- * @param options - Error options containing the address
146
- */
147
- static tokenAccountNotFound({ address }) {
148
- return new _SplTokenError({
149
- code: "TOKEN_ACCOUNT_NOT_FOUND" /* TOKEN_ACCOUNT_NOT_FOUND */,
150
- message: `Token account not found: ${address}`,
151
- details: { address }
152
- });
133
+ }
134
+ function createView(arr) {
135
+ return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
136
+ }
137
+ function rotr(word, shift) {
138
+ return word << 32 - shift | word >>> shift;
139
+ }
140
+ function createHasher(hashCons, info = {}) {
141
+ const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
142
+ const tmp = hashCons(void 0);
143
+ hashC.outputLen = tmp.outputLen;
144
+ hashC.blockLen = tmp.blockLen;
145
+ hashC.create = (opts) => hashCons(opts);
146
+ Object.assign(hashC, info);
147
+ return Object.freeze(hashC);
148
+ }
149
+ var oidNist = (suffix) => ({
150
+ oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
151
+ });
152
+
153
+ // node_modules/@noble/hashes/_md.js
154
+ function Chi(a, b, c) {
155
+ return a & b ^ ~a & c;
156
+ }
157
+ function Maj(a, b, c) {
158
+ return a & b ^ a & c ^ b & c;
159
+ }
160
+ var HashMD = class {
161
+ blockLen;
162
+ outputLen;
163
+ padOffset;
164
+ isLE;
165
+ // For partial updates less than block size
166
+ buffer;
167
+ view;
168
+ finished = false;
169
+ length = 0;
170
+ pos = 0;
171
+ destroyed = false;
172
+ constructor(blockLen, outputLen, padOffset, isLE) {
173
+ this.blockLen = blockLen;
174
+ this.outputLen = outputLen;
175
+ this.padOffset = padOffset;
176
+ this.isLE = isLE;
177
+ this.buffer = new Uint8Array(blockLen);
178
+ this.view = createView(this.buffer);
153
179
  }
154
- /**
155
- * Creates a mint not found error.
156
- *
157
- * @param options - Error options containing the address
158
- */
159
- static mintNotFound({ address }) {
160
- return new _SplTokenError({
161
- code: "MINT_NOT_FOUND" /* MINT_NOT_FOUND */,
162
- message: `Mint not found: ${address}`,
163
- details: { address }
164
- });
180
+ update(data) {
181
+ aexists(this);
182
+ abytes(data);
183
+ const { view, buffer, blockLen } = this;
184
+ const len = data.length;
185
+ for (let pos = 0; pos < len; ) {
186
+ const take = Math.min(blockLen - this.pos, len - pos);
187
+ if (take === blockLen) {
188
+ const dataView = createView(data);
189
+ for (; blockLen <= len - pos; pos += blockLen)
190
+ this.process(dataView, pos);
191
+ continue;
192
+ }
193
+ buffer.set(data.subarray(pos, pos + take), this.pos);
194
+ this.pos += take;
195
+ pos += take;
196
+ if (this.pos === blockLen) {
197
+ this.process(view, 0);
198
+ this.pos = 0;
199
+ }
200
+ }
201
+ this.length += data.length;
202
+ this.roundClean();
203
+ return this;
165
204
  }
166
- /**
167
- * Creates an account frozen error.
168
- *
169
- * @param options - Error options containing the address
170
- */
171
- static accountFrozen({ address }) {
172
- return new _SplTokenError({
173
- code: "ACCOUNT_FROZEN" /* ACCOUNT_FROZEN */,
174
- message: `Token account is frozen: ${address}`,
175
- details: { address }
176
- });
205
+ digestInto(out) {
206
+ aexists(this);
207
+ aoutput(out, this);
208
+ this.finished = true;
209
+ const { buffer, view, blockLen, isLE } = this;
210
+ let { pos } = this;
211
+ buffer[pos++] = 128;
212
+ clean(this.buffer.subarray(pos));
213
+ if (this.padOffset > blockLen - pos) {
214
+ this.process(view, 0);
215
+ pos = 0;
216
+ }
217
+ for (let i = pos; i < blockLen; i++)
218
+ buffer[i] = 0;
219
+ view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);
220
+ this.process(view, 0);
221
+ const oview = createView(out);
222
+ const len = this.outputLen;
223
+ if (len % 4)
224
+ throw new Error("_sha2: outputLen must be aligned to 32bit");
225
+ const outLen = len / 4;
226
+ const state = this.get();
227
+ if (outLen > state.length)
228
+ throw new Error("_sha2: outputLen bigger than state");
229
+ for (let i = 0; i < outLen; i++)
230
+ oview.setUint32(4 * i, state[i], isLE);
177
231
  }
178
- /**
179
- * Creates an insufficient balance error.
180
- *
181
- * @param options - Error options containing required and available amounts
182
- */
183
- static insufficientBalance({
184
- required,
185
- available
186
- }) {
187
- return new _SplTokenError({
188
- code: "INSUFFICIENT_BALANCE" /* INSUFFICIENT_BALANCE */,
189
- message: `Insufficient balance: required ${required}, available ${available}`,
190
- details: { required: required.toString(), available: available.toString() }
191
- });
232
+ digest() {
233
+ const { buffer, outputLen } = this;
234
+ this.digestInto(buffer);
235
+ const res = buffer.slice(0, outputLen);
236
+ this.destroy();
237
+ return res;
192
238
  }
193
- /**
194
- * Creates an invalid extension error.
195
- *
196
- * @param options - Error options containing the reason
197
- */
198
- static invalidExtension({ reason }) {
199
- return new _SplTokenError({
200
- code: "INVALID_EXTENSION" /* INVALID_EXTENSION */,
201
- message: `Invalid extension: ${reason}`
202
- });
239
+ _cloneInto(to) {
240
+ to ||= new this.constructor();
241
+ to.set(...this.get());
242
+ const { blockLen, buffer, length, finished, destroyed, pos } = this;
243
+ to.destroyed = destroyed;
244
+ to.finished = finished;
245
+ to.length = length;
246
+ to.pos = pos;
247
+ if (length % blockLen)
248
+ to.buffer.set(buffer);
249
+ return to;
203
250
  }
204
- /**
205
- * Creates a PDA derivation failed error.
206
- *
207
- * @param options - Error options containing the reason
208
- */
209
- static pdaDerivationFailed({ reason }) {
210
- return new _SplTokenError({
211
- code: "PDA_DERIVATION_FAILED" /* PDA_DERIVATION_FAILED */,
212
- message: `PDA derivation failed: ${reason}`
213
- });
251
+ clone() {
252
+ return this._cloneInto();
214
253
  }
215
- /**
216
- * Creates an invalid metadata error.
217
- *
218
- * @param options - Error options containing the reason
219
- */
220
- static invalidMetadata({ reason }) {
221
- return new _SplTokenError({
222
- code: "INVALID_METADATA" /* INVALID_METADATA */,
223
- message: `Invalid metadata: ${reason}`
224
- });
254
+ };
255
+ var SHA256_IV = /* @__PURE__ */ Uint32Array.from([
256
+ 1779033703,
257
+ 3144134277,
258
+ 1013904242,
259
+ 2773480762,
260
+ 1359893119,
261
+ 2600822924,
262
+ 528734635,
263
+ 1541459225
264
+ ]);
265
+
266
+ // node_modules/@noble/hashes/sha2.js
267
+ var SHA256_K = /* @__PURE__ */ Uint32Array.from([
268
+ 1116352408,
269
+ 1899447441,
270
+ 3049323471,
271
+ 3921009573,
272
+ 961987163,
273
+ 1508970993,
274
+ 2453635748,
275
+ 2870763221,
276
+ 3624381080,
277
+ 310598401,
278
+ 607225278,
279
+ 1426881987,
280
+ 1925078388,
281
+ 2162078206,
282
+ 2614888103,
283
+ 3248222580,
284
+ 3835390401,
285
+ 4022224774,
286
+ 264347078,
287
+ 604807628,
288
+ 770255983,
289
+ 1249150122,
290
+ 1555081692,
291
+ 1996064986,
292
+ 2554220882,
293
+ 2821834349,
294
+ 2952996808,
295
+ 3210313671,
296
+ 3336571891,
297
+ 3584528711,
298
+ 113926993,
299
+ 338241895,
300
+ 666307205,
301
+ 773529912,
302
+ 1294757372,
303
+ 1396182291,
304
+ 1695183700,
305
+ 1986661051,
306
+ 2177026350,
307
+ 2456956037,
308
+ 2730485921,
309
+ 2820302411,
310
+ 3259730800,
311
+ 3345764771,
312
+ 3516065817,
313
+ 3600352804,
314
+ 4094571909,
315
+ 275423344,
316
+ 430227734,
317
+ 506948616,
318
+ 659060556,
319
+ 883997877,
320
+ 958139571,
321
+ 1322822218,
322
+ 1537002063,
323
+ 1747873779,
324
+ 1955562222,
325
+ 2024104815,
326
+ 2227730452,
327
+ 2361852424,
328
+ 2428436474,
329
+ 2756734187,
330
+ 3204031479,
331
+ 3329325298
332
+ ]);
333
+ var SHA256_W = /* @__PURE__ */ new Uint32Array(64);
334
+ var SHA2_32B = class extends HashMD {
335
+ constructor(outputLen) {
336
+ super(64, outputLen, 8, false);
225
337
  }
226
- /**
227
- * Creates an account not initialized error.
228
- *
229
- * @param options - Error options containing the address
230
- */
231
- static accountNotInitialized({ address }) {
232
- return new _SplTokenError({
233
- code: "ACCOUNT_NOT_INITIALIZED" /* ACCOUNT_NOT_INITIALIZED */,
234
- message: `Account not initialized: ${address}`,
235
- details: { address }
236
- });
338
+ get() {
339
+ const { A, B, C, D, E, F, G, H } = this;
340
+ return [A, B, C, D, E, F, G, H];
341
+ }
342
+ // prettier-ignore
343
+ set(A, B, C, D, E, F, G, H) {
344
+ this.A = A | 0;
345
+ this.B = B | 0;
346
+ this.C = C | 0;
347
+ this.D = D | 0;
348
+ this.E = E | 0;
349
+ this.F = F | 0;
350
+ this.G = G | 0;
351
+ this.H = H | 0;
352
+ }
353
+ process(view, offset) {
354
+ for (let i = 0; i < 16; i++, offset += 4)
355
+ SHA256_W[i] = view.getUint32(offset, false);
356
+ for (let i = 16; i < 64; i++) {
357
+ const W15 = SHA256_W[i - 15];
358
+ const W2 = SHA256_W[i - 2];
359
+ const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
360
+ const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
361
+ SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
362
+ }
363
+ let { A, B, C, D, E, F, G, H } = this;
364
+ for (let i = 0; i < 64; i++) {
365
+ const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
366
+ const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;
367
+ const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
368
+ const T2 = sigma0 + Maj(A, B, C) | 0;
369
+ H = G;
370
+ G = F;
371
+ F = E;
372
+ E = D + T1 | 0;
373
+ D = C;
374
+ C = B;
375
+ B = A;
376
+ A = T1 + T2 | 0;
377
+ }
378
+ A = A + this.A | 0;
379
+ B = B + this.B | 0;
380
+ C = C + this.C | 0;
381
+ D = D + this.D | 0;
382
+ E = E + this.E | 0;
383
+ F = F + this.F | 0;
384
+ G = G + this.G | 0;
385
+ H = H + this.H | 0;
386
+ this.set(A, B, C, D, E, F, G, H);
387
+ }
388
+ roundClean() {
389
+ clean(SHA256_W);
390
+ }
391
+ destroy() {
392
+ this.set(0, 0, 0, 0, 0, 0, 0, 0);
393
+ clean(this.buffer);
394
+ }
395
+ };
396
+ var _SHA256 = class extends SHA2_32B {
397
+ // We cannot use array here since array allows indexing by variable
398
+ // which means optimizer/compiler cannot use registers.
399
+ A = SHA256_IV[0] | 0;
400
+ B = SHA256_IV[1] | 0;
401
+ C = SHA256_IV[2] | 0;
402
+ D = SHA256_IV[3] | 0;
403
+ E = SHA256_IV[4] | 0;
404
+ F = SHA256_IV[5] | 0;
405
+ G = SHA256_IV[6] | 0;
406
+ H = SHA256_IV[7] | 0;
407
+ constructor() {
408
+ super(32);
409
+ }
410
+ };
411
+ var sha256 = /* @__PURE__ */ createHasher(
412
+ () => new _SHA256(),
413
+ /* @__PURE__ */ oidNist(1)
414
+ );
415
+ var TOKEN_METADATA_NAMESPACE = "rialo_s_spl_token_metadata_interface";
416
+ var TOKEN_METADATA_DISCRIMINATOR_LENGTH = 8;
417
+ function metadataDiscriminator(label) {
418
+ const input = new TextEncoder().encode(`${TOKEN_METADATA_NAMESPACE}:${label}`);
419
+ return sha256(input).slice(0, TOKEN_METADATA_DISCRIMINATOR_LENGTH);
420
+ }
421
+ function writeU32LE({
422
+ data,
423
+ offset,
424
+ value
425
+ }) {
426
+ data[offset] = value & 255;
427
+ data[offset + 1] = value >>> 8 & 255;
428
+ data[offset + 2] = value >>> 16 & 255;
429
+ data[offset + 3] = value >>> 24 & 255;
430
+ }
431
+ function encodeLengthPrefixedString(value) {
432
+ const bytes = new TextEncoder().encode(value);
433
+ const buffer = new Uint8Array(4 + bytes.length);
434
+ writeU32LE({ data: buffer, offset: 0, value: bytes.length });
435
+ buffer.set(bytes, 4);
436
+ return buffer;
437
+ }
438
+ function encodeAdditionalMetadata(additionalMetadata) {
439
+ const entries = additionalMetadata.flatMap(([key, value]) => [
440
+ encodeLengthPrefixedString(key),
441
+ encodeLengthPrefixedString(value)
442
+ ]);
443
+ const totalLength = 4 + entries.reduce((sum, entry) => sum + entry.length, 0);
444
+ const buffer = new Uint8Array(totalLength);
445
+ writeU32LE({ data: buffer, offset: 0, value: additionalMetadata.length });
446
+ let offset = 4;
447
+ for (const entry of entries) {
448
+ buffer.set(entry, offset);
449
+ offset += entry.length;
450
+ }
451
+ return buffer;
452
+ }
453
+ function getTokenMetadataDataSize({
454
+ name,
455
+ symbol,
456
+ uri,
457
+ additionalMetadata = []
458
+ }) {
459
+ return 32 + 32 + encodeLengthPrefixedString(name).length + encodeLengthPrefixedString(symbol).length + encodeLengthPrefixedString(uri).length + encodeAdditionalMetadata(additionalMetadata).length;
460
+ }
461
+ function initializeTokenMetadataInstruction({
462
+ mint,
463
+ updateAuthority,
464
+ mintAuthority,
465
+ name,
466
+ symbol,
467
+ uri,
468
+ additionalMetadata = [],
469
+ programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
470
+ }) {
471
+ const nameBytes = encodeLengthPrefixedString(name);
472
+ const symbolBytes = encodeLengthPrefixedString(symbol);
473
+ const uriBytes = encodeLengthPrefixedString(uri);
474
+ const hasAdditionalMetadata = additionalMetadata.length > 0;
475
+ const additionalBytes = hasAdditionalMetadata ? encodeAdditionalMetadata(additionalMetadata) : null;
476
+ const dataLength = TOKEN_METADATA_DISCRIMINATOR_LENGTH + nameBytes.length + symbolBytes.length + uriBytes.length + (additionalBytes?.length ?? 0);
477
+ const data = new Uint8Array(dataLength);
478
+ data.set(metadataDiscriminator("initialize_account"), 0);
479
+ let offset = TOKEN_METADATA_DISCRIMINATOR_LENGTH;
480
+ data.set(nameBytes, offset);
481
+ offset += nameBytes.length;
482
+ data.set(symbolBytes, offset);
483
+ offset += symbolBytes.length;
484
+ data.set(uriBytes, offset);
485
+ if (additionalBytes) {
486
+ offset += uriBytes.length;
487
+ data.set(additionalBytes, offset);
237
488
  }
489
+ return {
490
+ programId,
491
+ accounts: [
492
+ { pubkey: mint, isSigner: false, isWritable: true },
493
+ { pubkey: updateAuthority, isSigner: false, isWritable: false },
494
+ { pubkey: mint, isSigner: false, isWritable: false },
495
+ { pubkey: mintAuthority, isSigner: true, isWritable: false }
496
+ ],
497
+ data
498
+ };
499
+ }
500
+
501
+ // src/helpers/size.ts
502
+ var TLV_HEADER_SIZE = TLV_TYPE_SIZE + TLV_LENGTH_SIZE;
503
+ var ACCOUNT_TYPE_SIZE = 1;
504
+ var EXTENSION_SIZES = {
505
+ [1 /* TransferFeeConfig */]: 108,
506
+ [2 /* TransferFeeAmount */]: 8,
507
+ [3 /* MintCloseAuthority */]: 32,
508
+ [4 /* ConfidentialTransferMint */]: 97,
509
+ [5 /* ConfidentialTransferAccount */]: 286,
510
+ [6 /* DefaultAccountState */]: 1,
511
+ [7 /* ImmutableOwner */]: 0,
512
+ [8 /* MemoTransfer */]: 1,
513
+ [9 /* NonTransferable */]: 0,
514
+ [10 /* InterestBearingConfig */]: 52,
515
+ [11 /* CpiGuard */]: 1,
516
+ [12 /* PermanentDelegate */]: 32,
517
+ [13 /* NonTransferableAccount */]: 0,
518
+ [14 /* TransferHook */]: 64,
519
+ [15 /* TransferHookAccount */]: 1,
520
+ [16 /* ConfidentialTransferFeeConfig */]: 64,
521
+ [17 /* ConfidentialTransferFeeAmount */]: 32,
522
+ [18 /* MetadataPointer */]: 64,
523
+ // TokenMetadata is variable-sized, must use getMetadataExtensionSize
524
+ [20 /* GroupPointer */]: 64,
525
+ [21 /* TokenGroup */]: 72,
526
+ [22 /* GroupMemberPointer */]: 64,
527
+ [23 /* TokenGroupMember */]: 68
238
528
  };
529
+ function getMintSizeWithExtensions({
530
+ extensions,
531
+ metadataSize
532
+ }) {
533
+ if (extensions.length === 0) {
534
+ return MINT_SIZE;
535
+ }
536
+ let totalSize = TOKEN_ACCOUNT_SIZE + ACCOUNT_TYPE_SIZE;
537
+ for (const extension of extensions) {
538
+ if (extension === 19 /* TokenMetadata */) {
539
+ if (metadataSize === void 0) {
540
+ throw new Error(
541
+ "metadataSize is required when ExtensionType.TokenMetadata is included. Use getMetadataExtensionSize() to calculate it."
542
+ );
543
+ }
544
+ totalSize += TLV_HEADER_SIZE + metadataSize;
545
+ } else {
546
+ const extSize = EXTENSION_SIZES[extension];
547
+ if (extSize === void 0) {
548
+ throw new Error(`Unknown extension type: ${extension}`);
549
+ }
550
+ totalSize += TLV_HEADER_SIZE + extSize;
551
+ }
552
+ }
553
+ return totalSize;
554
+ }
555
+ function getMetadataExtensionSize({
556
+ name,
557
+ symbol,
558
+ uri,
559
+ additionalMetadata = []
560
+ }) {
561
+ return getTokenMetadataDataSize({ name, symbol, uri, additionalMetadata });
562
+ }
563
+ async function getMinRentForMint(client, options) {
564
+ const size = getMintSizeWithExtensions(options);
565
+ return await client.getMinimumBalanceForRentExemption(BigInt(size));
566
+ }
567
+ function getMintSizeWithMetadata({
568
+ name,
569
+ symbol,
570
+ uri,
571
+ additionalMetadata = []
572
+ }) {
573
+ const metadataSize = getMetadataExtensionSize({ name, symbol, uri, additionalMetadata });
574
+ return getMintSizeWithExtensions({
575
+ extensions: [18 /* MetadataPointer */, 19 /* TokenMetadata */],
576
+ metadataSize
577
+ });
578
+ }
579
+ async function getMinRentForMintWithMetadata(client, metadata) {
580
+ const size = getMintSizeWithMetadata(metadata);
581
+ return await client.getMinimumBalanceForRentExemption(BigInt(size));
582
+ }
239
583
  function createAssociatedTokenAccountInstruction({
240
584
  payer,
241
585
  associatedToken,
@@ -283,7 +627,7 @@ function createAssociatedTokenAccountIdempotentInstruction({
283
627
  };
284
628
  }
285
629
 
286
- // src/test-helpers.ts
630
+ // src/utils/bytes.ts
287
631
  function writeU64LE({
288
632
  data,
289
633
  offset,
@@ -293,8 +637,96 @@ function writeU64LE({
293
637
  data[offset + i] = Number(value >> BigInt(i * 8) & 0xffn);
294
638
  }
295
639
  }
640
+ function writeU16LE({
641
+ data,
642
+ offset,
643
+ value
644
+ }) {
645
+ data[offset] = value & 255;
646
+ data[offset + 1] = value >> 8 & 255;
647
+ }
648
+
649
+ // src/instructions/utils.ts
650
+ function isAuthoritySigner({ signers }) {
651
+ return (signers?.length ?? 0) === 0;
652
+ }
653
+ function writeOptionalNonZeroPubkey({
654
+ data,
655
+ offset,
656
+ value
657
+ }) {
658
+ if (value) {
659
+ data.set(value.toBytes(), offset);
660
+ }
661
+ }
662
+ function writeCOptionPubkey({
663
+ data,
664
+ offset,
665
+ value
666
+ }) {
667
+ if (value) {
668
+ data[offset] = 1;
669
+ data.set(value.toBytes(), offset + 1);
670
+ return 33;
671
+ }
672
+ data[offset] = 0;
673
+ return 1;
674
+ }
675
+ function appendSigners({
676
+ accounts,
677
+ signers
678
+ }) {
679
+ for (const signer of signers ?? []) {
680
+ accounts.push({ pubkey: signer, isSigner: true, isWritable: false });
681
+ }
682
+ }
296
683
 
297
- // src/instructions/mint.ts
684
+ // src/instructions/metadata-pointer.ts
685
+ var METADATA_POINTER_INSTRUCTION_INITIALIZE = 0;
686
+ var METADATA_POINTER_INSTRUCTION_UPDATE = 1;
687
+ function initializeMetadataPointerInstruction({
688
+ mint,
689
+ authority,
690
+ metadataAddress,
691
+ programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
692
+ }) {
693
+ const data = new Uint8Array(66);
694
+ data[0] = 39 /* MetadataPointerExtension */;
695
+ data[1] = METADATA_POINTER_INSTRUCTION_INITIALIZE;
696
+ writeOptionalNonZeroPubkey({ data, offset: 2, value: authority ?? null });
697
+ writeOptionalNonZeroPubkey({
698
+ data,
699
+ offset: 34,
700
+ value: metadataAddress ?? null
701
+ });
702
+ return {
703
+ programId,
704
+ accounts: [{ pubkey: mint, isSigner: false, isWritable: true }],
705
+ data
706
+ };
707
+ }
708
+ function updateMetadataPointerInstruction({
709
+ mint,
710
+ authority,
711
+ metadataAddress,
712
+ signers,
713
+ programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
714
+ }) {
715
+ const data = new Uint8Array(34);
716
+ data[0] = 39 /* MetadataPointerExtension */;
717
+ data[1] = METADATA_POINTER_INSTRUCTION_UPDATE;
718
+ writeOptionalNonZeroPubkey({
719
+ data,
720
+ offset: 2,
721
+ value: metadataAddress ?? null
722
+ });
723
+ const accounts = [
724
+ { pubkey: mint, isSigner: false, isWritable: true },
725
+ { pubkey: authority, isSigner: isAuthoritySigner({ signers }), isWritable: false }
726
+ ];
727
+ appendSigners({ accounts, signers });
728
+ return { programId, accounts, data };
729
+ }
298
730
  function initializeMintInstruction({
299
731
  mint,
300
732
  decimals,
@@ -330,29 +762,43 @@ function mintToInstruction({
330
762
  destination,
331
763
  authority,
332
764
  amount,
765
+ signers,
333
766
  programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
334
767
  }) {
335
768
  const data = new Uint8Array(9);
336
769
  data[0] = 7 /* MintTo */;
337
770
  writeU64LE({ data, offset: 1, value: amount });
771
+ const accounts = [
772
+ { pubkey: mint, isSigner: false, isWritable: true },
773
+ { pubkey: destination, isSigner: false, isWritable: true },
774
+ { pubkey: authority, isSigner: isAuthoritySigner({ signers }), isWritable: false }
775
+ ];
776
+ appendSigners({ accounts, signers });
777
+ return { programId, accounts, data };
778
+ }
779
+ function initializeNonTransferableMintInstruction({
780
+ mint,
781
+ programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
782
+ }) {
338
783
  return {
339
784
  programId,
340
- accounts: [
341
- { pubkey: mint, isSigner: false, isWritable: true },
342
- { pubkey: destination, isSigner: false, isWritable: true },
343
- { pubkey: authority, isSigner: true, isWritable: false }
344
- ],
345
- data
785
+ accounts: [{ pubkey: mint, isSigner: false, isWritable: true }],
786
+ data: new Uint8Array([32 /* InitializeNonTransferableMint */])
346
787
  };
347
788
  }
348
- function writeU64LE2({
349
- data,
350
- offset,
351
- value
789
+ function initializePermanentDelegateInstruction({
790
+ mint,
791
+ delegate,
792
+ programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
352
793
  }) {
353
- for (let i = 0; i < 8; i++) {
354
- data[offset + i] = Number(value >> BigInt(i * 8) & 0xffn);
355
- }
794
+ const data = new Uint8Array(33);
795
+ data[0] = 35 /* InitializePermanentDelegate */;
796
+ data.set(delegate.toBytes(), 1);
797
+ return {
798
+ programId,
799
+ accounts: [{ pubkey: mint, isSigner: false, isWritable: true }],
800
+ data
801
+ };
356
802
  }
357
803
  function transferCheckedInstruction({
358
804
  source,
@@ -361,359 +807,289 @@ function transferCheckedInstruction({
361
807
  authority,
362
808
  amount,
363
809
  decimals,
810
+ signers,
364
811
  programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
365
812
  }) {
366
813
  const data = new Uint8Array(10);
367
814
  data[0] = 12 /* TransferChecked */;
368
- writeU64LE2({ data, offset: 1, value: amount });
815
+ writeU64LE({ data, offset: 1, value: amount });
369
816
  data[9] = decimals;
370
- return {
371
- programId,
372
- accounts: [
373
- { pubkey: source, isSigner: false, isWritable: true },
374
- { pubkey: mint, isSigner: false, isWritable: false },
375
- { pubkey: destination, isSigner: false, isWritable: true },
376
- { pubkey: authority, isSigner: true, isWritable: false }
377
- ],
378
- data
379
- };
817
+ const accounts = [
818
+ { pubkey: source, isSigner: false, isWritable: true },
819
+ { pubkey: mint, isSigner: false, isWritable: false },
820
+ { pubkey: destination, isSigner: false, isWritable: true },
821
+ { pubkey: authority, isSigner: isAuthoritySigner({ signers }), isWritable: false }
822
+ ];
823
+ appendSigners({ accounts, signers });
824
+ return { programId, accounts, data };
380
825
  }
381
826
  function transferInstruction({
382
827
  source,
383
828
  destination,
384
829
  authority,
385
830
  amount,
831
+ signers,
386
832
  programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
387
833
  }) {
388
834
  const data = new Uint8Array(9);
389
835
  data[0] = 3 /* Transfer */;
390
- writeU64LE2({ data, offset: 1, value: amount });
836
+ writeU64LE({ data, offset: 1, value: amount });
837
+ const accounts = [
838
+ { pubkey: source, isSigner: false, isWritable: true },
839
+ { pubkey: destination, isSigner: false, isWritable: true },
840
+ { pubkey: authority, isSigner: isAuthoritySigner({ signers }), isWritable: false }
841
+ ];
842
+ appendSigners({ accounts, signers });
843
+ return { programId, accounts, data };
844
+ }
845
+ var TRANSFER_FEE_INSTRUCTION_INITIALIZE_CONFIG = 0;
846
+ var TRANSFER_FEE_INSTRUCTION_TRANSFER_CHECKED_WITH_FEE = 1;
847
+ var TRANSFER_FEE_INSTRUCTION_SET_TRANSFER_FEE = 5;
848
+ function initializeTransferFeeConfigInstruction({
849
+ mint,
850
+ transferFeeConfigAuthority,
851
+ withdrawWithheldAuthority,
852
+ transferFeeBasisPoints,
853
+ maximumFee,
854
+ programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
855
+ }) {
856
+ const authorityLength = transferFeeConfigAuthority ? 33 : 1;
857
+ const withdrawLength = withdrawWithheldAuthority ? 33 : 1;
858
+ const data = new Uint8Array(2 + authorityLength + withdrawLength + 2 + 8);
859
+ data[0] = 26 /* TransferFeeExtension */;
860
+ data[1] = TRANSFER_FEE_INSTRUCTION_INITIALIZE_CONFIG;
861
+ let offset = 2;
862
+ offset += writeCOptionPubkey({
863
+ data,
864
+ offset,
865
+ value: transferFeeConfigAuthority ?? null
866
+ });
867
+ offset += writeCOptionPubkey({
868
+ data,
869
+ offset,
870
+ value: withdrawWithheldAuthority ?? null
871
+ });
872
+ writeU16LE({ data, offset, value: transferFeeBasisPoints });
873
+ offset += 2;
874
+ writeU64LE({ data, offset, value: maximumFee });
391
875
  return {
392
876
  programId,
393
- accounts: [
394
- { pubkey: source, isSigner: false, isWritable: true },
395
- { pubkey: destination, isSigner: false, isWritable: true },
396
- { pubkey: authority, isSigner: true, isWritable: false }
397
- ],
877
+ accounts: [{ pubkey: mint, isSigner: false, isWritable: true }],
398
878
  data
399
879
  };
400
880
  }
401
-
402
- // node_modules/@noble/hashes/utils.js
403
- function isBytes(a) {
404
- return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
405
- }
406
- function abytes(value, length, title = "") {
407
- const bytes = isBytes(value);
408
- const len = value?.length;
409
- const needsLen = length !== void 0;
410
- if (!bytes || needsLen) {
411
- const prefix = title && `"${title}" `;
412
- const ofLen = "";
413
- const got = bytes ? `length=${len}` : `type=${typeof value}`;
414
- throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
415
- }
416
- return value;
417
- }
418
- function aexists(instance, checkFinished = true) {
419
- if (instance.destroyed)
420
- throw new Error("Hash instance has been destroyed");
421
- if (checkFinished && instance.finished)
422
- throw new Error("Hash#digest() has already been called");
423
- }
424
- function aoutput(out, instance) {
425
- abytes(out, void 0, "digestInto() output");
426
- const min = instance.outputLen;
427
- if (out.length < min) {
428
- throw new Error('"digestInto() output" expected to be of length >=' + min);
429
- }
430
- }
431
- function clean(...arrays) {
432
- for (let i = 0; i < arrays.length; i++) {
433
- arrays[i].fill(0);
434
- }
435
- }
436
- function createView(arr) {
437
- return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
881
+ function transferCheckedWithFeeInstruction({
882
+ source,
883
+ mint,
884
+ destination,
885
+ authority,
886
+ amount,
887
+ decimals,
888
+ fee,
889
+ signers,
890
+ programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
891
+ }) {
892
+ const data = new Uint8Array(2 + 8 + 1 + 8);
893
+ data[0] = 26 /* TransferFeeExtension */;
894
+ data[1] = TRANSFER_FEE_INSTRUCTION_TRANSFER_CHECKED_WITH_FEE;
895
+ writeU64LE({ data, offset: 2, value: amount });
896
+ data[10] = decimals;
897
+ writeU64LE({ data, offset: 11, value: fee });
898
+ const accounts = [
899
+ { pubkey: source, isSigner: false, isWritable: true },
900
+ { pubkey: mint, isSigner: false, isWritable: false },
901
+ { pubkey: destination, isSigner: false, isWritable: true },
902
+ { pubkey: authority, isSigner: isAuthoritySigner({ signers }), isWritable: false }
903
+ ];
904
+ appendSigners({ accounts, signers });
905
+ return { programId, accounts, data };
438
906
  }
439
- function rotr(word, shift) {
440
- return word << 32 - shift | word >>> shift;
907
+ function setTransferFeeInstruction({
908
+ mint,
909
+ authority,
910
+ transferFeeBasisPoints,
911
+ maximumFee,
912
+ signers,
913
+ programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
914
+ }) {
915
+ const data = new Uint8Array(2 + 2 + 8);
916
+ data[0] = 26 /* TransferFeeExtension */;
917
+ data[1] = TRANSFER_FEE_INSTRUCTION_SET_TRANSFER_FEE;
918
+ writeU16LE({ data, offset: 2, value: transferFeeBasisPoints });
919
+ writeU64LE({ data, offset: 4, value: maximumFee });
920
+ const accounts = [
921
+ { pubkey: mint, isSigner: false, isWritable: true },
922
+ { pubkey: authority, isSigner: isAuthoritySigner({ signers }), isWritable: false }
923
+ ];
924
+ appendSigners({ accounts, signers });
925
+ return { programId, accounts, data };
441
926
  }
442
- function createHasher(hashCons, info = {}) {
443
- const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
444
- const tmp = hashCons(void 0);
445
- hashC.outputLen = tmp.outputLen;
446
- hashC.blockLen = tmp.blockLen;
447
- hashC.create = (opts) => hashCons(opts);
448
- Object.assign(hashC, info);
449
- return Object.freeze(hashC);
927
+ var TRANSFER_HOOK_INSTRUCTION_INITIALIZE = 0;
928
+ function initializeTransferHookInstruction({
929
+ mint,
930
+ authority,
931
+ hookProgramId,
932
+ programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
933
+ }) {
934
+ const data = new Uint8Array(66);
935
+ data[0] = 36 /* TransferHookExtension */;
936
+ data[1] = TRANSFER_HOOK_INSTRUCTION_INITIALIZE;
937
+ data.set(authority.toBytes(), 2);
938
+ data.set(hookProgramId.toBytes(), 34);
939
+ return {
940
+ programId,
941
+ accounts: [{ pubkey: mint, isSigner: false, isWritable: true }],
942
+ data
943
+ };
450
944
  }
451
- var oidNist = (suffix) => ({
452
- oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
453
- });
454
945
 
455
- // node_modules/@noble/hashes/_md.js
456
- function Chi(a, b, c) {
457
- return a & b ^ ~a & c;
458
- }
459
- function Maj(a, b, c) {
460
- return a & b ^ a & c ^ b & c;
461
- }
462
- var HashMD = class {
463
- blockLen;
464
- outputLen;
465
- padOffset;
466
- isLE;
467
- // For partial updates less than block size
468
- buffer;
469
- view;
470
- finished = false;
471
- length = 0;
472
- pos = 0;
473
- destroyed = false;
474
- constructor(blockLen, outputLen, padOffset, isLE) {
475
- this.blockLen = blockLen;
476
- this.outputLen = outputLen;
477
- this.padOffset = padOffset;
478
- this.isLE = isLE;
479
- this.buffer = new Uint8Array(blockLen);
480
- this.view = createView(this.buffer);
481
- }
482
- update(data) {
483
- aexists(this);
484
- abytes(data);
485
- const { view, buffer, blockLen } = this;
486
- const len = data.length;
487
- for (let pos = 0; pos < len; ) {
488
- const take = Math.min(blockLen - this.pos, len - pos);
489
- if (take === blockLen) {
490
- const dataView = createView(data);
491
- for (; blockLen <= len - pos; pos += blockLen)
492
- this.process(dataView, pos);
493
- continue;
494
- }
495
- buffer.set(data.subarray(pos, pos + take), this.pos);
496
- this.pos += take;
497
- pos += take;
498
- if (this.pos === blockLen) {
499
- this.process(view, 0);
500
- this.pos = 0;
501
- }
502
- }
503
- this.length += data.length;
504
- this.roundClean();
505
- return this;
506
- }
507
- digestInto(out) {
508
- aexists(this);
509
- aoutput(out, this);
510
- this.finished = true;
511
- const { buffer, view, blockLen, isLE } = this;
512
- let { pos } = this;
513
- buffer[pos++] = 128;
514
- clean(this.buffer.subarray(pos));
515
- if (this.padOffset > blockLen - pos) {
516
- this.process(view, 0);
517
- pos = 0;
946
+ // src/errors.ts
947
+ var SplTokenErrorCode = /* @__PURE__ */ ((SplTokenErrorCode2) => {
948
+ SplTokenErrorCode2["INVALID_MINT"] = "INVALID_MINT";
949
+ SplTokenErrorCode2["INVALID_TOKEN_ACCOUNT"] = "INVALID_TOKEN_ACCOUNT";
950
+ SplTokenErrorCode2["TOKEN_ACCOUNT_NOT_FOUND"] = "TOKEN_ACCOUNT_NOT_FOUND";
951
+ SplTokenErrorCode2["MINT_NOT_FOUND"] = "MINT_NOT_FOUND";
952
+ SplTokenErrorCode2["ACCOUNT_FROZEN"] = "ACCOUNT_FROZEN";
953
+ SplTokenErrorCode2["INSUFFICIENT_BALANCE"] = "INSUFFICIENT_BALANCE";
954
+ SplTokenErrorCode2["INVALID_EXTENSION"] = "INVALID_EXTENSION";
955
+ SplTokenErrorCode2["PDA_DERIVATION_FAILED"] = "PDA_DERIVATION_FAILED";
956
+ SplTokenErrorCode2["INVALID_METADATA"] = "INVALID_METADATA";
957
+ SplTokenErrorCode2["ACCOUNT_NOT_INITIALIZED"] = "ACCOUNT_NOT_INITIALIZED";
958
+ return SplTokenErrorCode2;
959
+ })(SplTokenErrorCode || {});
960
+ var SplTokenError = class _SplTokenError extends Error {
961
+ code;
962
+ details;
963
+ constructor({ code, message, details }) {
964
+ super(message);
965
+ this.name = "SplTokenError";
966
+ this.code = code;
967
+ this.details = details;
968
+ if (Error.captureStackTrace) {
969
+ Error.captureStackTrace(this, _SplTokenError);
518
970
  }
519
- for (let i = pos; i < blockLen; i++)
520
- buffer[i] = 0;
521
- view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE);
522
- this.process(view, 0);
523
- const oview = createView(out);
524
- const len = this.outputLen;
525
- if (len % 4)
526
- throw new Error("_sha2: outputLen must be aligned to 32bit");
527
- const outLen = len / 4;
528
- const state = this.get();
529
- if (outLen > state.length)
530
- throw new Error("_sha2: outputLen bigger than state");
531
- for (let i = 0; i < outLen; i++)
532
- oview.setUint32(4 * i, state[i], isLE);
533
971
  }
534
- digest() {
535
- const { buffer, outputLen } = this;
536
- this.digestInto(buffer);
537
- const res = buffer.slice(0, outputLen);
538
- this.destroy();
539
- return res;
972
+ /**
973
+ * Creates an invalid mint error.
974
+ *
975
+ * @param options - Error options containing the reason
976
+ */
977
+ static invalidMint({ reason }) {
978
+ return new _SplTokenError({
979
+ code: "INVALID_MINT" /* INVALID_MINT */,
980
+ message: `Invalid mint: ${reason}`
981
+ });
540
982
  }
541
- _cloneInto(to) {
542
- to ||= new this.constructor();
543
- to.set(...this.get());
544
- const { blockLen, buffer, length, finished, destroyed, pos } = this;
545
- to.destroyed = destroyed;
546
- to.finished = finished;
547
- to.length = length;
548
- to.pos = pos;
549
- if (length % blockLen)
550
- to.buffer.set(buffer);
551
- return to;
983
+ /**
984
+ * Creates an invalid token account error.
985
+ *
986
+ * @param options - Error options containing the reason
987
+ */
988
+ static invalidTokenAccount({ reason }) {
989
+ return new _SplTokenError({
990
+ code: "INVALID_TOKEN_ACCOUNT" /* INVALID_TOKEN_ACCOUNT */,
991
+ message: `Invalid token account: ${reason}`
992
+ });
552
993
  }
553
- clone() {
554
- return this._cloneInto();
994
+ /**
995
+ * Creates a token account not found error.
996
+ *
997
+ * @param options - Error options containing the address
998
+ */
999
+ static tokenAccountNotFound({ address }) {
1000
+ return new _SplTokenError({
1001
+ code: "TOKEN_ACCOUNT_NOT_FOUND" /* TOKEN_ACCOUNT_NOT_FOUND */,
1002
+ message: `Token account not found: ${address}`,
1003
+ details: { address }
1004
+ });
555
1005
  }
556
- };
557
- var SHA256_IV = /* @__PURE__ */ Uint32Array.from([
558
- 1779033703,
559
- 3144134277,
560
- 1013904242,
561
- 2773480762,
562
- 1359893119,
563
- 2600822924,
564
- 528734635,
565
- 1541459225
566
- ]);
567
-
568
- // node_modules/@noble/hashes/sha2.js
569
- var SHA256_K = /* @__PURE__ */ Uint32Array.from([
570
- 1116352408,
571
- 1899447441,
572
- 3049323471,
573
- 3921009573,
574
- 961987163,
575
- 1508970993,
576
- 2453635748,
577
- 2870763221,
578
- 3624381080,
579
- 310598401,
580
- 607225278,
581
- 1426881987,
582
- 1925078388,
583
- 2162078206,
584
- 2614888103,
585
- 3248222580,
586
- 3835390401,
587
- 4022224774,
588
- 264347078,
589
- 604807628,
590
- 770255983,
591
- 1249150122,
592
- 1555081692,
593
- 1996064986,
594
- 2554220882,
595
- 2821834349,
596
- 2952996808,
597
- 3210313671,
598
- 3336571891,
599
- 3584528711,
600
- 113926993,
601
- 338241895,
602
- 666307205,
603
- 773529912,
604
- 1294757372,
605
- 1396182291,
606
- 1695183700,
607
- 1986661051,
608
- 2177026350,
609
- 2456956037,
610
- 2730485921,
611
- 2820302411,
612
- 3259730800,
613
- 3345764771,
614
- 3516065817,
615
- 3600352804,
616
- 4094571909,
617
- 275423344,
618
- 430227734,
619
- 506948616,
620
- 659060556,
621
- 883997877,
622
- 958139571,
623
- 1322822218,
624
- 1537002063,
625
- 1747873779,
626
- 1955562222,
627
- 2024104815,
628
- 2227730452,
629
- 2361852424,
630
- 2428436474,
631
- 2756734187,
632
- 3204031479,
633
- 3329325298
634
- ]);
635
- var SHA256_W = /* @__PURE__ */ new Uint32Array(64);
636
- var SHA2_32B = class extends HashMD {
637
- constructor(outputLen) {
638
- super(64, outputLen, 8, false);
1006
+ /**
1007
+ * Creates a mint not found error.
1008
+ *
1009
+ * @param options - Error options containing the address
1010
+ */
1011
+ static mintNotFound({ address }) {
1012
+ return new _SplTokenError({
1013
+ code: "MINT_NOT_FOUND" /* MINT_NOT_FOUND */,
1014
+ message: `Mint not found: ${address}`,
1015
+ details: { address }
1016
+ });
639
1017
  }
640
- get() {
641
- const { A, B, C, D, E, F, G, H } = this;
642
- return [A, B, C, D, E, F, G, H];
1018
+ /**
1019
+ * Creates an account frozen error.
1020
+ *
1021
+ * @param options - Error options containing the address
1022
+ */
1023
+ static accountFrozen({ address }) {
1024
+ return new _SplTokenError({
1025
+ code: "ACCOUNT_FROZEN" /* ACCOUNT_FROZEN */,
1026
+ message: `Token account is frozen: ${address}`,
1027
+ details: { address }
1028
+ });
643
1029
  }
644
- // prettier-ignore
645
- set(A, B, C, D, E, F, G, H) {
646
- this.A = A | 0;
647
- this.B = B | 0;
648
- this.C = C | 0;
649
- this.D = D | 0;
650
- this.E = E | 0;
651
- this.F = F | 0;
652
- this.G = G | 0;
653
- this.H = H | 0;
1030
+ /**
1031
+ * Creates an insufficient balance error.
1032
+ *
1033
+ * @param options - Error options containing required and available amounts
1034
+ */
1035
+ static insufficientBalance({
1036
+ required,
1037
+ available
1038
+ }) {
1039
+ return new _SplTokenError({
1040
+ code: "INSUFFICIENT_BALANCE" /* INSUFFICIENT_BALANCE */,
1041
+ message: `Insufficient balance: required ${required}, available ${available}`,
1042
+ details: { required: required.toString(), available: available.toString() }
1043
+ });
654
1044
  }
655
- process(view, offset) {
656
- for (let i = 0; i < 16; i++, offset += 4)
657
- SHA256_W[i] = view.getUint32(offset, false);
658
- for (let i = 16; i < 64; i++) {
659
- const W15 = SHA256_W[i - 15];
660
- const W2 = SHA256_W[i - 2];
661
- const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
662
- const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
663
- SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
664
- }
665
- let { A, B, C, D, E, F, G, H } = this;
666
- for (let i = 0; i < 64; i++) {
667
- const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
668
- const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;
669
- const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
670
- const T2 = sigma0 + Maj(A, B, C) | 0;
671
- H = G;
672
- G = F;
673
- F = E;
674
- E = D + T1 | 0;
675
- D = C;
676
- C = B;
677
- B = A;
678
- A = T1 + T2 | 0;
679
- }
680
- A = A + this.A | 0;
681
- B = B + this.B | 0;
682
- C = C + this.C | 0;
683
- D = D + this.D | 0;
684
- E = E + this.E | 0;
685
- F = F + this.F | 0;
686
- G = G + this.G | 0;
687
- H = H + this.H | 0;
688
- this.set(A, B, C, D, E, F, G, H);
1045
+ /**
1046
+ * Creates an invalid extension error.
1047
+ *
1048
+ * @param options - Error options containing the reason
1049
+ */
1050
+ static invalidExtension({ reason }) {
1051
+ return new _SplTokenError({
1052
+ code: "INVALID_EXTENSION" /* INVALID_EXTENSION */,
1053
+ message: `Invalid extension: ${reason}`
1054
+ });
689
1055
  }
690
- roundClean() {
691
- clean(SHA256_W);
1056
+ /**
1057
+ * Creates a PDA derivation failed error.
1058
+ *
1059
+ * @param options - Error options containing the reason
1060
+ */
1061
+ static pdaDerivationFailed({ reason }) {
1062
+ return new _SplTokenError({
1063
+ code: "PDA_DERIVATION_FAILED" /* PDA_DERIVATION_FAILED */,
1064
+ message: `PDA derivation failed: ${reason}`
1065
+ });
692
1066
  }
693
- destroy() {
694
- this.set(0, 0, 0, 0, 0, 0, 0, 0);
695
- clean(this.buffer);
1067
+ /**
1068
+ * Creates an invalid metadata error.
1069
+ *
1070
+ * @param options - Error options containing the reason
1071
+ */
1072
+ static invalidMetadata({ reason }) {
1073
+ return new _SplTokenError({
1074
+ code: "INVALID_METADATA" /* INVALID_METADATA */,
1075
+ message: `Invalid metadata: ${reason}`
1076
+ });
696
1077
  }
697
- };
698
- var _SHA256 = class extends SHA2_32B {
699
- // We cannot use array here since array allows indexing by variable
700
- // which means optimizer/compiler cannot use registers.
701
- A = SHA256_IV[0] | 0;
702
- B = SHA256_IV[1] | 0;
703
- C = SHA256_IV[2] | 0;
704
- D = SHA256_IV[3] | 0;
705
- E = SHA256_IV[4] | 0;
706
- F = SHA256_IV[5] | 0;
707
- G = SHA256_IV[6] | 0;
708
- H = SHA256_IV[7] | 0;
709
- constructor() {
710
- super(32);
1078
+ /**
1079
+ * Creates an account not initialized error.
1080
+ *
1081
+ * @param options - Error options containing the address
1082
+ */
1083
+ static accountNotInitialized({ address }) {
1084
+ return new _SplTokenError({
1085
+ code: "ACCOUNT_NOT_INITIALIZED" /* ACCOUNT_NOT_INITIALIZED */,
1086
+ message: `Account not initialized: ${address}`,
1087
+ details: { address }
1088
+ });
711
1089
  }
712
1090
  };
713
- var sha256 = /* @__PURE__ */ createHasher(
714
- () => new _SHA256(),
715
- /* @__PURE__ */ oidNist(1)
716
- );
1091
+
1092
+ // src/pda/ata.ts
717
1093
  function createProgramAddress({
718
1094
  seeds,
719
1095
  programId
@@ -745,29 +1121,418 @@ function createProgramAddress({
745
1121
  };
746
1122
  }
747
1123
  }
748
- return null;
749
- }
750
- function findAssociatedTokenAddress({
751
- wallet,
752
- mint,
753
- programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
754
- }) {
755
- const associatedTokenProgramId = tsCdk.PublicKey.fromString(ASSOCIATED_TOKEN_PROGRAM_ID);
756
- const seeds = [wallet.toBytes(), programId.toBytes(), mint.toBytes()];
757
- const result = createProgramAddress({ seeds, programId: associatedTokenProgramId });
758
- if (!result) {
759
- throw SplTokenError.pdaDerivationFailed({
760
- reason: `Could not find valid PDA for wallet=${wallet.toString()}, mint=${mint.toString()}`
761
- });
762
- }
763
- return result;
1124
+ return null;
1125
+ }
1126
+ function findAssociatedTokenAddress({
1127
+ wallet,
1128
+ mint,
1129
+ programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
1130
+ }) {
1131
+ const associatedTokenProgramId = tsCdk.PublicKey.fromString(ASSOCIATED_TOKEN_PROGRAM_ID);
1132
+ const seeds = [wallet.toBytes(), programId.toBytes(), mint.toBytes()];
1133
+ const result = createProgramAddress({ seeds, programId: associatedTokenProgramId });
1134
+ if (!result) {
1135
+ throw SplTokenError.pdaDerivationFailed({
1136
+ reason: `Could not find valid PDA for wallet=${wallet.toString()}, mint=${mint.toString()}`
1137
+ });
1138
+ }
1139
+ return result;
1140
+ }
1141
+ function getAssociatedTokenAddressSync({
1142
+ wallet,
1143
+ mint,
1144
+ programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
1145
+ }) {
1146
+ return findAssociatedTokenAddress({ wallet, mint, programId }).address;
1147
+ }
1148
+
1149
+ // src/builders/mint-builder.ts
1150
+ var MintBuilder = class _MintBuilder {
1151
+ client;
1152
+ programId;
1153
+ // Default of 9 matches SOL and most major Solana tokens (e.g. USDC uses 6, native SOL uses 9).
1154
+ // SPL Token-2022 stores decimals as a u8, so the valid range is 0–255.
1155
+ decimals = 9;
1156
+ mintAuthority = null;
1157
+ freezeAuthority = null;
1158
+ metadata = null;
1159
+ transferFee = null;
1160
+ nonTransferable = false;
1161
+ permanentDelegate = null;
1162
+ transferHook = null;
1163
+ initialSupply = null;
1164
+ constructor(tokenClient, client) {
1165
+ this.client = client;
1166
+ this.programId = tokenClient.getProgramId();
1167
+ }
1168
+ /**
1169
+ * Creates a new MintBuilder instance.
1170
+ *
1171
+ * @param tokenClient - SplTokenClient instance
1172
+ * @returns A new MintBuilder
1173
+ *
1174
+ * @example
1175
+ * ```typescript
1176
+ * const builder = MintBuilder.create(tokenClient);
1177
+ * ```
1178
+ */
1179
+ static create(tokenClient) {
1180
+ return new _MintBuilder(tokenClient, tokenClient.getRialoClient());
1181
+ }
1182
+ /**
1183
+ * Sets the number of decimals for the token.
1184
+ *
1185
+ * SPL Token-2022 stores decimals as a u8, so values from 0 to 255 are
1186
+ * valid at the protocol level. Common choices are 6 (USDC-style) or 9
1187
+ * (SOL-style). Values above 9 are uncommon on Solana but fully supported.
1188
+ *
1189
+ * @param decimals - Number of decimals (0-255)
1190
+ * @returns this for chaining
1191
+ */
1192
+ withDecimals(decimals) {
1193
+ if (decimals < 0 || decimals > 255) {
1194
+ throw new Error("Decimals must be between 0 and 255");
1195
+ }
1196
+ this.decimals = decimals;
1197
+ return this;
1198
+ }
1199
+ /**
1200
+ * Sets the mint authority.
1201
+ *
1202
+ * @param authority - Public key of the mint authority
1203
+ * @returns this for chaining
1204
+ */
1205
+ withMintAuthority(authority) {
1206
+ this.mintAuthority = authority;
1207
+ return this;
1208
+ }
1209
+ /**
1210
+ * Sets the freeze authority.
1211
+ *
1212
+ * @param authority - Public key of the freeze authority
1213
+ * @returns this for chaining
1214
+ */
1215
+ withFreezeAuthority(authority) {
1216
+ this.freezeAuthority = authority;
1217
+ return this;
1218
+ }
1219
+ /**
1220
+ * Configures token metadata extension.
1221
+ *
1222
+ * This enables both MetadataPointer and TokenMetadata extensions,
1223
+ * with the metadata stored directly on the mint account.
1224
+ *
1225
+ * @param metadata - Token metadata configuration
1226
+ * @returns this for chaining
1227
+ */
1228
+ withMetadata(metadata) {
1229
+ this.metadata = metadata;
1230
+ return this;
1231
+ }
1232
+ /**
1233
+ * Configures transfer fee extension.
1234
+ *
1235
+ * @param config - Transfer fee configuration
1236
+ * @returns this for chaining
1237
+ */
1238
+ withTransferFee(config) {
1239
+ if (this.nonTransferable) {
1240
+ throw new Error("Cannot add transfer fee to non-transferable mint");
1241
+ }
1242
+ this.transferFee = config;
1243
+ return this;
1244
+ }
1245
+ /**
1246
+ * Makes the mint non-transferable.
1247
+ *
1248
+ * Non-transferable tokens (soulbound tokens) cannot be transferred
1249
+ * after minting.
1250
+ *
1251
+ * @returns this for chaining
1252
+ */
1253
+ withNonTransferable() {
1254
+ if (this.transferFee) {
1255
+ throw new Error(
1256
+ "Cannot make mint non-transferable when transfer fee is configured"
1257
+ );
1258
+ }
1259
+ this.nonTransferable = true;
1260
+ return this;
1261
+ }
1262
+ /**
1263
+ * Configures permanent delegate extension.
1264
+ *
1265
+ * A permanent delegate has unrestricted transfer and burn authority
1266
+ * over all token accounts for this mint.
1267
+ *
1268
+ * @param delegate - Public key of the permanent delegate
1269
+ * @returns this for chaining
1270
+ */
1271
+ withPermanentDelegate(delegate) {
1272
+ this.permanentDelegate = delegate;
1273
+ return this;
1274
+ }
1275
+ /**
1276
+ * Configures transfer hook extension.
1277
+ *
1278
+ * A transfer hook invokes a specified program on every token transfer,
1279
+ * enabling custom transfer logic (e.g., compliance checks, royalties).
1280
+ *
1281
+ * @param config - Transfer hook configuration
1282
+ * @returns this for chaining
1283
+ */
1284
+ withTransferHook(config) {
1285
+ this.transferHook = config;
1286
+ return this;
1287
+ }
1288
+ /**
1289
+ * Configures initial token supply to mint after creation.
1290
+ *
1291
+ * The tokens will be minted to an Associated Token Account (ATA)
1292
+ * derived from the destination wallet.
1293
+ *
1294
+ * @param config - Initial supply configuration
1295
+ * @returns this for chaining
1296
+ */
1297
+ withInitialSupply(config) {
1298
+ this.initialSupply = config;
1299
+ return this;
1300
+ }
1301
+ /**
1302
+ * Builds the mint transaction without sending.
1303
+ *
1304
+ * @param options - Build options
1305
+ * @returns Build result with transaction and addresses
1306
+ *
1307
+ * @example
1308
+ * ```typescript
1309
+ * const { transaction, mintAddress } = await builder.build({
1310
+ * payer: authority,
1311
+ * mintKeypair,
1312
+ * validFrom: BigInt(Date.now()),
1313
+ * });
1314
+ *
1315
+ * // Sign manually
1316
+ * const signed = transaction.sign(authorityKeypair).sign(mintKeypair);
1317
+ * await client.sendAndConfirmTransaction(signed.serialize());
1318
+ * ```
1319
+ */
1320
+ async build(options) {
1321
+ const { payer, mintKeypair, validFrom } = options;
1322
+ const mintAddress = mintKeypair.publicKey;
1323
+ if (!this.mintAuthority) {
1324
+ throw new Error(
1325
+ "Mint authority is required. Call withMintAuthority() first."
1326
+ );
1327
+ }
1328
+ const extensions = this.getExtensions();
1329
+ const createAccountExtensions = extensions.filter(
1330
+ (ext) => ext !== 19 /* TokenMetadata */
1331
+ );
1332
+ const createAccountSize = getMintSizeWithExtensions({
1333
+ extensions: createAccountExtensions,
1334
+ metadataSize: void 0
1335
+ });
1336
+ let rentSize = createAccountSize;
1337
+ if (this.metadata) {
1338
+ const metadataSize = getMetadataExtensionSize({
1339
+ name: this.metadata.name,
1340
+ symbol: this.metadata.symbol,
1341
+ uri: this.metadata.uri,
1342
+ additionalMetadata: this.metadata.additionalMetadata
1343
+ });
1344
+ rentSize = getMintSizeWithExtensions({
1345
+ extensions,
1346
+ metadataSize
1347
+ });
1348
+ }
1349
+ const rent = await this.client.getMinimumBalanceForRentExemption(
1350
+ BigInt(rentSize)
1351
+ );
1352
+ const instructions = [];
1353
+ instructions.push(
1354
+ tsCdk.createAccount(
1355
+ payer,
1356
+ mintAddress,
1357
+ rent,
1358
+ BigInt(createAccountSize),
1359
+ this.programId
1360
+ )
1361
+ );
1362
+ if (this.metadata) {
1363
+ instructions.push(
1364
+ initializeMetadataPointerInstruction({
1365
+ mint: mintAddress,
1366
+ authority: this.mintAuthority,
1367
+ metadataAddress: mintAddress,
1368
+ // Self-referential for on-mint metadata
1369
+ programId: this.programId
1370
+ })
1371
+ );
1372
+ }
1373
+ if (this.transferFee) {
1374
+ instructions.push(
1375
+ initializeTransferFeeConfigInstruction({
1376
+ mint: mintAddress,
1377
+ transferFeeConfigAuthority: this.transferFee.transferFeeConfigAuthority,
1378
+ withdrawWithheldAuthority: this.transferFee.withdrawWithheldAuthority,
1379
+ transferFeeBasisPoints: this.transferFee.transferFeeBasisPoints,
1380
+ maximumFee: this.transferFee.maximumFee,
1381
+ programId: this.programId
1382
+ })
1383
+ );
1384
+ }
1385
+ if (this.nonTransferable) {
1386
+ instructions.push(
1387
+ initializeNonTransferableMintInstruction({
1388
+ mint: mintAddress,
1389
+ programId: this.programId
1390
+ })
1391
+ );
1392
+ }
1393
+ if (this.permanentDelegate) {
1394
+ instructions.push(
1395
+ initializePermanentDelegateInstruction({
1396
+ mint: mintAddress,
1397
+ delegate: this.permanentDelegate,
1398
+ programId: this.programId
1399
+ })
1400
+ );
1401
+ }
1402
+ if (this.transferHook) {
1403
+ instructions.push(
1404
+ initializeTransferHookInstruction({
1405
+ mint: mintAddress,
1406
+ authority: this.transferHook.authority,
1407
+ hookProgramId: this.transferHook.programId,
1408
+ programId: this.programId
1409
+ })
1410
+ );
1411
+ }
1412
+ instructions.push(
1413
+ initializeMintInstruction({
1414
+ mint: mintAddress,
1415
+ decimals: this.decimals,
1416
+ mintAuthority: this.mintAuthority,
1417
+ freezeAuthority: this.freezeAuthority ?? void 0,
1418
+ programId: this.programId
1419
+ })
1420
+ );
1421
+ if (this.metadata) {
1422
+ instructions.push(
1423
+ initializeTokenMetadataInstruction({
1424
+ mint: mintAddress,
1425
+ updateAuthority: this.mintAuthority,
1426
+ mintAuthority: this.mintAuthority,
1427
+ name: this.metadata.name,
1428
+ symbol: this.metadata.symbol,
1429
+ uri: this.metadata.uri,
1430
+ additionalMetadata: this.metadata.additionalMetadata,
1431
+ programId: this.programId
1432
+ })
1433
+ );
1434
+ }
1435
+ let ataAddress;
1436
+ if (this.initialSupply) {
1437
+ ataAddress = getAssociatedTokenAddressSync({
1438
+ wallet: this.initialSupply.destination,
1439
+ mint: mintAddress,
1440
+ programId: this.programId
1441
+ });
1442
+ instructions.push(
1443
+ createAssociatedTokenAccountIdempotentInstruction({
1444
+ payer,
1445
+ associatedToken: ataAddress,
1446
+ owner: this.initialSupply.destination,
1447
+ mint: mintAddress,
1448
+ programId: this.programId
1449
+ })
1450
+ );
1451
+ instructions.push(
1452
+ mintToInstruction({
1453
+ mint: mintAddress,
1454
+ destination: ataAddress,
1455
+ authority: this.mintAuthority,
1456
+ amount: this.initialSupply.amount,
1457
+ programId: this.programId
1458
+ })
1459
+ );
1460
+ }
1461
+ const configHashPrefix = await this.client.getConfigHashPrefix();
1462
+ const builder = tsCdk.TransactionBuilder.create().setPayer(payer).setValidFrom(validFrom).setConfigHashPrefix(configHashPrefix);
1463
+ for (const instruction of instructions) {
1464
+ builder.addInstruction(instruction);
1465
+ }
1466
+ return {
1467
+ transaction: builder.build(),
1468
+ mintAddress,
1469
+ ataAddress
1470
+ };
1471
+ }
1472
+ /**
1473
+ * Builds, signs, and sends the mint transaction.
1474
+ *
1475
+ * @param options - Send options including signers
1476
+ * @returns Send result with signature and addresses
1477
+ *
1478
+ * @example
1479
+ * ```typescript
1480
+ * const { signature, mintAddress } = await builder.send({
1481
+ * payer: authority,
1482
+ * mintKeypair,
1483
+ * validFrom: BigInt(Date.now()),
1484
+ * signers: [authorityKeypair, mintKeypair],
1485
+ * });
1486
+ * ```
1487
+ */
1488
+ async send(options) {
1489
+ const { signers, ...buildOptions } = options;
1490
+ if (signers.length === 0) {
1491
+ throw new Error("At least one signer is required");
1492
+ }
1493
+ const { transaction, mintAddress, ataAddress } = await this.build(buildOptions);
1494
+ let signedTx = transaction;
1495
+ for (const signer of signers) {
1496
+ signedTx = signedTx.sign(signer);
1497
+ }
1498
+ const result = await this.client.sendAndConfirmTransaction(
1499
+ signedTx.serialize()
1500
+ );
1501
+ return {
1502
+ signature: result.signature,
1503
+ mintAddress,
1504
+ ataAddress
1505
+ };
1506
+ }
1507
+ /**
1508
+ * Returns the list of extensions that will be enabled.
1509
+ */
1510
+ getExtensions() {
1511
+ const extensions = [];
1512
+ if (this.metadata) {
1513
+ extensions.push(18 /* MetadataPointer */);
1514
+ extensions.push(19 /* TokenMetadata */);
1515
+ }
1516
+ if (this.transferFee) {
1517
+ extensions.push(1 /* TransferFeeConfig */);
1518
+ }
1519
+ if (this.nonTransferable) {
1520
+ extensions.push(9 /* NonTransferable */);
1521
+ }
1522
+ if (this.permanentDelegate) {
1523
+ extensions.push(12 /* PermanentDelegate */);
1524
+ }
1525
+ if (this.transferHook) {
1526
+ extensions.push(14 /* TransferHook */);
1527
+ }
1528
+ return extensions;
1529
+ }
1530
+ };
1531
+ function readU16LE({ data, offset }) {
1532
+ return data[offset] | data[offset + 1] << 8;
764
1533
  }
765
- function getAssociatedTokenAddressSync({
766
- wallet,
767
- mint,
768
- programId = tsCdk.PublicKey.fromString(TOKEN_2022_PROGRAM_ID)
769
- }) {
770
- return findAssociatedTokenAddress({ wallet, mint, programId }).address;
1534
+ function readU32LE({ data, offset }) {
1535
+ return (data[offset] | data[offset + 1] << 8 | data[offset + 2] << 16 | data[offset + 3] << 24) >>> 0;
771
1536
  }
772
1537
  function readU64LE({ data, offset }) {
773
1538
  let value = 0n;
@@ -776,13 +1541,15 @@ function readU64LE({ data, offset }) {
776
1541
  }
777
1542
  return value;
778
1543
  }
779
- function readU32LE({ data, offset }) {
780
- return (data[offset] | data[offset + 1] << 8 | data[offset + 2] << 16 | data[offset + 3] << 24) >>> 0;
781
- }
782
1544
  function readCOptionPubkey({
783
1545
  data,
784
1546
  offset
785
1547
  }) {
1548
+ if (data.length < offset + 4 + PUBKEY_SIZE) {
1549
+ throw SplTokenError.invalidExtension({
1550
+ reason: `COption<Pubkey> out of bounds: need ${offset + 4 + PUBKEY_SIZE} bytes, got ${data.length}`
1551
+ });
1552
+ }
786
1553
  const tag = readU32LE({ data, offset });
787
1554
  if (tag === COPTION_SOME) {
788
1555
  const pubkeyBytes = data.slice(offset + 4, offset + 4 + PUBKEY_SIZE);
@@ -790,122 +1557,192 @@ function readCOptionPubkey({
790
1557
  }
791
1558
  return null;
792
1559
  }
793
- function parseMintAccount({ address, data }) {
794
- if (data.length < MINT_SIZE) {
795
- throw SplTokenError.invalidMint({
796
- reason: `Account data too short: expected at least ${MINT_SIZE} bytes, got ${data.length}`
1560
+ function readOptionalNonZeroPubkey({
1561
+ data,
1562
+ offset
1563
+ }) {
1564
+ const pubkeyBytes = data.slice(offset, offset + PUBKEY_SIZE);
1565
+ const isZero = pubkeyBytes.every((byte) => byte === 0);
1566
+ return isZero ? null : tsCdk.PublicKey.fromBytes(pubkeyBytes);
1567
+ }
1568
+ function readPubkey({ data, offset }) {
1569
+ return tsCdk.PublicKey.fromBytes(data.slice(offset, offset + PUBKEY_SIZE));
1570
+ }
1571
+
1572
+ // src/state/extensions.ts
1573
+ function parseTlvExtensions({
1574
+ data,
1575
+ extensionsOffset
1576
+ }) {
1577
+ const extensions = [];
1578
+ let offset = extensionsOffset;
1579
+ while (offset + TLV_TYPE_SIZE + TLV_LENGTH_SIZE <= data.length) {
1580
+ const type = readU16LE({ data, offset });
1581
+ const length = readU16LE({ data, offset: offset + TLV_TYPE_SIZE });
1582
+ if (type === 0 /* Uninitialized */ && length === 0) {
1583
+ break;
1584
+ }
1585
+ const dataStart = offset + TLV_TYPE_SIZE + TLV_LENGTH_SIZE;
1586
+ const dataEnd = dataStart + length;
1587
+ if (dataEnd > data.length) {
1588
+ throw SplTokenError.invalidExtension({
1589
+ reason: `Extension data extends beyond buffer: type=${type}, length=${length}`
1590
+ });
1591
+ }
1592
+ extensions.push({
1593
+ type,
1594
+ data: data.slice(dataStart, dataEnd)
797
1595
  });
1596
+ offset = dataEnd;
798
1597
  }
799
- const mintAuthority = readCOptionPubkey({ data, offset: 0 });
800
- const supply = readU64LE({ data, offset: MINT_SUPPLY_OFFSET });
801
- const decimals = data[MINT_DECIMALS_OFFSET];
802
- const isInitialized = data[MINT_IS_INITIALIZED_OFFSET] !== 0;
803
- const freezeAuthority = readCOptionPubkey({ data, offset: MINT_FREEZE_AUTHORITY_OFFSET });
804
- if (!isInitialized) {
805
- throw SplTokenError.accountNotInitialized({ address: address.toString() });
1598
+ return extensions;
1599
+ }
1600
+ function getMintExtensions({ data }) {
1601
+ if (data.length <= TOKEN_ACCOUNT_SIZE) {
1602
+ return [];
1603
+ }
1604
+ const accountType = data[TOKEN_ACCOUNT_SIZE];
1605
+ if (accountType !== 1 /* Mint */) {
1606
+ return [];
806
1607
  }
1608
+ return parseTlvExtensions({ data, extensionsOffset: MINT_EXTENSIONS_OFFSET });
1609
+ }
1610
+ function getTokenAccountExtensions({ data }) {
1611
+ if (data.length <= TOKEN_ACCOUNT_SIZE) {
1612
+ return [];
1613
+ }
1614
+ const accountType = data[TOKEN_ACCOUNT_SIZE];
1615
+ if (accountType !== 2 /* Account */) {
1616
+ return [];
1617
+ }
1618
+ return parseTlvExtensions({
1619
+ data,
1620
+ extensionsOffset: TOKEN_ACCOUNT_EXTENSIONS_OFFSET
1621
+ });
1622
+ }
1623
+
1624
+ // src/state/extension-parsers.ts
1625
+ var TRANSFER_FEE_CONFIG_SIZE = 108;
1626
+ var TRANSFER_FEE_AMOUNT_SIZE = 8;
1627
+ var METADATA_POINTER_SIZE = 64;
1628
+ var PUBKEY_SIZE2 = 32;
1629
+ var PERMANENT_DELEGATE_SIZE = 32;
1630
+ var TRANSFER_HOOK_SIZE = 64;
1631
+ var TOKEN_METADATA_MAX_SIZE = 65535;
1632
+ function parseTransferFee({ data, offset }) {
1633
+ const epoch = readU64LE({ data, offset });
1634
+ const maximumFee = readU64LE({ data, offset: offset + 8 });
1635
+ const transferFeeBasisPoints = readU16LE({ data, offset: offset + 16 });
807
1636
  return {
808
- address,
809
- supply,
810
- decimals,
811
- isInitialized,
812
- mintAuthority,
813
- freezeAuthority
1637
+ epoch,
1638
+ maximumFee,
1639
+ transferFeeBasisPoints
814
1640
  };
815
1641
  }
816
- function readU64LE2({ data, offset }) {
817
- let value = 0n;
818
- for (let i = 0; i < 8; i++) {
819
- value |= BigInt(data[offset + i]) << BigInt(i * 8);
1642
+ function parseTransferFeeConfigExtension({
1643
+ data
1644
+ }) {
1645
+ if (data.length < TRANSFER_FEE_CONFIG_SIZE) {
1646
+ throw SplTokenError.invalidExtension({
1647
+ reason: `TransferFeeConfig too short: expected ${TRANSFER_FEE_CONFIG_SIZE} bytes, got ${data.length}`
1648
+ });
820
1649
  }
821
- return value;
822
- }
823
- function readU32LE2({ data, offset }) {
824
- return (data[offset] | data[offset + 1] << 8 | data[offset + 2] << 16 | data[offset + 3] << 24) >>> 0;
1650
+ const transferFeeConfigAuthority = readOptionalNonZeroPubkey({
1651
+ data,
1652
+ offset: 0
1653
+ });
1654
+ const withdrawWithheldAuthority = readOptionalNonZeroPubkey({
1655
+ data,
1656
+ offset: 32
1657
+ });
1658
+ const withheldAmount = readU64LE({ data, offset: 64 });
1659
+ const olderTransferFee = parseTransferFee({ data, offset: 72 });
1660
+ const newerTransferFee = parseTransferFee({ data, offset: 90 });
1661
+ return {
1662
+ transferFeeConfigAuthority,
1663
+ withdrawWithheldAuthority,
1664
+ withheldAmount,
1665
+ olderTransferFee,
1666
+ newerTransferFee
1667
+ };
825
1668
  }
826
- function readCOptionPubkey2({
827
- data,
828
- offset
1669
+ function parseTransferFeeAmountExtension({
1670
+ data
829
1671
  }) {
830
- const tag = readU32LE2({ data, offset });
831
- if (tag === COPTION_SOME) {
832
- const pubkeyBytes = data.slice(offset + 4, offset + 4 + PUBKEY_SIZE);
833
- return tsCdk.PublicKey.fromBytes(pubkeyBytes);
1672
+ if (data.length < TRANSFER_FEE_AMOUNT_SIZE) {
1673
+ throw SplTokenError.invalidExtension({
1674
+ reason: `TransferFeeAmount too short: expected ${TRANSFER_FEE_AMOUNT_SIZE} bytes, got ${data.length}`
1675
+ });
834
1676
  }
835
- return null;
1677
+ return {
1678
+ withheldAmount: readU64LE({ data, offset: 0 })
1679
+ };
836
1680
  }
837
- function readCOptionU64({ data, offset }) {
838
- const tag = readU32LE2({ data, offset });
839
- if (tag === COPTION_SOME) {
840
- return readU64LE2({ data, offset: offset + 4 });
1681
+ function parseNonTransferableExtension({
1682
+ data
1683
+ }) {
1684
+ if (data.length !== 0) {
1685
+ throw SplTokenError.invalidExtension({
1686
+ reason: `NonTransferable has unexpected length: expected 0 bytes, got ${data.length}`
1687
+ });
841
1688
  }
842
- return null;
1689
+ return { isNonTransferable: true };
843
1690
  }
844
- function parseTokenAccount({ address, data }) {
845
- if (data.length < TOKEN_ACCOUNT_SIZE) {
846
- throw SplTokenError.invalidTokenAccount({
847
- reason: `Account data too short: expected at least ${TOKEN_ACCOUNT_SIZE} bytes, got ${data.length}`
1691
+ function parseNonTransferableAccountExtension({
1692
+ data
1693
+ }) {
1694
+ if (data.length !== 0) {
1695
+ throw SplTokenError.invalidExtension({
1696
+ reason: `NonTransferableAccount has unexpected length: expected 0 bytes, got ${data.length}`
848
1697
  });
849
1698
  }
850
- const mintBytes = data.slice(TOKEN_ACCOUNT_MINT_OFFSET, TOKEN_ACCOUNT_MINT_OFFSET + PUBKEY_SIZE);
851
- const mint = tsCdk.PublicKey.fromBytes(mintBytes);
852
- const ownerBytes = data.slice(
853
- TOKEN_ACCOUNT_OWNER_OFFSET,
854
- TOKEN_ACCOUNT_OWNER_OFFSET + PUBKEY_SIZE
855
- );
856
- const owner = tsCdk.PublicKey.fromBytes(ownerBytes);
857
- const amount = readU64LE2({ data, offset: TOKEN_ACCOUNT_AMOUNT_OFFSET });
858
- const delegate = readCOptionPubkey2({ data, offset: TOKEN_ACCOUNT_DELEGATE_OFFSET });
859
- const stateValue = data[TOKEN_ACCOUNT_STATE_OFFSET];
860
- if (stateValue > 2) {
861
- throw SplTokenError.invalidTokenAccount({ reason: `Invalid account state: ${stateValue}` });
1699
+ return { isNonTransferableAccount: true };
1700
+ }
1701
+ function parsePermanentDelegateExtension({
1702
+ data
1703
+ }) {
1704
+ if (data.length < PERMANENT_DELEGATE_SIZE) {
1705
+ throw SplTokenError.invalidExtension({
1706
+ reason: `PermanentDelegate too short: expected ${PERMANENT_DELEGATE_SIZE} bytes, got ${data.length}`
1707
+ });
862
1708
  }
863
- const state = stateValue;
864
- if (state === 0 /* Uninitialized */) {
865
- throw SplTokenError.accountNotInitialized({ address: address.toString() });
1709
+ return { delegate: readOptionalNonZeroPubkey({ data, offset: 0 }) };
1710
+ }
1711
+ function parseTransferHookExtension({ data }) {
1712
+ if (data.length < TRANSFER_HOOK_SIZE) {
1713
+ throw SplTokenError.invalidExtension({
1714
+ reason: `TransferHook too short: expected ${TRANSFER_HOOK_SIZE} bytes, got ${data.length}`
1715
+ });
866
1716
  }
867
- const isNative = readCOptionU64({ data, offset: TOKEN_ACCOUNT_IS_NATIVE_OFFSET });
868
- const delegatedAmount = readU64LE2({ data, offset: TOKEN_ACCOUNT_DELEGATED_AMOUNT_OFFSET });
869
- const closeAuthority = readCOptionPubkey2({ data, offset: TOKEN_ACCOUNT_CLOSE_AUTHORITY_OFFSET });
870
1717
  return {
871
- address,
872
- mint,
873
- owner,
874
- amount,
875
- delegate,
876
- state,
877
- isNative,
878
- delegatedAmount,
879
- closeAuthority
1718
+ authority: readOptionalNonZeroPubkey({ data, offset: 0 }),
1719
+ programId: readOptionalNonZeroPubkey({ data, offset: 32 })
880
1720
  };
881
1721
  }
882
- function readU16LE({ data, offset }) {
883
- return data[offset] | data[offset + 1] << 8;
884
- }
885
- function readU32LE3({ data, offset }) {
886
- return (data[offset] | data[offset + 1] << 8 | data[offset + 2] << 16 | data[offset + 3] << 24) >>> 0;
887
- }
888
- function readCOptionPubkey3({
889
- data,
890
- offset
1722
+ function parseMetadataPointerExtensionData({
1723
+ data
891
1724
  }) {
892
- const tag = readU32LE3({ data, offset });
893
- if (tag === COPTION_SOME) {
894
- const pubkeyBytes = data.slice(offset + 4, offset + 4 + PUBKEY_SIZE);
895
- return tsCdk.PublicKey.fromBytes(pubkeyBytes);
1725
+ if (data.length < METADATA_POINTER_SIZE) {
1726
+ throw SplTokenError.invalidExtension({
1727
+ reason: `MetadataPointer too short: expected ${METADATA_POINTER_SIZE} bytes, got ${data.length}`
1728
+ });
896
1729
  }
897
- return null;
1730
+ const authority = readOptionalNonZeroPubkey({ data, offset: 0 });
1731
+ const metadataAddress = readOptionalNonZeroPubkey({ data, offset: 32 });
1732
+ return { authority, metadataAddress };
898
1733
  }
899
1734
  function readLengthPrefixedString({
900
1735
  data,
901
1736
  offset
902
1737
  }) {
903
1738
  if (offset + 4 > data.length) {
904
- throw SplTokenError.invalidMetadata({ reason: "String length prefix extends beyond data" });
1739
+ throw SplTokenError.invalidExtension({
1740
+ reason: "String length prefix extends beyond data"
1741
+ });
905
1742
  }
906
- const length = readU32LE3({ data, offset });
1743
+ const length = readU32LE({ data, offset });
907
1744
  if (offset + 4 + length > data.length) {
908
- throw SplTokenError.invalidMetadata({
1745
+ throw SplTokenError.invalidExtension({
909
1746
  reason: `String data extends beyond buffer: need ${length} bytes at offset ${offset + 4}`
910
1747
  });
911
1748
  }
@@ -913,47 +1750,140 @@ function readLengthPrefixedString({
913
1750
  try {
914
1751
  const str = new TextDecoder().decode(stringBytes);
915
1752
  return [str, 4 + length];
916
- } catch (error) {
917
- throw SplTokenError.invalidMetadata({
1753
+ } catch {
1754
+ throw SplTokenError.invalidExtension({
918
1755
  reason: `Invalid UTF-8 string at offset ${offset}`
919
1756
  });
920
1757
  }
921
1758
  }
922
- function parseExtensions({
1759
+ function parseTokenMetadataExtensionData({ data }) {
1760
+ if (data.length < 64) {
1761
+ throw SplTokenError.invalidExtension({
1762
+ reason: `TokenMetadata too short: expected at least 64 bytes, got ${data.length}`
1763
+ });
1764
+ }
1765
+ if (data.length > TOKEN_METADATA_MAX_SIZE) {
1766
+ throw SplTokenError.invalidExtension({
1767
+ reason: `TokenMetadata too large: maximum ${TOKEN_METADATA_MAX_SIZE} bytes, got ${data.length}`
1768
+ });
1769
+ }
1770
+ let offset = 0;
1771
+ const updateAuthority = readOptionalNonZeroPubkey({ data, offset });
1772
+ offset += PUBKEY_SIZE2;
1773
+ const mint = readPubkey({ data, offset });
1774
+ offset += PUBKEY_SIZE2;
1775
+ const [name, nameLen] = readLengthPrefixedString({ data, offset });
1776
+ offset += nameLen;
1777
+ const [symbol, symbolLen] = readLengthPrefixedString({ data, offset });
1778
+ offset += symbolLen;
1779
+ const [uri, uriLen] = readLengthPrefixedString({ data, offset });
1780
+ offset += uriLen;
1781
+ const additionalMetadata = [];
1782
+ if (offset + 4 <= data.length) {
1783
+ const numEntries = readU32LE({ data, offset });
1784
+ offset += 4;
1785
+ for (let i = 0; i < numEntries && offset < data.length; i++) {
1786
+ const [key, keyLen] = readLengthPrefixedString({ data, offset });
1787
+ offset += keyLen;
1788
+ const [value, valueLen] = readLengthPrefixedString({ data, offset });
1789
+ offset += valueLen;
1790
+ additionalMetadata.push([key, value]);
1791
+ }
1792
+ }
1793
+ return {
1794
+ updateAuthority,
1795
+ mint,
1796
+ name,
1797
+ symbol,
1798
+ uri,
1799
+ additionalMetadata
1800
+ };
1801
+ }
1802
+ function parseExtension({ extension }) {
1803
+ switch (extension.type) {
1804
+ case 1 /* TransferFeeConfig */:
1805
+ return {
1806
+ type: 1 /* TransferFeeConfig */,
1807
+ value: parseTransferFeeConfigExtension({ data: extension.data })
1808
+ };
1809
+ case 2 /* TransferFeeAmount */:
1810
+ return {
1811
+ type: 2 /* TransferFeeAmount */,
1812
+ value: parseTransferFeeAmountExtension({ data: extension.data })
1813
+ };
1814
+ case 9 /* NonTransferable */:
1815
+ return {
1816
+ type: 9 /* NonTransferable */,
1817
+ value: parseNonTransferableExtension({ data: extension.data })
1818
+ };
1819
+ case 13 /* NonTransferableAccount */:
1820
+ return {
1821
+ type: 13 /* NonTransferableAccount */,
1822
+ value: parseNonTransferableAccountExtension({ data: extension.data })
1823
+ };
1824
+ case 18 /* MetadataPointer */:
1825
+ return {
1826
+ type: 18 /* MetadataPointer */,
1827
+ value: parseMetadataPointerExtensionData({ data: extension.data })
1828
+ };
1829
+ case 19 /* TokenMetadata */:
1830
+ return {
1831
+ type: 19 /* TokenMetadata */,
1832
+ value: parseTokenMetadataExtensionData({ data: extension.data })
1833
+ };
1834
+ case 12 /* PermanentDelegate */:
1835
+ return {
1836
+ type: 12 /* PermanentDelegate */,
1837
+ value: parsePermanentDelegateExtension({ data: extension.data })
1838
+ };
1839
+ case 14 /* TransferHook */:
1840
+ return {
1841
+ type: 14 /* TransferHook */,
1842
+ value: parseTransferHookExtension({ data: extension.data })
1843
+ };
1844
+ default:
1845
+ return null;
1846
+ }
1847
+ }
1848
+ function getMintExtensionStates({ data }) {
1849
+ return getMintExtensions({ data }).map((extension) => parseExtension({ extension })).filter((extension) => extension !== null);
1850
+ }
1851
+ function getTokenAccountExtensionStates({ data }) {
1852
+ return getTokenAccountExtensions({ data }).map((extension) => parseExtension({ extension })).filter((extension) => extension !== null);
1853
+ }
1854
+ function readLengthPrefixedString2({
923
1855
  data,
924
- extensionsOffset
1856
+ offset
925
1857
  }) {
926
- const extensions = [];
927
- let offset = extensionsOffset;
928
- while (offset + TLV_TYPE_SIZE + TLV_LENGTH_SIZE <= data.length) {
929
- const type = readU16LE({ data, offset });
930
- const length = readU16LE({ data, offset: offset + TLV_TYPE_SIZE });
931
- if (type === 0 && length === 0) {
932
- break;
933
- }
934
- const dataStart = offset + TLV_TYPE_SIZE + TLV_LENGTH_SIZE;
935
- const dataEnd = dataStart + length;
936
- if (dataEnd > data.length) {
937
- throw SplTokenError.invalidExtension({
938
- reason: `Extension data extends beyond buffer: type=${type}, length=${length}`
939
- });
940
- }
941
- extensions.push({
942
- type,
943
- data: data.slice(dataStart, dataEnd)
1858
+ if (offset + 4 > data.length) {
1859
+ throw SplTokenError.invalidMetadata({
1860
+ reason: "String length prefix extends beyond data"
1861
+ });
1862
+ }
1863
+ const length = readU32LE({ data, offset });
1864
+ if (offset + 4 + length > data.length) {
1865
+ throw SplTokenError.invalidMetadata({
1866
+ reason: `String data extends beyond buffer: need ${length} bytes at offset ${offset + 4}`
1867
+ });
1868
+ }
1869
+ const stringBytes = data.slice(offset + 4, offset + 4 + length);
1870
+ try {
1871
+ const str = new TextDecoder().decode(stringBytes);
1872
+ return [str, 4 + length];
1873
+ } catch {
1874
+ throw SplTokenError.invalidMetadata({
1875
+ reason: `Invalid UTF-8 string at offset ${offset}`
944
1876
  });
945
- offset = dataEnd;
946
1877
  }
947
- return extensions;
948
1878
  }
949
1879
  function parseMetadataPointer({ data }) {
950
- if (data.length < 72) {
1880
+ if (data.length < 64) {
951
1881
  throw SplTokenError.invalidExtension({
952
- reason: `MetadataPointer too short: expected 72 bytes, got ${data.length}`
1882
+ reason: `MetadataPointer too short: expected 64 bytes, got ${data.length}`
953
1883
  });
954
1884
  }
955
- const authority = readCOptionPubkey3({ data, offset: 0 });
956
- const metadataAddress = readCOptionPubkey3({ data, offset: 36 });
1885
+ const authority = readOptionalNonZeroPubkey({ data, offset: 0 });
1886
+ const metadataAddress = readOptionalNonZeroPubkey({ data, offset: 32 });
957
1887
  return { authority, metadataAddress };
958
1888
  }
959
1889
  function parseTokenMetadataExtension({
@@ -971,20 +1901,20 @@ function parseTokenMetadataExtension({
971
1901
  const updateAuthority = isZeroAuthority ? null : tsCdk.PublicKey.fromBytes(updateAuthorityBytes);
972
1902
  offset += PUBKEY_SIZE;
973
1903
  offset += PUBKEY_SIZE;
974
- const [name, nameLen] = readLengthPrefixedString({ data, offset });
1904
+ const [name, nameLen] = readLengthPrefixedString2({ data, offset });
975
1905
  offset += nameLen;
976
- const [symbol, symbolLen] = readLengthPrefixedString({ data, offset });
1906
+ const [symbol, symbolLen] = readLengthPrefixedString2({ data, offset });
977
1907
  offset += symbolLen;
978
- const [uri, uriLen] = readLengthPrefixedString({ data, offset });
1908
+ const [uri, uriLen] = readLengthPrefixedString2({ data, offset });
979
1909
  offset += uriLen;
980
1910
  const additionalMetadata = [];
981
1911
  if (offset + 4 <= data.length) {
982
- const numEntries = readU32LE3({ data, offset });
1912
+ const numEntries = readU32LE({ data, offset });
983
1913
  offset += 4;
984
1914
  for (let i = 0; i < numEntries && offset < data.length; i++) {
985
- const [key, keyLen] = readLengthPrefixedString({ data, offset });
1915
+ const [key, keyLen] = readLengthPrefixedString2({ data, offset });
986
1916
  offset += keyLen;
987
- const [value, valueLen] = readLengthPrefixedString({ data, offset });
1917
+ const [value, valueLen] = readLengthPrefixedString2({ data, offset });
988
1918
  offset += valueLen;
989
1919
  additionalMetadata.push([key, value]);
990
1920
  }
@@ -1002,14 +1932,17 @@ function parseTokenMetadata({
1002
1932
  mint,
1003
1933
  data
1004
1934
  }) {
1005
- if (data.length <= MINT_SIZE) {
1935
+ if (data.length <= TOKEN_ACCOUNT_SIZE) {
1006
1936
  return null;
1007
1937
  }
1008
- const accountType = data[MINT_SIZE];
1938
+ const accountType = data[TOKEN_ACCOUNT_SIZE];
1009
1939
  if (accountType !== 1 /* Mint */) {
1010
1940
  return null;
1011
1941
  }
1012
- const extensions = parseExtensions({ data, extensionsOffset: MINT_EXTENSIONS_OFFSET });
1942
+ const extensions = parseTlvExtensions({
1943
+ data,
1944
+ extensionsOffset: MINT_EXTENSIONS_OFFSET
1945
+ });
1013
1946
  const metadataExt = extensions.find((ext) => ext.type === 19 /* TokenMetadata */);
1014
1947
  if (!metadataExt) {
1015
1948
  return null;
@@ -1019,29 +1952,321 @@ function parseTokenMetadata({
1019
1952
  function parseMetadataPointerExtension({
1020
1953
  data
1021
1954
  }) {
1022
- if (data.length <= MINT_SIZE) {
1955
+ if (data.length <= TOKEN_ACCOUNT_SIZE) {
1023
1956
  return null;
1024
1957
  }
1025
- const accountType = data[MINT_SIZE];
1958
+ const accountType = data[TOKEN_ACCOUNT_SIZE];
1026
1959
  if (accountType !== 1 /* Mint */) {
1027
1960
  return null;
1028
1961
  }
1029
- const extensions = parseExtensions({ data, extensionsOffset: MINT_EXTENSIONS_OFFSET });
1962
+ const extensions = parseTlvExtensions({
1963
+ data,
1964
+ extensionsOffset: MINT_EXTENSIONS_OFFSET
1965
+ });
1030
1966
  const pointerExt = extensions.find((ext) => ext.type === 18 /* MetadataPointer */);
1031
1967
  if (!pointerExt) {
1032
1968
  return null;
1033
1969
  }
1034
1970
  return parseMetadataPointer({ data: pointerExt.data });
1035
1971
  }
1036
- function getMintExtensions({ data }) {
1037
- if (data.length <= MINT_SIZE) {
1972
+
1973
+ // src/state/mint.ts
1974
+ function parseMintAccount({ address, data }) {
1975
+ if (data.length < MINT_SIZE) {
1976
+ throw SplTokenError.invalidMint({
1977
+ reason: `Account data too short: expected at least ${MINT_SIZE} bytes, got ${data.length}`
1978
+ });
1979
+ }
1980
+ const mintAuthority = readCOptionPubkey({ data, offset: 0 });
1981
+ const supply = readU64LE({ data, offset: MINT_SUPPLY_OFFSET });
1982
+ const decimals = data[MINT_DECIMALS_OFFSET];
1983
+ const isInitialized = data[MINT_IS_INITIALIZED_OFFSET] !== 0;
1984
+ const freezeAuthority = readCOptionPubkey({
1985
+ data,
1986
+ offset: MINT_FREEZE_AUTHORITY_OFFSET
1987
+ });
1988
+ if (!isInitialized) {
1989
+ throw SplTokenError.accountNotInitialized({ address: address.toString() });
1990
+ }
1991
+ return {
1992
+ address,
1993
+ supply,
1994
+ decimals,
1995
+ isInitialized,
1996
+ mintAuthority,
1997
+ freezeAuthority
1998
+ };
1999
+ }
2000
+
2001
+ // src/state/token-account.ts
2002
+ function readCOptionU64({ data, offset }) {
2003
+ const tag = readU32LE({ data, offset });
2004
+ if (tag === COPTION_SOME) {
2005
+ return readU64LE({ data, offset: offset + 4 });
2006
+ }
2007
+ return null;
2008
+ }
2009
+ function parseTokenAccount({ address, data }) {
2010
+ if (data.length < TOKEN_ACCOUNT_SIZE) {
2011
+ throw SplTokenError.invalidTokenAccount({
2012
+ reason: `Account data too short: expected at least ${TOKEN_ACCOUNT_SIZE} bytes, got ${data.length}`
2013
+ });
2014
+ }
2015
+ const mint = readPubkey({ data, offset: TOKEN_ACCOUNT_MINT_OFFSET });
2016
+ const owner = readPubkey({ data, offset: TOKEN_ACCOUNT_OWNER_OFFSET });
2017
+ const amount = readU64LE({ data, offset: TOKEN_ACCOUNT_AMOUNT_OFFSET });
2018
+ const delegate = readCOptionPubkey({
2019
+ data,
2020
+ offset: TOKEN_ACCOUNT_DELEGATE_OFFSET
2021
+ });
2022
+ const stateValue = data[TOKEN_ACCOUNT_STATE_OFFSET];
2023
+ if (stateValue > 2) {
2024
+ throw SplTokenError.invalidTokenAccount({
2025
+ reason: `Invalid account state: ${stateValue}`
2026
+ });
2027
+ }
2028
+ const state = stateValue;
2029
+ if (state === 0 /* Uninitialized */) {
2030
+ throw SplTokenError.accountNotInitialized({ address: address.toString() });
2031
+ }
2032
+ const isNative = readCOptionU64({
2033
+ data,
2034
+ offset: TOKEN_ACCOUNT_IS_NATIVE_OFFSET
2035
+ });
2036
+ const delegatedAmount = readU64LE({
2037
+ data,
2038
+ offset: TOKEN_ACCOUNT_DELEGATED_AMOUNT_OFFSET
2039
+ });
2040
+ const closeAuthority = readCOptionPubkey({
2041
+ data,
2042
+ offset: TOKEN_ACCOUNT_CLOSE_AUTHORITY_OFFSET
2043
+ });
2044
+ return {
2045
+ address,
2046
+ mint,
2047
+ owner,
2048
+ amount,
2049
+ delegate,
2050
+ state,
2051
+ isNative,
2052
+ delegatedAmount,
2053
+ closeAuthority
2054
+ };
2055
+ }
2056
+
2057
+ // src/transfer-hook/extra-account-meta.ts
2058
+ var EXTRA_ACCOUNT_META_SIZE = 35;
2059
+ function parseExtraAccountMeta(data, offset) {
2060
+ return {
2061
+ discriminator: data[offset],
2062
+ addressConfig: data.slice(offset + 1, offset + 33),
2063
+ isSigner: data[offset + 33] !== 0,
2064
+ isWritable: data[offset + 34] !== 0
2065
+ };
2066
+ }
2067
+ var EXECUTE_DISCRIMINATOR = sha256(
2068
+ new TextEncoder().encode("rialo-s-spl-transfer-hook-interface:execute")
2069
+ ).slice(0, 8);
2070
+ var TLV_HEADER_SIZE2 = 16;
2071
+ function parseExtraAccountMetaList(data) {
2072
+ if (data.length < TLV_HEADER_SIZE2) {
1038
2073
  return [];
1039
2074
  }
1040
- const accountType = data[MINT_SIZE];
1041
- if (accountType !== 1 /* Mint */) {
2075
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
2076
+ const count = view.getUint32(12, true);
2077
+ if (count === 0) {
1042
2078
  return [];
1043
2079
  }
1044
- return parseExtensions({ data, extensionsOffset: MINT_EXTENSIONS_OFFSET });
2080
+ const entries = [];
2081
+ let cursor = TLV_HEADER_SIZE2;
2082
+ for (let i = 0; i < count; i++) {
2083
+ if (cursor + EXTRA_ACCOUNT_META_SIZE > data.length) {
2084
+ break;
2085
+ }
2086
+ entries.push(parseExtraAccountMeta(data, cursor));
2087
+ cursor += EXTRA_ACCOUNT_META_SIZE;
2088
+ }
2089
+ return entries;
2090
+ }
2091
+ function buildExecuteInstructionData(amount) {
2092
+ const data = new Uint8Array(16);
2093
+ data.set(EXECUTE_DISCRIMINATOR, 0);
2094
+ writeU64LE({ data, offset: 8, value: amount });
2095
+ return data;
2096
+ }
2097
+ function getExtraAccountMetaAddress(mint, hookProgramId) {
2098
+ const [pda] = tsCdk.PublicKey.findProgramAddress(
2099
+ ["extra-account-metas", mint.toBytes()],
2100
+ hookProgramId
2101
+ );
2102
+ return pda;
2103
+ }
2104
+
2105
+ // src/transfer-hook/seeds.ts
2106
+ async function unpackSeeds(params) {
2107
+ const { addressConfig, previousMetas, instructionData, fetchAccountData } = params;
2108
+ const seeds = [];
2109
+ let cursor = 0;
2110
+ if (addressConfig.length < 32) {
2111
+ throw SplTokenError.pdaDerivationFailed({
2112
+ reason: `addressConfig must be at least 32 bytes, got ${addressConfig.length}`
2113
+ });
2114
+ }
2115
+ while (cursor < 32) {
2116
+ const discriminator = addressConfig[cursor];
2117
+ if (discriminator === 0) {
2118
+ break;
2119
+ }
2120
+ cursor++;
2121
+ switch (discriminator) {
2122
+ case 1: {
2123
+ const length = addressConfig[cursor++];
2124
+ seeds.push(addressConfig.slice(cursor, cursor + length));
2125
+ cursor += length;
2126
+ break;
2127
+ }
2128
+ case 2: {
2129
+ const offset = addressConfig[cursor++];
2130
+ const length = addressConfig[cursor++];
2131
+ seeds.push(instructionData.slice(offset, offset + length));
2132
+ break;
2133
+ }
2134
+ case 3: {
2135
+ const index = addressConfig[cursor++];
2136
+ seeds.push(previousMetas[index].pubkey.toBytes());
2137
+ break;
2138
+ }
2139
+ case 4: {
2140
+ const accountIndex = addressConfig[cursor++];
2141
+ const dataOffset = addressConfig[cursor++];
2142
+ const length = addressConfig[cursor++];
2143
+ const data = await fetchAccountData(previousMetas[accountIndex].pubkey);
2144
+ if (data) {
2145
+ seeds.push(data.slice(dataOffset, dataOffset + length));
2146
+ }
2147
+ break;
2148
+ }
2149
+ default: {
2150
+ throw SplTokenError.pdaDerivationFailed({
2151
+ reason: `Unknown seed discriminator ${discriminator} at addressConfig offset ${cursor - 1}`
2152
+ });
2153
+ }
2154
+ }
2155
+ }
2156
+ return seeds;
2157
+ }
2158
+
2159
+ // src/transfer-hook/resolve-extra-accounts.ts
2160
+ async function resolveExtraAccountMeta(params) {
2161
+ const { meta, previousMetas, instructionData, hookProgramId, fetchAccountData } = params;
2162
+ if (meta.discriminator === 0) {
2163
+ return {
2164
+ pubkey: tsCdk.PublicKey.fromBytes(meta.addressConfig),
2165
+ isSigner: meta.isSigner,
2166
+ isWritable: meta.isWritable
2167
+ };
2168
+ }
2169
+ if (meta.discriminator === 1) {
2170
+ const seeds2 = await unpackSeeds({
2171
+ addressConfig: meta.addressConfig,
2172
+ previousMetas,
2173
+ instructionData,
2174
+ fetchAccountData
2175
+ });
2176
+ const [pda2] = tsCdk.PublicKey.findProgramAddress(seeds2, hookProgramId);
2177
+ return {
2178
+ pubkey: pda2,
2179
+ isSigner: meta.isSigner,
2180
+ isWritable: meta.isWritable
2181
+ };
2182
+ }
2183
+ if (meta.discriminator === 2) {
2184
+ const accountIndex2 = meta.addressConfig[0];
2185
+ const dataOffset = meta.addressConfig[1];
2186
+ const data = await fetchAccountData(previousMetas[accountIndex2].pubkey);
2187
+ if (!data) {
2188
+ throw SplTokenError.pdaDerivationFailed({
2189
+ reason: `Failed to fetch account data for discriminator 2 resolution: account at index ${accountIndex2} returned no data`
2190
+ });
2191
+ }
2192
+ if (data.length < dataOffset + 32) {
2193
+ throw SplTokenError.pdaDerivationFailed({
2194
+ reason: `Account data too short for discriminator 2 resolution: expected at least ${dataOffset + 32} bytes at offset ${dataOffset}, but data is only ${data.length} bytes`
2195
+ });
2196
+ }
2197
+ const extracted = data.slice(dataOffset, dataOffset + 32);
2198
+ return {
2199
+ pubkey: tsCdk.PublicKey.fromBytes(extracted),
2200
+ isSigner: meta.isSigner,
2201
+ isWritable: meta.isWritable
2202
+ };
2203
+ }
2204
+ const accountIndex = meta.discriminator - 128;
2205
+ if (accountIndex >= previousMetas.length) {
2206
+ throw SplTokenError.pdaDerivationFailed({
2207
+ reason: `External PDA resolution failed: accountIndex ${accountIndex} (discriminator ${meta.discriminator}) is out of bounds for previousMetas of length ${previousMetas.length}`
2208
+ });
2209
+ }
2210
+ const programId = previousMetas[accountIndex].pubkey;
2211
+ const seeds = await unpackSeeds({
2212
+ addressConfig: meta.addressConfig,
2213
+ previousMetas,
2214
+ instructionData,
2215
+ fetchAccountData
2216
+ });
2217
+ const [pda] = tsCdk.PublicKey.findProgramAddress(seeds, programId);
2218
+ return {
2219
+ pubkey: pda,
2220
+ isSigner: meta.isSigner,
2221
+ isWritable: meta.isWritable
2222
+ };
2223
+ }
2224
+ async function resolveTransferHookExtraAccounts(params) {
2225
+ const { mint, hookProgramId, sourceAta, destinationAta, authority, amount, fetchAccountData } = params;
2226
+ const validationPda = getExtraAccountMetaAddress(mint, hookProgramId);
2227
+ const validationData = await fetchAccountData(validationPda);
2228
+ if (!validationData) {
2229
+ return [
2230
+ { pubkey: hookProgramId, isSigner: false, isWritable: false },
2231
+ { pubkey: validationPda, isSigner: false, isWritable: false }
2232
+ ];
2233
+ }
2234
+ const extraMetas = parseExtraAccountMetaList(validationData);
2235
+ if (extraMetas.length === 0) {
2236
+ return [
2237
+ { pubkey: hookProgramId, isSigner: false, isWritable: false },
2238
+ { pubkey: validationPda, isSigner: false, isWritable: false }
2239
+ ];
2240
+ }
2241
+ const instructionData = buildExecuteInstructionData(amount);
2242
+ const baseMetas = [
2243
+ { pubkey: sourceAta, isSigner: false, isWritable: true },
2244
+ { pubkey: mint, isSigner: false, isWritable: false },
2245
+ { pubkey: destinationAta, isSigner: false, isWritable: true },
2246
+ { pubkey: authority, isSigner: false, isWritable: false },
2247
+ { pubkey: validationPda, isSigner: false, isWritable: false }
2248
+ ];
2249
+ const resolvedExtras = [];
2250
+ for (const meta of extraMetas) {
2251
+ const previousMetas = [...baseMetas, ...resolvedExtras];
2252
+ const resolved = await resolveExtraAccountMeta({
2253
+ meta,
2254
+ previousMetas,
2255
+ instructionData,
2256
+ hookProgramId,
2257
+ fetchAccountData
2258
+ });
2259
+ resolvedExtras.push(resolved);
2260
+ }
2261
+ const deEscalated = resolvedExtras.map((account) => ({
2262
+ ...account,
2263
+ isSigner: false
2264
+ }));
2265
+ return [
2266
+ ...deEscalated,
2267
+ { pubkey: hookProgramId, isSigner: false, isWritable: false },
2268
+ { pubkey: validationPda, isSigner: false, isWritable: false }
2269
+ ];
1045
2270
  }
1046
2271
 
1047
2272
  // src/client/spl-token-client.ts
@@ -1071,11 +2296,20 @@ var SplTokenClient = class {
1071
2296
  this.programId = programId;
1072
2297
  }
1073
2298
  /**
1074
- * Gets the token program ID this client is configured to use.
2299
+ * Returns the Token-2022 program ID used by this client.
1075
2300
  */
1076
2301
  getProgramId() {
1077
2302
  return this.programId;
1078
2303
  }
2304
+ /**
2305
+ * Returns the underlying RialoClient.
2306
+ *
2307
+ * Useful for advanced operations that need direct RPC access,
2308
+ * such as MintBuilder which needs to calculate rent.
2309
+ */
2310
+ getRialoClient() {
2311
+ return this.client;
2312
+ }
1079
2313
  /**
1080
2314
  * Retrieves mint account information.
1081
2315
  *
@@ -1085,10 +2319,8 @@ var SplTokenClient = class {
1085
2319
  *
1086
2320
  * @example
1087
2321
  * ```typescript
1088
- * const mintInfo = await tokenClient.getMintInfo({ mint: mintPubkey });
1089
- * console.log(`Supply: ${mintInfo.supply}`);
1090
- * console.log(`Decimals: ${mintInfo.decimals}`);
1091
- * console.log(`Mint Authority: ${mintInfo.mintAuthority?.toString() ?? 'disabled'}`);
2322
+ * const mintInfo = await tokenClient.getMintInfo({ mint });
2323
+ * console.log(mintInfo.decimals);
1092
2324
  * ```
1093
2325
  */
1094
2326
  async getMintInfo({ mint }) {
@@ -1096,7 +2328,10 @@ var SplTokenClient = class {
1096
2328
  if (!accountInfo) {
1097
2329
  throw SplTokenError.mintNotFound({ address: mint.toString() });
1098
2330
  }
1099
- return parseMintAccount({ address: mint, data: decodeAccountData(accountInfo.data) });
2331
+ return parseMintAccount({
2332
+ address: mint,
2333
+ data: decodeAccountData(accountInfo.data)
2334
+ });
1100
2335
  }
1101
2336
  /**
1102
2337
  * Retrieves Token-2022 native metadata from a mint.
@@ -1107,20 +2342,52 @@ var SplTokenClient = class {
1107
2342
  *
1108
2343
  * @example
1109
2344
  * ```typescript
1110
- * const metadata = await tokenClient.getTokenMetadata({ mint: mintPubkey });
2345
+ * const metadata = await tokenClient.getTokenMetadata({ mint });
1111
2346
  * if (metadata) {
1112
- * console.log(`Name: ${metadata.name}`);
1113
- * console.log(`Symbol: ${metadata.symbol}`);
1114
- * console.log(`URI: ${metadata.uri}`);
2347
+ * console.log(metadata.name, metadata.symbol);
1115
2348
  * }
1116
2349
  * ```
1117
2350
  */
1118
- async getTokenMetadata({ mint }) {
2351
+ async getTokenMetadata({
2352
+ mint
2353
+ }) {
2354
+ const accountInfo = await this.client.getAccountInfo(mint);
2355
+ if (!accountInfo) {
2356
+ throw SplTokenError.mintNotFound({ address: mint.toString() });
2357
+ }
2358
+ return parseTokenMetadata({
2359
+ mint,
2360
+ data: decodeAccountData(accountInfo.data)
2361
+ });
2362
+ }
2363
+ /**
2364
+ * Retrieves complete mint account data in a single RPC call.
2365
+ *
2366
+ * Returns parsed mint info, token metadata, and raw extensions from one
2367
+ * `getAccountInfo` call, avoiding the redundant RPC calls that occur when
2368
+ * calling `getMintInfo()` and `getTokenMetadata()` separately.
2369
+ *
2370
+ * Raw extensions include ALL extension types (including PermanentDelegate,
2371
+ * TransferHook, etc.) unlike `getMintExtensionStates()` which only parses
2372
+ * a subset.
2373
+ *
2374
+ * @param options - Options containing the mint public key
2375
+ * @returns Combined mint info, metadata, and raw extensions
2376
+ * @throws {SplTokenError} If the mint account doesn't exist
2377
+ */
2378
+ async getMintAccountData({
2379
+ mint
2380
+ }) {
1119
2381
  const accountInfo = await this.client.getAccountInfo(mint);
1120
2382
  if (!accountInfo) {
1121
2383
  throw SplTokenError.mintNotFound({ address: mint.toString() });
1122
2384
  }
1123
- return parseTokenMetadata({ mint, data: decodeAccountData(accountInfo.data) });
2385
+ const data = decodeAccountData(accountInfo.data);
2386
+ return {
2387
+ mintInfo: parseMintAccount({ address: mint, data }),
2388
+ metadata: parseTokenMetadata({ mint, data }),
2389
+ rawExtensions: getMintExtensions({ data })
2390
+ };
1124
2391
  }
1125
2392
  /**
1126
2393
  * Retrieves token account information.
@@ -1134,9 +2401,14 @@ var SplTokenClient = class {
1134
2401
  }) {
1135
2402
  const accountInfo = await this.client.getAccountInfo(tokenAccount);
1136
2403
  if (!accountInfo) {
1137
- throw SplTokenError.tokenAccountNotFound({ address: tokenAccount.toString() });
2404
+ throw SplTokenError.tokenAccountNotFound({
2405
+ address: tokenAccount.toString()
2406
+ });
1138
2407
  }
1139
- return parseTokenAccount({ address: tokenAccount, data: decodeAccountData(accountInfo.data) });
2408
+ return parseTokenAccount({
2409
+ address: tokenAccount,
2410
+ data: decodeAccountData(accountInfo.data)
2411
+ });
1140
2412
  }
1141
2413
  /**
1142
2414
  * Gets the token balance for a wallet.
@@ -1153,13 +2425,23 @@ var SplTokenClient = class {
1153
2425
  * console.log(`Token balance: ${balance}`);
1154
2426
  * ```
1155
2427
  */
1156
- async getBalance({ wallet, mint }) {
1157
- const ata = getAssociatedTokenAddressSync({ wallet, mint, programId: this.programId });
2428
+ async getBalance({
2429
+ wallet,
2430
+ mint
2431
+ }) {
2432
+ const ata = getAssociatedTokenAddressSync({
2433
+ wallet,
2434
+ mint,
2435
+ programId: this.programId
2436
+ });
1158
2437
  const accountInfo = await this.client.getAccountInfo(ata);
1159
2438
  if (!accountInfo) {
1160
2439
  return 0n;
1161
2440
  }
1162
- const tokenAccount = parseTokenAccount({ address: ata, data: decodeAccountData(accountInfo.data) });
2441
+ const tokenAccount = parseTokenAccount({
2442
+ address: ata,
2443
+ data: decodeAccountData(accountInfo.data)
2444
+ });
1163
2445
  return tokenAccount.amount;
1164
2446
  }
1165
2447
  /**
@@ -1167,6 +2449,7 @@ var SplTokenClient = class {
1167
2449
  *
1168
2450
  * @param options - Options containing wallet and mint public keys
1169
2451
  * @returns The derived ATA address and bump seed
2452
+ * @throws {SplTokenError} If the ATA derivation fails
1170
2453
  *
1171
2454
  * @example
1172
2455
  * ```typescript
@@ -1178,7 +2461,11 @@ var SplTokenClient = class {
1178
2461
  wallet,
1179
2462
  mint
1180
2463
  }) {
1181
- return findAssociatedTokenAddress({ wallet, mint, programId: this.programId });
2464
+ return findAssociatedTokenAddress({
2465
+ wallet,
2466
+ mint,
2467
+ programId: this.programId
2468
+ });
1182
2469
  }
1183
2470
  /**
1184
2471
  * Checks if an Associated Token Account exists.
@@ -1186,20 +2473,26 @@ var SplTokenClient = class {
1186
2473
  * @param options - Options containing wallet and mint public keys
1187
2474
  * @returns True if the ATA exists, false otherwise
1188
2475
  */
1189
- async ataExists({ wallet, mint }) {
1190
- const ata = getAssociatedTokenAddressSync({ wallet, mint, programId: this.programId });
2476
+ async ataExists({
2477
+ wallet,
2478
+ mint
2479
+ }) {
2480
+ const ata = getAssociatedTokenAddressSync({
2481
+ wallet,
2482
+ mint,
2483
+ programId: this.programId
2484
+ });
1191
2485
  const accountInfo = await this.client.getAccountInfo(ata);
1192
2486
  return accountInfo !== null;
1193
2487
  }
1194
2488
  /**
1195
2489
  * Creates instructions for a token transfer.
1196
2490
  *
1197
- * This builds the necessary instructions for transferring tokens,
2491
+ * Builds the necessary instructions for transferring tokens,
1198
2492
  * optionally creating the destination ATA if it doesn't exist.
1199
2493
  *
1200
2494
  * @param params - Transfer parameters
1201
2495
  * @returns Array of instructions to execute
1202
- * @throws {SplTokenError} If the mint doesn't exist
1203
2496
  *
1204
2497
  * @example
1205
2498
  * ```typescript
@@ -1214,7 +2507,14 @@ var SplTokenClient = class {
1214
2507
  * ```
1215
2508
  */
1216
2509
  async createTransferInstructions(params) {
1217
- const { source, destination, mint, amount, decimals, createDestinationAta = true } = params;
2510
+ const {
2511
+ source,
2512
+ destination,
2513
+ mint,
2514
+ amount,
2515
+ decimals,
2516
+ createDestinationAta = true
2517
+ } = params;
1218
2518
  const instructions = [];
1219
2519
  const sourceAta = getAssociatedTokenAddressSync({
1220
2520
  wallet: source,
@@ -1227,35 +2527,63 @@ var SplTokenClient = class {
1227
2527
  programId: this.programId
1228
2528
  });
1229
2529
  if (createDestinationAta) {
1230
- const destExists = await this.ataExists({ wallet: destination, mint });
1231
- if (!destExists) {
1232
- instructions.push(
1233
- createAssociatedTokenAccountIdempotentInstruction({
1234
- payer: source,
1235
- associatedToken: destinationAta,
1236
- owner: destination,
1237
- mint,
1238
- programId: this.programId
1239
- })
1240
- );
1241
- }
2530
+ instructions.push(
2531
+ createAssociatedTokenAccountIdempotentInstruction({
2532
+ payer: source,
2533
+ associatedToken: destinationAta,
2534
+ owner: destination,
2535
+ mint,
2536
+ programId: this.programId
2537
+ })
2538
+ );
1242
2539
  }
1243
- instructions.push(
1244
- transferCheckedInstruction({
1245
- source: sourceAta,
2540
+ if (params.transferFee) {
2541
+ instructions.push(
2542
+ transferCheckedWithFeeInstruction({
2543
+ source: sourceAta,
2544
+ mint,
2545
+ destination: destinationAta,
2546
+ authority: source,
2547
+ amount,
2548
+ decimals,
2549
+ fee: params.transferFee.fee,
2550
+ programId: this.programId
2551
+ })
2552
+ );
2553
+ } else {
2554
+ instructions.push(
2555
+ transferCheckedInstruction({
2556
+ source: sourceAta,
2557
+ mint,
2558
+ destination: destinationAta,
2559
+ authority: source,
2560
+ amount,
2561
+ decimals,
2562
+ programId: this.programId
2563
+ })
2564
+ );
2565
+ }
2566
+ if (params.transferHook) {
2567
+ const { hookProgramId } = params.transferHook;
2568
+ const transferIx = instructions[instructions.length - 1];
2569
+ const extraAccounts = await resolveTransferHookExtraAccounts({
1246
2570
  mint,
1247
- destination: destinationAta,
2571
+ hookProgramId,
2572
+ sourceAta,
2573
+ destinationAta,
1248
2574
  authority: source,
1249
2575
  amount,
1250
- decimals,
1251
- programId: this.programId
1252
- })
1253
- );
2576
+ fetchAccountData: async (pubkey) => {
2577
+ const info = await this.client.getAccountInfo(pubkey);
2578
+ return info ? decodeAccountData(info.data) : null;
2579
+ }
2580
+ });
2581
+ for (const account of extraAccounts) {
2582
+ transferIx.accounts.push(account);
2583
+ }
2584
+ }
1254
2585
  return instructions;
1255
2586
  }
1256
- /**
1257
- * Options for creating a transfer transaction.
1258
- */
1259
2587
  /**
1260
2588
  * Creates a transaction for a token transfer.
1261
2589
  *
@@ -1288,18 +2616,19 @@ var SplTokenClient = class {
1288
2616
  */
1289
2617
  async createTransferTransaction({
1290
2618
  params,
2619
+ payer,
1291
2620
  validFrom,
1292
2621
  configHashPrefix
1293
2622
  }) {
1294
2623
  const instructions = await this.createTransferInstructions(params);
1295
- const builder = tsCdk.TransactionBuilder.create().setPayer(params.source).setValidFrom(validFrom).setConfigHashPrefix(configHashPrefix);
1296
- for (const ix of instructions) {
1297
- builder.addInstruction(ix);
2624
+ const builder = tsCdk.TransactionBuilder.create().setPayer(payer).setValidFrom(validFrom).setConfigHashPrefix(configHashPrefix);
2625
+ for (const instruction of instructions) {
2626
+ builder.addInstruction(instruction);
1298
2627
  }
1299
2628
  return builder.build();
1300
2629
  }
1301
2630
  /**
1302
- * Transfers tokens from one wallet to another.
2631
+ * Transfers tokens and sends the transaction.
1303
2632
  *
1304
2633
  * This is a high-level convenience method that:
1305
2634
  * 1. Creates the destination ATA if needed
@@ -1307,7 +2636,7 @@ var SplTokenClient = class {
1307
2636
  * 3. Signs and sends the transaction
1308
2637
  * 4. Waits for confirmation
1309
2638
  *
1310
- * @param options - Options containing params, validFrom, and signer
2639
+ * @param options - Transfer params, payer, validFrom, and signers
1311
2640
  * @returns Transaction signature
1312
2641
  *
1313
2642
  * @example
@@ -1331,21 +2660,209 @@ var SplTokenClient = class {
1331
2660
  */
1332
2661
  async transfer({
1333
2662
  params,
2663
+ payer,
1334
2664
  validFrom,
1335
2665
  configHashPrefix,
1336
- signer
2666
+ signers
2667
+ }) {
2668
+ const tx = await this.createTransferTransaction({
2669
+ params,
2670
+ payer,
2671
+ validFrom,
2672
+ configHashPrefix
2673
+ });
2674
+ return this.signAndSend({ tx, signers });
2675
+ }
2676
+ /**
2677
+ * Initializes a mint and sends the transaction.
2678
+ *
2679
+ * @param options - Initialize mint params, payer, validFrom, and signers
2680
+ * @returns Transaction signature
2681
+ */
2682
+ initializeMint({
2683
+ params,
2684
+ payer,
2685
+ validFrom,
2686
+ signers
2687
+ }) {
2688
+ const instruction = initializeMintInstruction({
2689
+ ...params,
2690
+ programId: this.programId
2691
+ });
2692
+ const tx = tsCdk.TransactionBuilder.create().setPayer(payer).setValidFrom(validFrom).addInstruction(instruction).build();
2693
+ return this.signAndSend({ tx, signers });
2694
+ }
2695
+ /**
2696
+ * Mints tokens and sends the transaction.
2697
+ *
2698
+ * @param options - Mint-to params, payer, validFrom, and signers
2699
+ * @returns Transaction signature
2700
+ */
2701
+ mintTo({
2702
+ params,
2703
+ payer,
2704
+ validFrom,
2705
+ signers
2706
+ }) {
2707
+ const instruction = mintToInstruction({
2708
+ ...params,
2709
+ programId: this.programId
2710
+ });
2711
+ const tx = tsCdk.TransactionBuilder.create().setPayer(payer).setValidFrom(validFrom).addInstruction(instruction).build();
2712
+ return this.signAndSend({ tx, signers });
2713
+ }
2714
+ /**
2715
+ * Initializes token metadata on a mint.
2716
+ *
2717
+ * Use this for the on-mint TokenMetadata extension flow.
2718
+ *
2719
+ * @param options - Token metadata params, payer, validFrom, and signers
2720
+ * @returns Transaction signature
2721
+ */
2722
+ initializeTokenMetadata({
2723
+ params,
2724
+ payer,
2725
+ validFrom,
2726
+ signers
2727
+ }) {
2728
+ const instruction = initializeTokenMetadataInstruction({
2729
+ ...params,
2730
+ programId: params.programId ?? this.programId
2731
+ });
2732
+ const tx = tsCdk.TransactionBuilder.create().setPayer(payer).setValidFrom(validFrom).addInstruction(instruction).build();
2733
+ return this.signAndSend({ tx, signers });
2734
+ }
2735
+ /**
2736
+ * Initializes a metadata pointer extension on a mint.
2737
+ *
2738
+ * Use this for the Metadata Pointer flow, where metadata lives in
2739
+ * a separate account and the mint stores a pointer to it.
2740
+ *
2741
+ * @param options - Metadata pointer params, payer, validFrom, and signers
2742
+ * @returns Transaction signature
2743
+ */
2744
+ initializeMetadataPointer({
2745
+ params,
2746
+ payer,
2747
+ validFrom,
2748
+ signers
2749
+ }) {
2750
+ const instruction = initializeMetadataPointerInstruction({
2751
+ ...params,
2752
+ programId: this.programId
2753
+ });
2754
+ const tx = tsCdk.TransactionBuilder.create().setPayer(payer).setValidFrom(validFrom).addInstruction(instruction).build();
2755
+ return this.signAndSend({ tx, signers });
2756
+ }
2757
+ /**
2758
+ * Updates a metadata pointer extension on a mint.
2759
+ *
2760
+ * @param options - Metadata pointer params, payer, validFrom, and signers
2761
+ * @returns Transaction signature
2762
+ */
2763
+ updateMetadataPointer({
2764
+ params,
2765
+ payer,
2766
+ validFrom,
2767
+ signers
2768
+ }) {
2769
+ const instruction = updateMetadataPointerInstruction({
2770
+ ...params,
2771
+ programId: this.programId
2772
+ });
2773
+ const tx = tsCdk.TransactionBuilder.create().setPayer(payer).setValidFrom(validFrom).addInstruction(instruction).build();
2774
+ return this.signAndSend({ tx, signers });
2775
+ }
2776
+ /**
2777
+ * Initializes a transfer fee config on a mint.
2778
+ *
2779
+ * @param options - Transfer fee config params, payer, validFrom, and signers
2780
+ * @returns Transaction signature
2781
+ */
2782
+ initializeTransferFeeConfig({
2783
+ params,
2784
+ payer,
2785
+ validFrom,
2786
+ signers
2787
+ }) {
2788
+ const instruction = initializeTransferFeeConfigInstruction({
2789
+ ...params,
2790
+ programId: this.programId
2791
+ });
2792
+ const tx = tsCdk.TransactionBuilder.create().setPayer(payer).setValidFrom(validFrom).addInstruction(instruction).build();
2793
+ return this.signAndSend({ tx, signers });
2794
+ }
2795
+ /**
2796
+ * Transfers tokens with a fee and sends the transaction.
2797
+ *
2798
+ * @param options - Transfer params, payer, validFrom, and signers
2799
+ * @returns Transaction signature
2800
+ */
2801
+ transferCheckedWithFee({
2802
+ params,
2803
+ payer,
2804
+ validFrom,
2805
+ signers
2806
+ }) {
2807
+ const instruction = transferCheckedWithFeeInstruction({
2808
+ ...params,
2809
+ programId: this.programId
2810
+ });
2811
+ const tx = tsCdk.TransactionBuilder.create().setPayer(payer).setValidFrom(validFrom).addInstruction(instruction).build();
2812
+ return this.signAndSend({ tx, signers });
2813
+ }
2814
+ /**
2815
+ * Initializes a non-transferable mint.
2816
+ *
2817
+ * @param options - Non-transferable mint params, payer, validFrom, and signers
2818
+ * @returns Transaction signature
2819
+ */
2820
+ initializeNonTransferableMint({
2821
+ params,
2822
+ payer,
2823
+ validFrom,
2824
+ signers
2825
+ }) {
2826
+ const instruction = initializeNonTransferableMintInstruction({
2827
+ ...params,
2828
+ programId: this.programId
2829
+ });
2830
+ const tx = tsCdk.TransactionBuilder.create().setPayer(payer).setValidFrom(validFrom).addInstruction(instruction).build();
2831
+ return this.signAndSend({ tx, signers });
2832
+ }
2833
+ async signAndSend({
2834
+ tx,
2835
+ signers
1337
2836
  }) {
1338
- const tx = await this.createTransferTransaction({ params, validFrom, configHashPrefix });
1339
- const signedTx = await tx.signWith(signer);
1340
- const result = await this.client.sendAndConfirmTransaction(signedTx.serialize());
2837
+ if (signers.length === 0) {
2838
+ throw new Error("At least one signer required.");
2839
+ }
2840
+ const signedTx = await tx.signAllWith(signers);
2841
+ const result = await this.client.sendAndConfirmTransaction(
2842
+ signedTx.serialize()
2843
+ );
1341
2844
  return result.signature;
1342
2845
  }
1343
2846
  };
1344
- function createSplTokenClient({
1345
- client,
1346
- programId
1347
- }) {
1348
- return new SplTokenClient({ client, programId });
2847
+ function createSplTokenClient(options) {
2848
+ return new SplTokenClient(options);
2849
+ }
2850
+
2851
+ // src/recipes/create-token-with-metadata.ts
2852
+ async function createTokenWithMetadata(tokenClient, params, options) {
2853
+ const builder = MintBuilder.create(tokenClient).withDecimals(params.decimals).withMintAuthority(params.mintAuthority).withMetadata(params.metadata);
2854
+ if (params.freezeAuthority) {
2855
+ builder.withFreezeAuthority(params.freezeAuthority);
2856
+ }
2857
+ if (params.initialMint) {
2858
+ builder.withInitialSupply(params.initialMint);
2859
+ }
2860
+ return await builder.send({
2861
+ payer: options.payer,
2862
+ mintKeypair: options.mintKeypair,
2863
+ validFrom: options.validFrom,
2864
+ signers: options.signers
2865
+ });
1349
2866
  }
1350
2867
  /*! Bundled license information:
1351
2868
 
@@ -1355,29 +2872,65 @@ function createSplTokenClient({
1355
2872
 
1356
2873
  exports.ASSOCIATED_TOKEN_PROGRAM_ID = ASSOCIATED_TOKEN_PROGRAM_ID;
1357
2874
  exports.AccountType = AccountType;
2875
+ exports.EXECUTE_DISCRIMINATOR = EXECUTE_DISCRIMINATOR;
2876
+ exports.EXTRA_ACCOUNT_META_SIZE = EXTRA_ACCOUNT_META_SIZE;
1358
2877
  exports.ExtensionType = ExtensionType;
1359
2878
  exports.MINT_SIZE = MINT_SIZE;
2879
+ exports.MintBuilder = MintBuilder;
1360
2880
  exports.SplTokenClient = SplTokenClient;
1361
2881
  exports.SplTokenError = SplTokenError;
1362
2882
  exports.SplTokenErrorCode = SplTokenErrorCode;
2883
+ exports.TLV_LENGTH_SIZE = TLV_LENGTH_SIZE;
2884
+ exports.TLV_TYPE_SIZE = TLV_TYPE_SIZE;
1363
2885
  exports.TOKEN_2022_PROGRAM_ID = TOKEN_2022_PROGRAM_ID;
1364
2886
  exports.TOKEN_ACCOUNT_SIZE = TOKEN_ACCOUNT_SIZE;
1365
2887
  exports.TOKEN_PROGRAM_ID = TOKEN_PROGRAM_ID;
1366
2888
  exports.TokenAccountState = TokenAccountState;
1367
2889
  exports.TokenInstruction = TokenInstruction;
2890
+ exports.buildExecuteInstructionData = buildExecuteInstructionData;
1368
2891
  exports.createAssociatedTokenAccountIdempotentInstruction = createAssociatedTokenAccountIdempotentInstruction;
1369
2892
  exports.createAssociatedTokenAccountInstruction = createAssociatedTokenAccountInstruction;
1370
2893
  exports.createSplTokenClient = createSplTokenClient;
2894
+ exports.createTokenWithMetadata = createTokenWithMetadata;
1371
2895
  exports.findAssociatedTokenAddress = findAssociatedTokenAddress;
1372
2896
  exports.getAssociatedTokenAddressSync = getAssociatedTokenAddressSync;
2897
+ exports.getExtraAccountMetaAddress = getExtraAccountMetaAddress;
2898
+ exports.getMetadataExtensionSize = getMetadataExtensionSize;
2899
+ exports.getMinRentForMint = getMinRentForMint;
2900
+ exports.getMinRentForMintWithMetadata = getMinRentForMintWithMetadata;
2901
+ exports.getMintExtensionStates = getMintExtensionStates;
1373
2902
  exports.getMintExtensions = getMintExtensions;
2903
+ exports.getMintSizeWithExtensions = getMintSizeWithExtensions;
2904
+ exports.getMintSizeWithMetadata = getMintSizeWithMetadata;
2905
+ exports.getTokenAccountExtensionStates = getTokenAccountExtensionStates;
2906
+ exports.getTokenAccountExtensions = getTokenAccountExtensions;
2907
+ exports.getTokenMetadataDataSize = getTokenMetadataDataSize;
2908
+ exports.initializeMetadataPointerInstruction = initializeMetadataPointerInstruction;
1374
2909
  exports.initializeMintInstruction = initializeMintInstruction;
2910
+ exports.initializeNonTransferableMintInstruction = initializeNonTransferableMintInstruction;
2911
+ exports.initializePermanentDelegateInstruction = initializePermanentDelegateInstruction;
2912
+ exports.initializeTokenMetadataInstruction = initializeTokenMetadataInstruction;
2913
+ exports.initializeTransferFeeConfigInstruction = initializeTransferFeeConfigInstruction;
2914
+ exports.initializeTransferHookInstruction = initializeTransferHookInstruction;
1375
2915
  exports.mintToInstruction = mintToInstruction;
2916
+ exports.parseExtension = parseExtension;
2917
+ exports.parseExtraAccountMetaList = parseExtraAccountMetaList;
1376
2918
  exports.parseMetadataPointerExtension = parseMetadataPointerExtension;
2919
+ exports.parseMetadataPointerExtensionData = parseMetadataPointerExtensionData;
1377
2920
  exports.parseMintAccount = parseMintAccount;
2921
+ exports.parsePermanentDelegateExtension = parsePermanentDelegateExtension;
1378
2922
  exports.parseTokenAccount = parseTokenAccount;
1379
2923
  exports.parseTokenMetadata = parseTokenMetadata;
2924
+ exports.parseTokenMetadataExtensionData = parseTokenMetadataExtensionData;
2925
+ exports.parseTransferFeeConfigExtension = parseTransferFeeConfigExtension;
2926
+ exports.parseTransferHookExtension = parseTransferHookExtension;
2927
+ exports.resolveExtraAccountMeta = resolveExtraAccountMeta;
2928
+ exports.resolveTransferHookExtraAccounts = resolveTransferHookExtraAccounts;
2929
+ exports.setTransferFeeInstruction = setTransferFeeInstruction;
1380
2930
  exports.transferCheckedInstruction = transferCheckedInstruction;
2931
+ exports.transferCheckedWithFeeInstruction = transferCheckedWithFeeInstruction;
1381
2932
  exports.transferInstruction = transferInstruction;
2933
+ exports.unpackSeeds = unpackSeeds;
2934
+ exports.updateMetadataPointerInstruction = updateMetadataPointerInstruction;
1382
2935
  //# sourceMappingURL=index.js.map
1383
2936
  //# sourceMappingURL=index.js.map