@xgamesfun/solana 0.24.0 → 0.25.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.
Files changed (92) hide show
  1. package/README.md +94 -51
  2. package/bin/xsolana.mjs +23 -8
  3. package/examples/blind-forge.json +2 -4
  4. package/examples/coin-flip-arena.json +2 -5
  5. package/examples/duel-arena.json +1 -4
  6. package/examples/fair-presale.json +1 -3
  7. package/examples/hero-trials.json +14 -2
  8. package/examples/holder-den.json +38 -0
  9. package/examples/holders-drop.json +105 -0
  10. package/examples/ideas.json +788 -788
  11. package/examples/match-predictions.json +24 -0
  12. package/examples/nft-raffle.json +1 -0
  13. package/examples/pack-league.json +108 -0
  14. package/examples/partner-vault.json +19 -3
  15. package/examples/sacrifice-raffle.json +2 -10
  16. package/examples/shelter-fair.json +1 -0
  17. package/examples/stakers-draw.json +3 -7
  18. package/examples/stride-sneakers.json +164 -0
  19. package/examples/trade-in-shop.json +2 -3
  20. package/js/approve/details.mjs +117 -48
  21. package/js/approve/ed25519.mjs +5 -1
  22. package/js/approve/live-check.mjs +83 -26
  23. package/js/approve/page.html +217 -78
  24. package/js/approve/page.js +43 -15
  25. package/js/approve/server.mjs +276 -74
  26. package/js/chain/base58.js +7 -1
  27. package/js/chain/borsh.js +15 -11
  28. package/js/chain/bytes.js +11 -8
  29. package/js/chain/core.js +21 -5
  30. package/js/chain/curve.js +1 -1
  31. package/js/chain/lookup.js +118 -36
  32. package/js/chain/mint.js +6 -2
  33. package/js/chain/pda.js +2 -2
  34. package/js/chain/programs.js +6 -6
  35. package/js/chain/rpc.js +40 -14
  36. package/js/chain/token.js +13 -2
  37. package/js/chain/token2022.js +55 -16
  38. package/js/chain/tx.js +32 -22
  39. package/js/client/accounts.js +270 -80
  40. package/js/client/compressed.js +4 -3
  41. package/js/client/grant.js +165 -40
  42. package/js/client/idl/loot.js +1 -1
  43. package/js/client/idl/loot.json +104 -16
  44. package/js/client/ix.js +2121 -457
  45. package/js/client/pda.js +20 -18
  46. package/js/client/policy.js +12 -5
  47. package/js/client/random.js +1 -1
  48. package/js/client/sizes.js +220 -65
  49. package/js/client/traits.js +14 -5
  50. package/js/connect/connect.mjs +59 -17
  51. package/js/economy/check.mjs +3873 -690
  52. package/js/economy/cost.mjs +380 -56
  53. package/js/economy/examples.mjs +176 -35
  54. package/js/economy/explain.mjs +461 -110
  55. package/js/economy/guide.mjs +282 -59
  56. package/js/economy/legal.mjs +12 -6
  57. package/js/economy/live.mjs +60 -19
  58. package/js/economy/model.mjs +320 -97
  59. package/js/economy/plan.mjs +1022 -203
  60. package/js/economy/schema.json +127 -369
  61. package/js/economy/secrets.mjs +17 -7
  62. package/js/economy/simulate.mjs +771 -178
  63. package/js/economy/txsize.mjs +15 -3
  64. package/js/economy/validate.mjs +61 -24
  65. package/js/mcp/server.mjs +42 -14
  66. package/js/mcp/tools.mjs +293 -80
  67. package/js/play/index.js +1960 -461
  68. package/js/play/keys.js +35 -9
  69. package/js/results/index.js +223 -30
  70. package/js/results/server.js +230 -0
  71. package/js/results/wire.js +64 -16
  72. package/package.json +6 -4
  73. package/release.json +5 -5
  74. package/skills/xsolana-economy/SKILL.md +30 -16
  75. package/skills/xsolana-economy/references/after-launch.md +30 -20
  76. package/skills/xsolana-economy/references/apps.md +47 -36
  77. package/skills/xsolana-economy/references/sentence-to-spec.md +148 -129
  78. package/skills/xsolana-economy/references/telling-the-person.md +9 -6
  79. package/types/chain/core.d.ts +1 -1
  80. package/types/chain/lookup.d.ts +1 -1
  81. package/types/client/accounts.d.ts +24 -3
  82. package/types/client/grant.d.ts +2 -2
  83. package/types/client/idl/loot.d.ts +22 -0
  84. package/types/client/ix.d.ts +54 -45
  85. package/types/client/pda.d.ts +3 -1
  86. package/types/economy/guide.d.mts +5 -0
  87. package/types/economy/model.d.mts +48 -3
  88. package/types/economy/plan.d.mts +44 -2
  89. package/types/play/index.d.ts +8 -19
  90. package/types/results/index.d.ts +7 -6
  91. package/types/results/server.d.ts +126 -0
  92. package/types/results/wire.d.ts +1 -1
