@xgamesfun/solana 0.24.0 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DISCLAIMER.md +1 -1
- package/NOTICE +4 -4
- package/README.md +100 -52
- package/bin/xsolana.mjs +32 -11
- package/examples/blind-forge.json +2 -4
- package/examples/coin-flip-arena.json +2 -5
- package/examples/duel-arena.json +1 -4
- package/examples/fair-presale.json +1 -3
- package/examples/hero-trials.json +14 -2
- package/examples/ideas.json +788 -788
- package/examples/nft-raffle.json +1 -0
- package/examples/partner-vault.json +19 -3
- package/examples/sacrifice-raffle.json +2 -10
- package/examples/shelter-fair.json +1 -0
- package/examples/stakers-draw.json +4 -7
- package/examples/trade-in-shop.json +2 -3
- package/js/approve/details.mjs +117 -48
- package/js/approve/ed25519.mjs +5 -1
- package/js/approve/live-check.mjs +83 -26
- package/js/approve/page.html +217 -78
- package/js/approve/page.js +43 -15
- package/js/approve/server.mjs +276 -74
- package/js/chain/base58.js +7 -1
- package/js/chain/borsh.js +15 -11
- package/js/chain/bytes.js +11 -8
- package/js/chain/core.js +21 -5
- package/js/chain/curve.js +1 -1
- package/js/chain/lookup.js +118 -36
- package/js/chain/mint.js +6 -2
- package/js/chain/pda.js +2 -2
- package/js/chain/programs.js +6 -6
- package/js/chain/rpc.js +40 -14
- package/js/chain/token.js +13 -2
- package/js/chain/token2022.js +55 -16
- package/js/chain/tx.js +32 -22
- package/js/client/accounts.js +270 -80
- package/js/client/compressed.js +4 -3
- package/js/client/grant.js +165 -40
- package/js/client/idl/loot.js +1 -1
- package/js/client/idl/loot.json +104 -16
- package/js/client/ix.js +2121 -457
- package/js/client/pda.js +20 -18
- package/js/client/policy.js +12 -5
- package/js/client/random.js +2 -2
- package/js/client/sizes.js +220 -65
- package/js/client/traits.js +14 -5
- package/js/connect/connect.mjs +59 -17
- package/js/economy/check.mjs +3884 -690
- package/js/economy/cost.mjs +381 -57
- package/js/economy/examples.mjs +176 -35
- package/js/economy/explain.mjs +468 -110
- package/js/economy/guide.mjs +282 -59
- package/js/economy/legal.mjs +12 -6
- package/js/economy/live.mjs +62 -20
- package/js/economy/model.mjs +320 -97
- package/js/economy/plan.mjs +1022 -203
- package/js/economy/review.mjs +760 -0
- package/js/economy/schema.json +134 -372
- package/js/economy/secrets.mjs +17 -7
- package/js/economy/simulate.mjs +771 -178
- package/js/economy/trust.mjs +15 -0
- package/js/economy/txsize.mjs +15 -3
- package/js/economy/validate.mjs +61 -24
- package/js/index.js +1 -0
- package/js/mcp/server.mjs +43 -15
- package/js/mcp/tools.mjs +318 -80
- package/js/play/index.js +1960 -461
- package/js/play/keys.js +35 -9
- package/js/results/index.js +225 -32
- package/js/results/server.js +230 -0
- package/js/results/wire.js +64 -16
- package/package.json +6 -4
- package/release.json +5 -5
- package/skills/xsolana-economy/SKILL.md +52 -22
- package/skills/xsolana-economy/references/after-launch.md +32 -21
- package/skills/xsolana-economy/references/apps.md +47 -36
- package/skills/xsolana-economy/references/sentence-to-spec.md +149 -129
- package/skills/xsolana-economy/references/telling-the-person.md +15 -6
- package/skills/xsolana-economy/references/trust-and-cheating.md +126 -0
- package/types/chain/core.d.ts +1 -1
- package/types/chain/lookup.d.ts +1 -1
- package/types/client/accounts.d.ts +24 -3
- package/types/client/grant.d.ts +2 -2
- package/types/client/idl/loot.d.ts +22 -0
- package/types/client/ix.d.ts +54 -45
- package/types/client/pda.d.ts +3 -1
- package/types/economy/cost.d.mts +1 -1
- package/types/economy/explain.d.mts +3 -0
- package/types/economy/guide.d.mts +5 -0
- package/types/economy/model.d.mts +48 -3
- package/types/economy/plan.d.mts +44 -2
- package/types/economy/review.d.mts +45 -0
- package/types/economy/trust.d.mts +8 -0
- package/types/index.d.ts +1 -0
- package/types/mcp/tools.d.mts +62 -0
- package/types/play/index.d.ts +14 -25
- package/types/results/index.d.ts +8 -7
- package/types/results/server.d.ts +126 -0
- package/types/results/wire.d.ts +1 -1
package/js/client/compressed.js
CHANGED
|
@@ -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 =
|
|
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 =
|
|
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(
|
|
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),
|
package/js/client/grant.js
CHANGED
|
@@ -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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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) =>
|
|
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({
|
|
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(
|
|
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 =
|
|
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) => ({
|
|
88
|
-
|
|
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 =
|
|
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) =>
|
|
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 =
|
|
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(
|
|
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)
|
|
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 =
|
|
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(
|
|
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:
|
|
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 =
|
|
237
|
+
const u16 = n => uintLE(n, 2);
|
|
188
238
|
const THIS = 0xffff;
|
|
189
|
-
const data = concat(
|
|
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) =>
|
|
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({
|
|
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(
|
|
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(
|
|
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(
|
|
260
|
-
|
|
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)
|
|
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(
|
|
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,
|
|
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) =>
|
|
276
|
-
|
|
277
|
-
|
|
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
|
-
|
|
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,
|
|
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(
|
|
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
|
};
|