@typesol/cli 0.16.0 → 0.18.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.
@@ -1,12 +1,14 @@
1
1
  import ts from "typescript";
2
- import { resolveScalarType } from "../analyze.js";
2
+ import { calleeName, resolveScalarType } from "../analyze.js";
3
3
  import { decodeAddress } from "../../keys.js";
4
4
  import { INT_INFO, INT_NAMES, isScalar, isWritable, sameType, scalarSize, typeName, } from "../model.js";
5
- import { U64, U8, I64, BOOL, PUBKEY, STRING, HASH, cBytes, cString, scalarC, scalarStorageC, optC, valueC, fieldC, storageDecl, accountMismatch, } from "./shared.js";
5
+ import { U64, U8, I64, BOOL, PUBKEY, STRING, HASH, cBytes, cString, scalarC, scalarStorageC, optC, valueC, fieldC, storageDecl, accountMismatch, vecCount, } from "./shared.js";
6
6
  import { ExpressionEmitter } from "./expressions.js";
7
7
  /**
8
8
  * Calls: built-in functions, Vec methods, helpers, remaining accounts, foreign account reads and return data.
9
9
  */
10
+ /** List methods taking a callback (or a value) that expand into a loop. */
11
+ const LIST_METHODS = new Set(["forEach", "some", "every", "find", "findIndex", "reduce", "includes", "indexOf"]);
10
12
  export class CallEmitter extends ExpressionEmitter {
11
13
  call(node, topLevel) {
12
14
  const callee = node.expression;
@@ -126,14 +128,26 @@ export class CallEmitter extends ExpressionEmitter {
126
128
  }
127
129
  case "mulDiv":
128
130
  case "mulDivCeil": {
129
- // a * b / c with a 128-bit intermediate (u64), rounding down or up; aborts if the result does not fit.
131
+ // a * b / c with a double-width intermediate (128-bit for u64, 256-bit for u128), rounding down or up;
132
+ // aborts if the result does not fit. All three are u64, or all u128 (literals take the others' type).
130
133
  if (args.length !== 3)
131
- this.fail(node, `${builtin}(a, b, c) takes three u64 values`);
132
- const [x, y, z] = this.lowerInOrder(args, [U64, U64, U64]);
134
+ this.fail(node, `${builtin}(a, b, c) takes three u64 or three u128 values`);
135
+ const vals = [];
136
+ for (const a of args) {
137
+ const mark = this.lines.length;
138
+ const v = this.expr(a);
139
+ for (let j = 0; j < vals.length; j++)
140
+ vals[j] = this.settle(vals[j], mark);
141
+ vals.push(v);
142
+ }
143
+ const typed = vals.find((v) => v.literal === undefined);
144
+ const wide = typed?.type.kind === "int" && typed.type.name === "u128";
145
+ const ty = wide ? { kind: "int", name: "u128" } : U64;
146
+ const [x, y, z] = vals.map((v, i) => this.expect(v.literal !== undefined ? this.literal(v.literal, ty, args[i]) : v, ty, args[i]));
133
147
  const t = this.tmp("md");
134
- this.line(`uint64_t ${t};`);
135
- this.line(`TS_TRY(ts_mul_div(${x.c}, ${y.c}, ${z.c}, ${builtin === "mulDivCeil"}, &${t}));`);
136
- return { c: t, type: U64 };
148
+ this.line(`${wide ? "unsigned __int128" : "uint64_t"} ${t};`);
149
+ this.line(`TS_TRY(ts_mul_div${wide ? "_u128" : ""}(${x.c}, ${y.c}, ${z.c}, ${builtin === "mulDivCeil"}, &${t}));`);
150
+ return { c: t, type: ty };
137
151
  }
138
152
  case "isqrt": {
139
153
  if (args.length !== 1)
@@ -219,7 +233,18 @@ export class CallEmitter extends ExpressionEmitter {
219
233
  this.line(`TS_TRY(ts_t22_transfer_fee(${m}, ${amt.c}, &${t}));`);
220
234
  return { c: t, type: U64 };
221
235
  }
236
+ case "isTransferring": {
237
+ // TransferHookAccount (15) on a Token-2022 token account: set only while Token-2022 runs a transfer of it.
238
+ if (args.length !== 1)
239
+ this.fail(node, "isTransferring(tokenAccount) takes the source token account");
240
+ const m = this.anyAccount(args[0], "the token account");
241
+ this.line(`TS_TRY(ts_t22_layout(${m}, 2));`);
242
+ const off = this.tmp("eo");
243
+ this.line(`uint64_t ${off}, ${off}l;`);
244
+ return { c: `(ts_t22_ext(${m}, 15, &${off}, &${off}l) && ${off}l >= 1 && ${m}->data[${off}] != 0)`, type: BOOL };
245
+ }
222
246
  case "transferHookProgram":
247
+ case "transferHookAuthority":
223
248
  case "permanentDelegate":
224
249
  case "mintCloseAuthority": {
225
250
  // Token-2022 mint extensions holding an optional Pubkey: TransferHook (14, program at +32),
@@ -228,7 +253,7 @@ export class CallEmitter extends ExpressionEmitter {
228
253
  this.fail(node, `${builtin}(mint) takes the mint`);
229
254
  const m = this.anyAccount(args[0], "the mint");
230
255
  this.line(`TS_TRY(ts_t22_layout(${m}, 1));`);
231
- const [type, field] = builtin === "transferHookProgram" ? [14, 32] : builtin === "permanentDelegate" ? [12, 0] : [3, 0];
256
+ const [type, field] = builtin === "transferHookProgram" ? [14, 32] : builtin === "transferHookAuthority" ? [14, 0] : builtin === "permanentDelegate" ? [12, 0] : [3, 0];
232
257
  this.model.options.set("pubkey", PUBKEY);
233
258
  const t = this.tmp("ext");
234
259
  this.line(`${optC(PUBKEY)} ${t};`);
@@ -364,13 +389,14 @@ export class CallEmitter extends ExpressionEmitter {
364
389
  this.line(`if (ts_find_pda(${seeds.name}, ${seeds.count}, ${program.c}, &${t}, &${b}) != SUCCESS) TS_FAIL(TS_ERR_SEEDS, "TypeSOL: no program address for these seeds");`);
365
390
  return { c: `(&${t})`, type: PUBKEY };
366
391
  }
367
- case "metadataAddress": {
392
+ case "metadataAddress":
393
+ case "masterEditionAddress": {
368
394
  if (args.length !== 1)
369
- this.fail(node, "metadataAddress(mint) takes the mint");
395
+ this.fail(node, `${builtin}(mint) takes the mint`);
370
396
  const m = this.expect(this.expr(args[0], PUBKEY), PUBKEY, args[0]);
371
397
  const t = this.tmp("md");
372
398
  this.line(`SolPubkey ${t};`);
373
- this.line(`TS_TRY(ts_metadata_address(${m.c}, &${t}));`);
399
+ this.line(`TS_TRY(${builtin === "metadataAddress" ? "ts_metadata_address" : "ts_master_edition_address"}(${m.c}, &${t}));`);
374
400
  return { c: `(&${t})`, type: PUBKEY };
375
401
  }
376
402
  case "initExtraAccountMetas":
@@ -433,10 +459,22 @@ export class CallEmitter extends ExpressionEmitter {
433
459
  }
434
460
  if (builtin)
435
461
  this.fail(callee, `${builtin} cannot be called here`);
436
- if (ts.isIdentifier(callee) && this.model.helpers.has(callee.text))
437
- return this.callHelper(node, this.model.helpers.get(callee.text));
462
+ if (ts.isIdentifier(callee)) {
463
+ const local = this.lookup(callee.text);
464
+ if (local?.closure)
465
+ return this.expandClosure(local.closure, node.arguments, node);
466
+ }
467
+ const helper = this.helperOf(node);
468
+ if (helper)
469
+ return this.callHelper(node, helper);
438
470
  if (ts.isPropertyAccessExpression(callee)) {
439
471
  const method = callee.name.text;
472
+ // xs.some(…) and friends on a Vec, FixedArray, FixedVec or Vec argument: a loop with the callback expanded in it.
473
+ if (LIST_METHODS.has(method)) {
474
+ const l = ts.isIdentifier(callee.expression) ? this.lookup(callee.expression.text) : undefined;
475
+ if (l?.type.kind === "vecArg" || l?.type.kind === "array" || this.peekArray(callee.expression))
476
+ return this.listMethod(node, method);
477
+ }
440
478
  // Vec<T> instruction arguments are read-only views.
441
479
  if (ts.isIdentifier(callee.expression)) {
442
480
  const l = this.lookup(callee.expression.text);
@@ -444,6 +482,10 @@ export class CallEmitter extends ExpressionEmitter {
444
482
  if (method !== "get" || args.length !== 1)
445
483
  this.fail(node, "Vec arguments are read-only: use .get(i) and .length");
446
484
  const elem = l.type.elem;
485
+ if (elem.kind === "string") {
486
+ const idx = this.index(args[0], `(uint64_t)${l.c}.len`);
487
+ return { c: `(((const TS_Str *)${l.c}.ptr)[${idx}])`, type: STRING };
488
+ }
447
489
  if (!isScalar(elem))
448
490
  this.fail(node, `read a field of the element: ${callee.expression.text}.get(i).field`);
449
491
  const idx = this.index(args[0], `(uint64_t)${l.c}.len`);
@@ -504,8 +546,10 @@ export class CallEmitter extends ExpressionEmitter {
504
546
  // Program accounts used through their methods (systemProgram.transfer, tokenProgram.*…) may be optional.
505
547
  if (target?.optional)
506
548
  this.assertUsable(target, callee.expression);
507
- if (target?.kind.kind === "token" && target.kind.init && method === (target.kind.init === "create" ? "create" : "createIfNeeded"))
508
- return this.createAta(node, target, topLevel);
549
+ if ((target?.kind.kind === "token" || target?.kind.kind === "mint") &&
550
+ target.kind.init &&
551
+ method === (target.kind.init === "create" ? "create" : "createIfNeeded"))
552
+ return target.kind.kind === "token" && target.constraints.ata ? this.createAta(node, target, topLevel) : this.createToken(node, target, topLevel);
509
553
  if (target?.kind.kind === "init" && method === "create")
510
554
  return this.create(node, target, topLevel);
511
555
  if (target?.kind.kind === "initIfNeeded" && method === "createIfNeeded")
@@ -520,10 +564,14 @@ export class CallEmitter extends ExpressionEmitter {
520
564
  return this.ataOp(node, target, method);
521
565
  if (target?.kind.kind === "metadataProgram")
522
566
  return this.metadataOp(node, target, method);
523
- if (target?.kind.kind === "coreProgram")
524
- return this.coreOp(node, target, method);
525
- if (target?.kind.kind === "bubblegumProgram")
526
- return this.bubblegumOp(node, target, method);
567
+ // Each Metaplex CPI in its own C block: its data buffer's stack slot is reused by the next one.
568
+ if (target?.kind.kind === "coreProgram" || target?.kind.kind === "bubblegumProgram") {
569
+ const t = target;
570
+ this.line("{");
571
+ this.block(() => (t.kind.kind === "coreProgram" ? this.coreOp(node, t, method) : this.bubblegumOp(node, t, method)));
572
+ this.line("}");
573
+ return undefined;
574
+ }
527
575
  }
528
576
  }
529
577
  if (ts.isPropertyAccessExpression(callee) && ts.isCallExpression(callee.expression) && this.exportName(callee.expression.expression) === "fixedArray")
@@ -536,7 +584,8 @@ export class CallEmitter extends ExpressionEmitter {
536
584
  const args = node.arguments;
537
585
  const vt = v.type;
538
586
  const info = v.vec;
539
- const elemRef = (idx) => ({ ...v, lv: `${v.lv}[${idx}]`, type: vt.elem, vec: undefined, path: undefined });
587
+ const elemRef = (idx) => this.withFixedVec({ ...v, lv: `${info.items}[${idx}]`, type: vt.elem, vec: undefined, path: undefined });
588
+ const count = vecCount(info);
540
589
  /**
541
590
  * Evaluate the value into a temporary first (JS evaluates arguments before the call runs), then return a
542
591
  * writer for the element: `push(v.length)` sees the old length, `set(i, pop())` checks i after the pop.
@@ -564,8 +613,10 @@ export class CallEmitter extends ExpressionEmitter {
564
613
  // Elements removed or replaced here must not be referenced afterwards.
565
614
  const elemPaths = () => (ts.isPropertyAccessExpression(node.expression) ? this.pathsOf(node.expression.expression)?.map((p) => `${p}[]`) : undefined);
566
615
  const resize = (newLen, payer) => {
616
+ if (info.cap !== undefined)
617
+ return; // a FixedVec has its room already
567
618
  if (!info.resizable || !v.account)
568
- this.fail(node, "only Vecs of declared Mut<...> / Init<...> accounts can grow or shrink");
619
+ this.fail(node, "only Vecs of Mut<...> / Init<...> accounts can grow or shrink");
569
620
  this.line(`TS_TRY(ts_resize(params, ${payer}, a_${v.account.name}, 8 + ${info.fixed} + (${newLen}) * ${info.elemSize}, entry_${v.account.name}));`);
570
621
  };
571
622
  switch (method) {
@@ -577,11 +628,23 @@ export class CallEmitter extends ExpressionEmitter {
577
628
  this.assertNotAliased(elemPaths(), node);
578
629
  const i = this.indexValue(args[0]);
579
630
  const write = stageElem(args[1]);
580
- this.checkIndex(i, `(uint64_t)${info.len}`);
631
+ this.checkIndex(i, count);
581
632
  write(elemRef(i));
582
633
  return undefined;
583
634
  }
584
635
  case "push": {
636
+ if (info.cap !== undefined) {
637
+ if (args.length !== 1)
638
+ this.fail(node, "push(value) on a FixedVec takes the value (it has room for its capacity already)");
639
+ needWritable();
640
+ const write = stageElem(args[0]);
641
+ const n = this.tmp("n");
642
+ this.line(`uint64_t ${n} = ${count};`);
643
+ this.line(`if (${n} >= ${info.cap}) TS_FAIL(TS_ERR_INDEX, "TypeSOL: push() on a full FixedVec");`);
644
+ this.line(`${info.len} = (uint32_t)(${n} + 1);`);
645
+ write(elemRef(n));
646
+ return undefined;
647
+ }
585
648
  if (args.length !== 2)
586
649
  this.fail(node, "push(value, payer) takes the value and a Mut<Signer> that pays for the extra rent");
587
650
  needWritable();
@@ -604,7 +667,7 @@ export class CallEmitter extends ExpressionEmitter {
604
667
  this.assertNotAliased(elemPaths(), node);
605
668
  const st = this.storageValueType(vt.elem);
606
669
  const n = this.tmp("n");
607
- this.line(`uint64_t ${n} = (uint64_t)${info.len};`);
670
+ this.line(`uint64_t ${n} = ${count};`);
608
671
  this.line(`if (${n} == 0) TS_FAIL(TS_ERR_INDEX, "TypeSOL: pop() on an empty Vec");`);
609
672
  // Structs and arrays are dropped (pop() as a statement); read .get(length - 1) first to keep one.
610
673
  let result;
@@ -836,6 +899,8 @@ export class CallEmitter extends ExpressionEmitter {
836
899
  const s = targ && ts.isTypeReferenceNode(targ) && ts.isIdentifier(targ.typeName) ? this.model.structs.get(targ.typeName.text) : undefined;
837
900
  if (!s || s.size === undefined || s.vec)
838
901
  this.fail(node, "loadForeign needs a fixed-size struct type: loadForeign<Pool>(account, owner)");
902
+ if (s.layout === "borsh")
903
+ this.fail(node, `${s.name} is @layout borsh: loadForeign reads fixed layouts only`);
839
904
  if (node.arguments.length !== 2)
840
905
  this.fail(node, "loadForeign<T>(account, owner) takes the account and its owning program's address");
841
906
  const h = this.anyAccount(node.arguments[0], "loadForeign's account");
@@ -857,6 +922,8 @@ export class CallEmitter extends ExpressionEmitter {
857
922
  const s = targ && ts.isTypeReferenceNode(targ) && ts.isIdentifier(targ.typeName) ? this.model.structs.get(targ.typeName.text) : undefined;
858
923
  if (!s || s.size === undefined)
859
924
  this.fail(node, "loadAccount needs an account struct type: loadAccount<MyStruct>(account)");
925
+ if (s.layout === "borsh")
926
+ this.fail(node, `${s.name} is @layout borsh: declare it as an instruction parameter (remaining accounts are read in place)`);
860
927
  if (node.arguments.length !== 1)
861
928
  this.fail(node, "loadAccount<T>(account) takes one remaining account");
862
929
  const h = this.handle(node.arguments[0]);
@@ -874,16 +941,45 @@ export class CallEmitter extends ExpressionEmitter {
874
941
  }
875
942
  return { c: `((TSS_${s.name} *)(${h}->data + 8))`, type: { kind: "structRef", struct: s.name, writable: mut } };
876
943
  }
944
+ /** Whether a helper (or one it calls) grows a Vec, which needs the instruction's SystemProgram for rent. */
945
+ helperGrows(body, seen = new Set()) {
946
+ if (seen.has(body))
947
+ return false;
948
+ seen.add(body);
949
+ let found = false;
950
+ const visit = (n) => {
951
+ if (found)
952
+ return;
953
+ if (ts.isCallExpression(n)) {
954
+ // Vec.push(value, payer) grows the account; FixedVec.push(value) does not.
955
+ if (ts.isPropertyAccessExpression(n.expression) && n.expression.name.text === "push" && n.arguments.length === 2)
956
+ found = true;
957
+ else if (ts.isIdentifier(n.expression)) {
958
+ const name = calleeName(n.expression, this.model.helperDecls, this.checker);
959
+ const callee = name ? (this.model.generics.get(name)?.node ?? this.model.helpers.get(name)?.node) : undefined;
960
+ if (callee && this.helperGrows(callee, seen))
961
+ found = true;
962
+ }
963
+ }
964
+ ts.forEachChild(n, visit);
965
+ };
966
+ visit(body);
967
+ return found;
968
+ }
877
969
  callHelper(node, h) {
878
- if (node.arguments.length !== h.params.length)
879
- this.fail(node, `${h.name}() takes ${h.params.length} argument(s)`);
970
+ if (this.ix && !this.ix.accounts.some((a) => a.kind.kind === "system" && !a.optional) && h.params.some((p) => p.account) && this.helperGrows(h.node))
971
+ this.fail(node, `${h.display}() grows a Vec (push): the instruction needs a SystemProgram parameter to top up rent`);
972
+ // Function arguments were bound when the helper was instantiated: they have no C parameter.
973
+ const argNodes = h.fnArgIndexes ? node.arguments.filter((_, i) => !h.fnArgIndexes.includes(i)) : node.arguments;
974
+ if (argNodes.length !== h.params.length)
975
+ this.fail(node, `${h.display}() takes ${h.params.length} argument(s)`);
880
976
  // Arguments are evaluated left to right: settle earlier ones when a later one runs statements.
881
977
  // A helper that takes accounts may change account data, so account text it gets is copied first.
882
978
  const takesAccounts = h.params.some((p) => p.account);
883
979
  const values = [];
884
980
  const pieces = [];
885
981
  h.params.forEach((p, i) => {
886
- const n = node.arguments[i];
982
+ const n = argNodes[i];
887
983
  const mark = this.lines.length;
888
984
  const raw = this.helperArg(h, p, n);
889
985
  for (let j = 0; j < values.length; j++)
@@ -897,8 +993,8 @@ export class CallEmitter extends ExpressionEmitter {
897
993
  });
898
994
  // A helper that takes a writable struct account may replace anything stored in it (see assertNotAliased).
899
995
  for (const [i, p] of h.params.entries())
900
- if (p.account && p.account.kind === "account" && p.account.mut && ts.isIdentifier(node.arguments[i]))
901
- this.assertNotAliased([node.arguments[i].text], node, h.name);
996
+ if (p.account && p.account.kind === "account" && p.account.mut && ts.isIdentifier(argNodes[i]))
997
+ this.assertNotAliased([argNodes[i].text], node, h.display);
902
998
  const args = ["params", ...pieces.map((x) => (typeof x === "number" ? (values[x].type.kind === "pubkey" ? `*(${values[x].c})` : values[x].c) : x))];
903
999
  if (!h.returns) {
904
1000
  this.line(`TS_TRY(fn_${h.name}(${args.join(", ")}));`);
@@ -912,6 +1008,11 @@ export class CallEmitter extends ExpressionEmitter {
912
1008
  this.line(`TS_TRY(fn_${h.name}(${[...args, `&${t}`].join(", ")}));`);
913
1009
  return { c: `(&${t})`, type: { kind: "structRef", struct: h.returns.name, writable: true } };
914
1010
  }
1011
+ if (h.returns.kind === "string") {
1012
+ this.line(`TS_Str ${t};`);
1013
+ this.line(`TS_TRY(fn_${h.name}(${[...args, `&${t}`].join(", ")}));`);
1014
+ return { c: t, type: STRING };
1015
+ }
915
1016
  this.line(`${scalarC(h.returns)} ${t};`);
916
1017
  this.line(`TS_TRY(fn_${h.name}(${[...args, `&${t}`].join(", ")}));`);
917
1018
  return h.returns.kind === "pubkey" ? { c: `(&${t})`, type: h.returns } : { c: t, type: h.returns };
@@ -923,6 +1024,11 @@ export class CallEmitter extends ExpressionEmitter {
923
1024
  const why = accountMismatch(acct.kind, p.account);
924
1025
  if (why)
925
1026
  this.fail(n, `${h.name}() takes ${p.name} as ${why}`);
1027
+ // A @layout borsh account goes with the struct it is being worked on as.
1028
+ if (p.account.kind === "account" && p.account.struct.layout === "borsh")
1029
+ return `a_${acct.name}, d_${acct.name}`;
1030
+ if (p.account.kind === "account" && p.account.mut && p.account.struct.vec)
1031
+ return `a_${acct.name}, entry_${acct.name}`;
926
1032
  return `a_${acct.name}`;
927
1033
  }
928
1034
  switch (p.type.kind) {
@@ -2,6 +2,13 @@ import ts from "typescript";
2
2
  import { type AccountParam, type IdlSeed, type ValueType } from "../model.js";
3
3
  import { type Value } from "./shared.js";
4
4
  import { CallEmitter } from "./calls.js";
5
+ /** One piece of a Metaplex instruction's Borsh data: fixed bytes, or a value lowered and serialized in source order. */
6
+ type MplField = {
7
+ bytes: number[];
8
+ } | {
9
+ value: ts.Expression;
10
+ type: ValueType;
11
+ };
5
12
  /**
6
13
  * Other programs: PDAs and seeds, account creation, System/Token/ATA/Metaplex CPIs, generic invoke, Borsh
7
14
  * serialization and events.
@@ -19,6 +26,25 @@ export declare abstract class CpiEmitter extends CallEmitter {
19
26
  protected describeSeed(el: ts.Expression): IdlSeed | undefined;
20
27
  protected recordPda(account: AccountParam, idl: IdlSeed[] | undefined): void;
21
28
  protected create(node: ts.CallExpression, target: AccountParam, topLevel: boolean, ifNeeded?: boolean): Value;
29
+ /**
30
+ * `vault.create(payer, seeds | null, mint, authority)` on `Init<TokenAccount>` and `mint.create(payer, seeds | null,
31
+ * decimals, authority, freezeAuthority | null)` on `Init<Mint>` (Anchor's `init` with `token::` / `mint::`
32
+ * constraints): a PDA of this program (or, with `null`, a new keypair account that signs), created owned by the
33
+ * instruction's token program and initialized. `createIfNeeded` on `InitIfNeeded<…>` does that unless the account
34
+ * exists, and then checks it is that PDA, owned by the token program, and has that mint and owner / those
35
+ * authorities and decimals (Anchor's init_if_needed checks). create returns the bump (0 for a keypair),
36
+ * createIfNeeded whether it created the account.
37
+ */
38
+ protected createToken(node: ts.CallExpression, target: AccountParam, topLevel: boolean): Value;
39
+ /**
40
+ * The extensions in `mint.create(…, { … })` (Anchor's `extensions::…` constraints): their values are evaluated now,
41
+ * in source order; the returned lines (each extension's Token-2022 initializer, mint writable, before
42
+ * InitializeMint2) run after the account is created, sized for exactly these extensions.
43
+ */
44
+ protected mintExtensions(lit: ts.ObjectLiteralExpression, tp: string, acct: string): {
45
+ space: number;
46
+ lines: string[];
47
+ };
22
48
  /**
23
49
  * `ata.create(payer)` / `ata.createIfNeeded(payer)` on `Ata<Init|InitIfNeeded<TokenAccount>, "owner", "mint">`
24
50
  * (Anchor's `init` / `init_if_needed` with `associated_token::…`). create always calls the ATA program's Create, which
@@ -30,10 +56,17 @@ export declare abstract class CpiEmitter extends CallEmitter {
30
56
  protected systemTransfer(node: ts.CallExpression): undefined;
31
57
  /** systemProgram.createAccount(payer, account, lamports, space, owner, signerSeeds?) */
32
58
  protected createAccount(node: ts.CallExpression, system: AccountParam): undefined;
33
- /** Emit a CPI to the program account `program` with these metas (account, writable, signer). */
59
+ /**
60
+ * Emit a CPI to the program account `program` with these metas (account, writable, signer), and then (`tail`) a range
61
+ * of the remaining accounts, read-only (a Merkle proof).
62
+ */
34
63
  protected cpi(program: string, metas: [string, boolean, boolean][], buf: string, len: string, seeds: {
35
64
  name: string;
36
65
  count: number | string;
66
+ }, tail?: {
67
+ from: string;
68
+ to: string;
69
+ asPassed?: boolean;
37
70
  }): void;
38
71
  protected signerSeeds(node: ts.Expression | undefined, authority: AccountParam, at: ts.Node): {
39
72
  name: string;
@@ -47,25 +80,41 @@ export declare abstract class CpiEmitter extends CallEmitter {
47
80
  protected tokenOp(node: ts.CallExpression, program: AccountParam, method: string): undefined;
48
81
  protected ataOp(node: ts.CallExpression, program: AccountParam, method: string): undefined;
49
82
  protected metadataOp(node: ts.CallExpression, program: AccountParam, method: string): undefined;
83
+ /** CreateMasterEditionV3 (17) and Verify (52) with VerificationArgs::CollectionV1. */
84
+ protected metadataCollectionOp(node: ts.CallExpression, program: AccountParam, method: string): undefined;
50
85
  /**
51
86
  * One account of a Metaplex CPI: an account parameter, or `null` for an optional account left out
52
87
  * (Metaplex programs take their own id in its place).
53
88
  */
54
89
  protected mplMeta(n: ts.Expression, program: AccountParam, what: string, writable: boolean, signer: boolean): [string, boolean, boolean];
55
90
  /** Borsh fields into a fresh buffer: raw bytes ("u8:N" style) or lowered values. */
56
- protected mplData(at: ts.Node, max: number, fields: ({
57
- bytes: number[];
58
- } | {
59
- value: ts.Expression;
60
- type: ValueType;
61
- })[]): {
91
+ protected mplData(at: ts.Node, max: number, fields: MplField[]): {
62
92
  buf: string;
63
93
  len: string;
64
94
  };
65
- /** Metaplex Core: createAsset, createCollection, transferAsset, burnAsset (no plugins). */
95
+ /**
96
+ * Borsh of one Metaplex Core plugin literal (`{ kind: "FreezeDelegate", frozen: true, authority?: … }`): the Plugin
97
+ * enum, then (`withAuthority`) the Option<PluginAuthority> that CreateV1's PluginAuthorityPair and AddPluginV1 take.
98
+ */
99
+ protected corePlugin(n: ts.Expression, withAuthority: boolean): MplField[];
100
+ /** CreateV1 / CreateCollectionV1 plugins: Option<Vec<PluginAuthorityPair>>. */
101
+ protected corePluginList(n: ts.Expression | undefined): MplField[];
102
+ /** Metaplex Core: assets and collections (with plugins), plugins added, updated and removed, transfer and burn. */
66
103
  protected coreOp(node: ts.CallExpression, core: AccountParam, method: string): undefined;
104
+ /** PluginType (u8) from a kind string literal: removePlugin(…, "FreezeDelegate"). */
105
+ protected corePluginType(n: ts.Expression): MplField;
67
106
  /** Bubblegum (compressed NFTs on SPL account compression): createTree, mint (MintV1, no collection, no creators). */
68
107
  protected bubblegumOp(node: ts.CallExpression, bg: AccountParam, method: string): undefined;
108
+ /** Bubblegum V2 (trees on mpl-account-compression with mpl-noop; optional Metaplex Core collections). */
109
+ protected bubblegumV2(node: ts.CallExpression, bg: AccountParam, method: string): undefined;
110
+ /** Object literal properties by name, refusing others. */
111
+ protected literalProps(o: ts.ObjectLiteralExpression, allowed: string[], what: string): Map<string, ts.Expression>;
112
+ /** Vec<Creator> (address, verified, share) from a literal list; shares add up to 100 when literal. */
113
+ protected bubblegumCreators(creators: ts.Expression | undefined): MplField[];
114
+ /** UpdateArgs: every field optional (left out or null: unchanged). */
115
+ protected bubblegumUpdateArgs(n: ts.Expression): MplField[];
116
+ /** `acct.key` of an account parameter, as an expression to serialize. */
117
+ protected keyOf(n: ts.Expression): ts.Expression;
69
118
  /**
70
119
  * `remainingAccounts()` (or a const bound to it): every remaining account; `rest.slice(a, b?)`: indexes a..b of them
71
120
  * (both checked against the count, 5104). C expressions for the range, relative to the first remaining account.
@@ -94,8 +143,13 @@ export declare abstract class CpiEmitter extends CallEmitter {
94
143
  authority: string;
95
144
  program: string;
96
145
  }): undefined;
146
+ /** emit<T> of a @layout borsh struct: built like account data, then packed as Anchor serializes it. */
147
+ private emitBorshEvent;
148
+ /** Discriminator + `body`, logged (emit) or self-invoked (emitCpi). */
149
+ private sendEvent;
97
150
  /** Structs reachable through the fields of struct `name` (not including itself unless it recurses). */
98
151
  protected nestedStructs(name: string): Set<string>;
99
152
  /** Structs whose IDL description is the fixed layout: account data, arguments, and everything nested in them. */
100
153
  protected fixedLayoutStructs(): Set<string>;
101
154
  }
155
+ export {};