@@ -11,7 +11,7 @@ const HEADER = 56;
11
11
  * the tree account's bytes.
12
12
  */
13
13
  export function proofLength(treeData) {
14
- const u32 = (at) => treeData[at] | (treeData[at + 1] << 8) | (treeData[at + 2] << 16) | (treeData[at + 3] * 2 ** 24);
14
+ const u32 = at => treeData[at] | (treeData[at + 1] << 8) | (treeData[at + 2] << 16) | (treeData[at + 3] * 2 ** 24);
15
15
  const [buffer, depth] = [u32(2), u32(6)];
16
16
  const canopyAt = HEADER + 24 + buffer * (32 * depth + 40) + 32 * depth + 40;
17
17
  const canopy = Math.max(0, treeData.length - canopyAt);
@@ -19,7 +19,8 @@ export function proofLength(treeData) {
19
19
  return Math.max(0, depth - Math.round(cached));
20
20
  }
21
21
 
22
- const bytes = (value) => (value == null ? null : typeof value === 'string' ? decodeBase58(value) : Uint8Array.from(value));
22
+ const bytes = value =>
23
+ value == null ? null : typeof value === 'string' ? decodeBase58(value) : Uint8Array.from(value);
23
24
 
24
25
  /**
25
26
  * A compressed NFT from an indexer's answers: `asset` (DAS `getAsset`), `proof` (DAS `getAssetProof`) and the tree
@@ -35,7 +36,7 @@ export function compressedFromDas({ asset, proof, treeData }) {
35
36
  nonce: BigInt(c.leaf_id),
36
37
  owner: asset.ownership.owner,
37
38
  delegate: asset.ownership.delegate ?? asset.ownership.owner,
38
- collection: asset.grouping?.find((g) => g.group_key === 'collection')?.group_value ?? null,
39
+ collection: asset.grouping?.find(g => g.group_key === 'collection')?.group_value ?? null,
39
40
  dataHash: bytes(c.data_hash),
40
41
  creatorHash: bytes(c.creator_hash),
41
42
  assetDataHash: bytes(c.asset_data_hash ?? null),
@@ -33,9 +33,9 @@ export const CLAIM_COMPUTE_UNITS = 400_000;
33
33
  export const ZERO_HASH = new Uint8Array(32);
34
34
  export const ED25519_PROGRAM = 'Ed25519SigVerify111111111111111111111111111';
35
35
  /** The seconds of a UTC day (the IDL's `DAY_SECONDS`): a limit's window of a day (`PerWallet.window`). */
36
- const DAY_SECONDS = Number(IDL.constants.find((c) => c.name === 'DAY_SECONDS').value);
36
+ const DAY_SECONDS = Number(IDL.constants.find(c => c.name === 'DAY_SECONDS').value);
37
37
  /** The day a window of `DAY_SECONDS` counts in, from the unix epoch. */
38
- export const dayOf = (unixSeconds) => Math.floor(Number(unixSeconds) / DAY_SECONDS);
38
+ export const dayOf = unixSeconds => Math.floor(Number(unixSeconds) / DAY_SECONDS);
39
39
 
40
40
  /** 32 bytes from a base58 address, 32 bytes or 64 hex characters. */
41
41
  function bytes32(value, what) {
@@ -48,24 +48,53 @@ function bytes32(value, what) {
48
48
  throw new TypeError(`${what} must be an address or 32 bytes`);
49
49
  }
50
50
 
51
- const personBytes = (value) => (value === null || value === undefined || value === '' ? ZERO_HASH : bytes32(value, 'person_hash'));
51
+ const personBytes = value =>
52
+ value === null || value === undefined || value === '' ? ZERO_HASH : bytes32(value, 'person_hash');
52
53
 
53
54
  function roundBytes(value) {
54
- const out = value instanceof Uint8Array ? value : typeof value === 'string' && /^[0-9a-f]{32}$/i.test(value) ? fromHex(value) : null;
55
+ const out =
56
+ value instanceof Uint8Array
57
+ ? value
58
+ : typeof value === 'string' && /^[0-9a-f]{32}$/i.test(value)
59
+ ? fromHex(value)
60
+ : null;
55
61
  if (!out || out.length !== 16) throw new RangeError('round must be 16 bytes (32 hex characters)');
56
62
  return out;
57
63
  }
58
64
 
59
65
  /** An i64 little-endian (two's complement), as the program reads `expires`. */
60
- export const i64LE = (value) => intLE(value, 8);
66
+ export const i64LE = value => intLE(value, 8);
61
67
 
62
68
  /** A claim's rounds: [{ id (16 bytes or 32 hex characters), amount }], or one `round` and its `amount`. */
63
- const roundsOf = (rounds, round, amount) => (rounds ?? [{ id: round, amount }]).map((r) => ({ id: roundBytes(r.id ?? r.round ?? new Uint8Array(16)), amount: toBigInt(r.amount ?? 0) }));
69
+ const roundsOf = (rounds, round, amount) =>
70
+ (rounds ?? [{ id: round, amount }]).map(r => ({
71
+ id: roundBytes(r.id ?? r.round ?? new Uint8Array(16)),
72
+ amount: toBigInt(r.amount ?? 0),
73
+ }));
64
74
 
65
75
  /** A voucher's body, which its key signs the sha256 of (`voucherBytes`). */
66
- export function voucherBody({ program = LOOT_PROGRAM, grant, incarnation, wallet, personHash, expires, rounds, round, amount = 0n }) {
76
+ export function voucherBody({
77
+ program = LOOT_PROGRAM,
78
+ grant,
79
+ incarnation,
80
+ wallet,
81
+ personHash,
82
+ expires,
83
+ rounds,
84
+ round,
85
+ amount = 0n,
86
+ }) {
67
87
  const list = roundsOf(rounds, round, amount);
68
- return concat(bytes32(program, 'program'), bytes32(grant, 'grant'), uintLE(incarnation, 8), bytes32(wallet, 'wallet'), personBytes(personHash), i64LE(expires), uintLE(list.length, 4), ...list.flatMap((r) => [r.id, uintLE(r.amount, 8)]));
88
+ return concat(
89
+ bytes32(program, 'program'),
90
+ bytes32(grant, 'grant'),
91
+ uintLE(incarnation, 8),
92
+ bytes32(wallet, 'wallet'),
93
+ personBytes(personHash),
94
+ i64LE(expires),
95
+ uintLE(list.length, 4),
96
+ ...list.flatMap(r => [r.id, uintLE(r.amount, 8)]),
97
+ );
69
98
  }
70
99
 
71
100
  /**
@@ -74,7 +103,7 @@ export function voucherBody({ program = LOOT_PROGRAM, grant, incarnation, wallet
74
103
  * ([{ id, amount }], or one `round` and its `amount`) names the wins (the project round, draw or giveaway each was won
75
104
  * in): the program pays a wallet each round once per grant incarnation.
76
105
  */
77
- export const voucherBytes = (fields) => concat(utf8(VOUCHER_DOMAIN), sha256(voucherBody(fields)));
106
+ export const voucherBytes = fields => concat(utf8(VOUCHER_DOMAIN), sha256(voucherBody(fields)));
78
107
 
79
108
  /** The fields back from a voucher's body (`voucherBody`; addresses as bytes, rounds as [{ id, amount }]). */
80
109
  export function readVoucher(body) {
@@ -84,12 +113,23 @@ export function readVoucher(body) {
84
113
  if (expires >= 1n << 63n) expires -= 1n << 64n;
85
114
  const count = Number(readUintLE(body, 144, 4));
86
115
  if (body.length !== 148 + 24 * count) throw new RangeError('a voucher body holds 24 bytes a round');
87
- const rounds = Array.from({ length: count }, (_, i) => ({ id: at(148 + 24 * i, 16), amount: readUintLE(body, 164 + 24 * i, 8) }));
88
- return { program: at(0, 32), grant: at(32, 32), incarnation: readUintLE(body, 64, 8), wallet: at(72, 32), personHash: at(104, 32), expires, rounds };
116
+ const rounds = Array.from({ length: count }, (_, i) => ({
117
+ id: at(148 + 24 * i, 16),
118
+ amount: readUintLE(body, 164 + 24 * i, 8),
119
+ }));
120
+ return {
121
+ program: at(0, 32),
122
+ grant: at(32, 32),
123
+ incarnation: readUintLE(body, 64, 8),
124
+ wallet: at(72, 32),
125
+ personHash: at(104, 32),
126
+ expires,
127
+ rounds,
128
+ };
89
129
  }
90
130
 
91
131
  /** A voucher key's leaf under a grant's `key_root`. */
92
- export const keyLeaf = (key) => sha256(concat(utf8(KEY_DOMAIN), bytes32(key, 'key')));
132
+ export const keyLeaf = key => sha256(concat(utf8(KEY_DOMAIN), bytes32(key, 'key')));
93
133
 
94
134
  /** A list entry's round as the leaf names it: a number (a spec's `round`) in the first 8 of 16 bytes; 0 is zeros. */
95
135
  export const listRound = (n = 0) => {
@@ -103,31 +143,41 @@ export const listRound = (n = 0) => {
103
143
  * paid once, so a list can name the winners of many rounds, and a wallet's earlier wins stay claimable when a new
104
144
  * list adds later ones.
105
145
  */
106
- export const listLeaf = (wallet, personHash, round, amount = 0n) => sha256(concat(utf8(LIST_DOMAIN), bytes32(wallet, 'wallet'), personBytes(personHash), roundBytes(round ?? new Uint8Array(16)), uintLE(amount, 8)));
146
+ export const listLeaf = (wallet, personHash, round, amount = 0n) =>
147
+ sha256(
148
+ concat(
149
+ utf8(LIST_DOMAIN),
150
+ bytes32(wallet, 'wallet'),
151
+ personBytes(personHash),
152
+ roundBytes(round ?? new Uint8Array(16)),
153
+ uintLE(amount, 8),
154
+ ),
155
+ );
107
156
 
108
157
  /** The prefix of a wallet's leaf in a list gate (`gateListLeaf`). */
109
158
  export const GATE_LIST_DOMAIN = 'loot-list-v1';
110
159
  /** A wallet's leaf in a list gate (`Gate::List`): sha256("loot-list-v1" | wallet). Its tree is a list's
111
160
  * (`merkleRoot`, `merkleProof`), and its proof's nodes go where an NFT shown would (`gateAccounts`'s `listProof`). */
112
- export const gateListLeaf = (wallet) => sha256(concat(utf8(GATE_LIST_DOMAIN), bytes32(wallet, 'wallet')));
161
+ export const gateListLeaf = wallet => sha256(concat(utf8(GATE_LIST_DOMAIN), bytes32(wallet, 'wallet')));
113
162
 
114
163
  /** The parent of two nodes: sha256 of the smaller then the larger. */
115
164
  export const parentOf = (a, b) => (compareBytes(a, b) <= 0 ? sha256(concat(a, b)) : sha256(concat(b, a)));
116
165
 
117
166
  function levelsOf(leaves) {
118
167
  if (!leaves.length) throw new RangeError('a list needs at least one wallet');
119
- const levels = [leaves.map((l) => bytes32(l, 'leaf'))];
168
+ const levels = [leaves.map(l => bytes32(l, 'leaf'))];
120
169
  while (levels.at(-1).length > 1) {
121
170
  const level = levels.at(-1);
122
171
  const next = [];
123
- for (let i = 0; i < level.length; i += 2) next.push(i + 1 < level.length ? parentOf(level[i], level[i + 1]) : level[i]);
172
+ for (let i = 0; i < level.length; i += 2)
173
+ next.push(i + 1 < level.length ? parentOf(level[i], level[i + 1]) : level[i]);
124
174
  levels.push(next);
125
175
  }
126
176
  return levels;
127
177
  }
128
178
 
129
179
  /** The root of the leaves, in the order given. Whoever builds the list keeps that order. */
130
- export const merkleRoot = (leaves) => levelsOf(leaves).at(-1)[0];
180
+ export const merkleRoot = leaves => levelsOf(leaves).at(-1)[0];
131
181
 
132
182
  /** The siblings of leaf `index`, from the bottom up. */
133
183
  export function merkleProof(leaves, index) {
@@ -150,7 +200,7 @@ export function merkleProof(leaves, index) {
150
200
  */
151
201
  export function gateList(wallets) {
152
202
  if (!wallets.length) throw new RangeError('a list needs at least one wallet');
153
- const leaves = wallets.map((w) => gateListLeaf(w));
203
+ const leaves = wallets.map(w => gateListLeaf(w));
154
204
  let size = 1;
155
205
  while (size < leaves.length) size *= 2;
156
206
  // Filled with a leaf no wallet has (all zeros): a wallet's leaf is a hash, so nobody can prove a filler.
@@ -158,7 +208,7 @@ export function gateList(wallets) {
158
208
  return {
159
209
  root: merkleRoot(leaves),
160
210
  depth: Math.log2(size),
161
- proofOf: (wallet) => {
211
+ proofOf: wallet => {
162
212
  const at = wallets.indexOf(wallet);
163
213
  if (at < 0) throw new RangeError(`${wallet} is not on the list`);
164
214
  return merkleProof(leaves, at);
@@ -184,9 +234,21 @@ export function ed25519Ix({ publicKey, signature, message }) {
184
234
  const keyAt = 16;
185
235
  const signatureAt = keyAt + 32;
186
236
  const messageAt = signatureAt + 64;
187
- const u16 = (n) => uintLE(n, 2);
237
+ const u16 = n => uintLE(n, 2);
188
238
  const THIS = 0xffff;
189
- const data = concat(Uint8Array.of(1, 0), u16(signatureAt), u16(THIS), u16(keyAt), u16(THIS), u16(messageAt), u16(message.length), u16(THIS), key, signature, message);
239
+ const data = concat(
240
+ Uint8Array.of(1, 0),
241
+ u16(signatureAt),
242
+ u16(THIS),
243
+ u16(keyAt),
244
+ u16(THIS),
245
+ u16(messageAt),
246
+ u16(message.length),
247
+ u16(THIS),
248
+ key,
249
+ signature,
250
+ message,
251
+ );
190
252
  return { programId: ED25519_PROGRAM, keys: [], data };
191
253
  }
192
254
 
@@ -207,7 +269,8 @@ export const shardOf = (key, bits) => (Number(bits) ? key[0] >> (8 - Number(bits
207
269
  export const walletShard = (grant, wallet) => shardOf(limitKey('wallet', wallet), grant.shard_bits);
208
270
 
209
271
  /** Whether a grant paid `wallet` for `round`, from the wallet's decoded rounds shard (`decodeList`, null for none). */
210
- export const roundPaid = (list, wallet, round) => Boolean(list?.records.some((r) => compareBytes(r, roundKey(round, wallet)) === 0));
272
+ export const roundPaid = (list, wallet, round) =>
273
+ Boolean(list?.records.some(r => compareBytes(r, roundKey(round, wallet)) === 0));
211
274
 
212
275
  /**
213
276
  * The fewest shard bits (0 to 8) that keep each of a grant's lists under ~100,000 records over its life: `wallets` ×
@@ -237,14 +300,38 @@ export function shardBitsFor(wallets, rounds = 1) {
237
300
  * order only (`askRollIx` then asks for it, in the same transaction when it fits). Send it with a compute limit of
238
301
  * `CLAIM_COMPUTE_UNITS`.
239
302
  */
240
- export function claimGrantIx({ project, id, grant, wallet, signer, count = 0, rounds, round, expires, personHash, amount = 0n, proofs, proof = [], paidRounds = null, poolMint, item, nft, shown, listProof, programs, voucherKey, nonce, extra = [] }) {
303
+ export function claimGrantIx({
304
+ project,
305
+ id,
306
+ grant,
307
+ wallet,
308
+ signer,
309
+ count = 0,
310
+ rounds,
311
+ round,
312
+ expires,
313
+ personHash,
314
+ amount = 0n,
315
+ proofs,
316
+ proof = [],
317
+ paidRounds = null,
318
+ poolMint,
319
+ item,
320
+ nft,
321
+ shown,
322
+ listProof,
323
+ programs,
324
+ voucherKey,
325
+ nonce,
326
+ extra = [],
327
+ }) {
241
328
  if (!signer) throw new Error('A claim needs its signer: whoever sends it');
242
329
  // Every claim is its winning wallet's own: the wallet signs it, whatever proves it (a voucher, a list, an open
243
330
  // grant), so nobody claims for a player (WalletMustSign). `signer` pays the fees and what the claim opens: the
244
331
  // wallet itself, or anyone who pays for it.
245
332
  const address = pda.grant(project, id);
246
333
  const person = personBytes(personHash);
247
- const listed = Uint8Array.from(grant.list_root ?? []).some((b) => b !== 0);
334
+ const listed = Uint8Array.from(grant.list_root ?? []).some(b => b !== 0);
248
335
  // A claim by voucher or list names its rounds; an open one names none.
249
336
  const named = Boolean(voucherKey) || listed || rounds != null || round != null;
250
337
  const list = named ? roundsOf(rounds, round ?? new Uint8Array(16), amount) : [];
@@ -252,40 +339,74 @@ export function claimGrantIx({ project, id, grant, wallet, signer, count = 0, ro
252
339
  // gated by one shows (a badge), a voucher key's; each shard of the grant's claims once, by shard number.
253
340
  const bits = Number(grant.shard_bits ?? 0);
254
341
  const keys = [limitKey('wallet', wallet)];
255
- if (person.some((b) => b !== 0) && Number(grant.limits?.per_person ?? 0) > 0) keys.push(limitKey('person', person));
256
- const badge = typeof shown === 'string' ? shown : shown?.asset ?? shown?.mint ?? shown?.compressed;
342
+ if (person.some(b => b !== 0) && Number(grant.limits?.per_person ?? 0) > 0) keys.push(limitKey('person', person));
343
+ const badge = typeof shown === 'string' ? shown : (shown?.asset ?? shown?.mint ?? shown?.compressed);
257
344
  if (!named && grant.open && grant.gate?.Holds && badge) keys.push(limitKey('badge', badge));
258
345
  if (voucherKey && Number(grant.limits?.per_key ?? 0) > 0) keys.push(limitKey('code', voucherKey));
259
- const shards = [...new Set(keys.map((k) => shardOf(k, bits)))].sort((x, y) => x - y).map((shard) => meta(pda.claims(address, grant.incarnation, shard), false, true));
260
- nonce = toBigInt(nonce ?? (named ? prizeNonce(address, wallet, ...list.map((r) => r.id)) : prizeNonce(address, wallet, toBigInt(count))));
346
+ const shards = [...new Set(keys.map(k => shardOf(k, bits)))]
347
+ .sort((x, y) => x - y)
348
+ .map(shard => meta(pda.claims(address, grant.incarnation, shard), false, true));
349
+ nonce = toBigInt(
350
+ nonce ??
351
+ (named ? prizeNonce(address, wallet, ...list.map(r => r.id)) : prizeNonce(address, wallet, toBigInt(count))),
352
+ );
261
353
  // Each round not paid yet gives the grant's prize, or the amount of its tokens the round names, in order; collectibles
262
354
  // of one item each at its next serial.
263
355
  const gives = grant.gives;
264
356
  const pool = gives.Tokens?.from.Pool?.[0];
265
357
  const itemId = gives.Item?.[0] ?? gives.Compressed?.item;
266
- if (pool !== undefined && !poolMint) throw new Error('A payout claim needs its pool’s mint (poolMint), read from the pool');
358
+ if (pool !== undefined && !poolMint)
359
+ throw new Error('A payout claim needs its pool’s mint (poolMint), read from the pool');
267
360
  const seen = new Set();
268
- const owed = (named ? list.map((r, i) => ({ ...r, i })) : [{ amount: 0n, i: 0 }]).filter((r) => {
361
+ const owed = (named ? list.map((r, i) => ({ ...r, i })) : [{ amount: 0n, i: 0 }]).filter(r => {
269
362
  if (!named) return true;
270
- const hex = Array.from(r.id, (b) => b.toString(16).padStart(2, '0')).join('');
363
+ const hex = Array.from(r.id, b => b.toString(16).padStart(2, '0')).join('');
271
364
  if (seen.has(hex) || roundPaid(paidRounds, wallet, r.id)) return false;
272
365
  seen.add(hex);
273
366
  return true;
274
367
  });
275
- const prizes = owed.flatMap((r, made) => prizeMetas({
276
- project, prize: r.amount > 0n && gives.Tokens ? { Tokens: { ...gives.Tokens, amount: r.amount } } : gives, winner: wallet, nonce: BigInt.asUintN(64, nonce + BigInt(r.i)), programs,
277
- poolMints: pool !== undefined ? { [pool]: poolMint } : {}, items: itemId !== undefined ? { [itemId]: item } : {}, nft, made,
278
- }));
368
+ const prizes = owed.flatMap((r, made) =>
369
+ prizeMetas({
370
+ project,
371
+ prize: r.amount > 0n && gives.Tokens ? { Tokens: { ...gives.Tokens, amount: r.amount } } : gives,
372
+ winner: wallet,
373
+ nonce: BigInt.asUintN(64, nonce + BigInt(r.i)),
374
+ programs,
375
+ poolMints: pool !== undefined ? { [pool]: poolMint } : {},
376
+ items: itemId !== undefined ? { [itemId]: item } : {},
377
+ nft,
378
+ made,
379
+ }),
380
+ );
279
381
  proofs ??= listed && !voucherKey ? [proof] : proof.length ? [proof] : [];
280
382
  return lootIx(
281
383
  'claim_grant',
282
- { rounds: list, expires: toBigInt(expires ?? 0), person_hash: person, proofs: proofs.map((p) => p.map((x) => bytes32(x, 'proof'))), nonce },
283
384
  {
284
- project, grant: address, signer, wallet,
385
+ rounds: list,
386
+ expires: toBigInt(expires ?? 0),
387
+ person_hash: person,
388
+ proofs: proofs.map(p => p.map(x => bytes32(x, 'proof'))),
389
+ nonce,
390
+ },
391
+ {
392
+ project,
393
+ grant: address,
394
+ signer,
395
+ wallet,
285
396
  rounds: named ? pda.rounds(address, grant.incarnation, shardOf(keys[0], bits)) : null,
286
- token_program: undefined, token_2022_program: undefined, associated_token_program: ASSOCIATED_TOKEN_PROGRAM,
397
+ token_program: undefined,
398
+ token_2022_program: undefined,
399
+ associated_token_program: ASSOCIATED_TOKEN_PROGRAM,
400
+ },
401
+ {
402
+ remaining: [
403
+ ...gateAccounts(project, { gate: grant.gate, wallet, shown, listProof }),
404
+ ...shards,
405
+ ...prizes,
406
+ ...tailOf(extra),
407
+ ],
408
+ signer: ['wallet'],
287
409
  },
288
- { remaining: [...gateAccounts(project, { gate: grant.gate, wallet, shown, listProof }), ...shards, ...prizes, ...tailOf(extra)], signer: ['wallet'] },
289
410
  );
290
411
  }
291
412
 
@@ -295,5 +416,9 @@ export function claimGrantIx({ project, id, grant, wallet, signer, count = 0, ro
295
416
  */
296
417
  export const closeShardIx = ({ project, id, incarnation, rounds = false, shard, owner }) => {
297
418
  const grant = pda.grant(project, id);
298
- return lootIx('close_shard', { id, incarnation: toBigInt(incarnation), rounds, shard }, { project, grant, shard: (rounds ? pda.rounds : pda.claims)(grant, incarnation, shard), owner });
419
+ return lootIx(
420
+ 'close_shard',
421
+ { id, incarnation: toBigInt(incarnation), rounds, shard },
422
+ { project, grant, shard: (rounds ? pda.rounds : pda.claims)(grant, incarnation, shard), owner },
423
+ );
299
424
  };