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

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