@domino-sdk/relay 1.67.0 → 1.69.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 (81) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/dist/{accounts-C2O8mpB8.d.ts → accounts-DD4gAOCe.d.ts} +232 -3
  3. package/dist/{action-9Xl0StBg.d.ts → action-BDFKqGlH.d.ts} +3 -2
  4. package/dist/{attempt-captures-ClHAoo_n.d.ts → attempt-captures-CbuCmthd.d.ts} +11 -2
  5. package/dist/authoring.d.ts +534 -48
  6. package/dist/authoring.js +192 -29
  7. package/dist/{automatic-outcomes-BEnPn4Uh.d.ts → automatic-outcomes-DE3vfi8g.d.ts} +11 -3
  8. package/dist/avatar.d.ts +2 -1
  9. package/dist/browser.d.ts +15 -13
  10. package/dist/browser.js +12 -13
  11. package/dist/{capability-error-CuI_F7yM.d.ts → capability-error-db7kO8-P.d.ts} +2 -1
  12. package/dist/{catalog-CbiftcxQ.d.ts → catalog-Cf3fHDNn.d.ts} +69 -3
  13. package/dist/{chunk-5DZNMLDM.js → chunk-2A3BJ262.js} +2 -2
  14. package/dist/{chunk-BQXRCJ3N.js → chunk-5RLIPTL7.js} +1 -1
  15. package/dist/{chunk-MVQQDPQX.js → chunk-AZDZEQFK.js} +14 -2
  16. package/dist/{chunk-JK3XV2CR.js → chunk-BRROI4CH.js} +50 -8
  17. package/dist/{chunk-P33ZAJMS.js → chunk-CQVKOD3B.js} +1266 -677
  18. package/dist/{chunk-QYC3CZVD.js → chunk-CZ23KRVK.js} +2 -2
  19. package/dist/{chunk-X3FMVRMM.js → chunk-DIXYVGXO.js} +1 -1
  20. package/dist/{chunk-RDUSFUXX.js → chunk-GEVARKEV.js} +9 -1
  21. package/dist/{chunk-2HHZV7U3.js → chunk-LDO5GP7G.js} +1 -1
  22. package/dist/{chunk-Z2Z5DBNW.js → chunk-LGGD7S5T.js} +45 -9
  23. package/dist/{chunk-U66GUVSG.js → chunk-LZXDYSUH.js} +2 -0
  24. package/dist/{chunk-NRMQVK2W.js → chunk-ME2KUAVJ.js} +1 -1
  25. package/dist/{chunk-KUNPCDN6.js → chunk-ODJGTFPY.js} +16 -9
  26. package/dist/{chunk-DSJ46QLB.js → chunk-PO2ZDY27.js} +1 -1
  27. package/dist/{chunk-RWR2LOPA.js → chunk-RKTMSTT7.js} +2 -2
  28. package/dist/{chunk-5SBA6X5X.js → chunk-SWLW4VN3.js} +2 -2
  29. package/dist/{chunk-BMJHFWVT.js → chunk-TCREFRPK.js} +10 -43
  30. package/dist/{chunk-Q5QVAF7R.js → chunk-UGM6DUB2.js} +42 -25
  31. package/dist/chunk-VAGGGB6B.js +87 -0
  32. package/dist/{chunk-FGXLXENM.js → chunk-VNEJH4NT.js} +47 -3
  33. package/dist/chunk-WNEQEDMU.js +427 -0
  34. package/dist/{chunk-Q6KTTVOI.js → chunk-WVK3G2J2.js} +1 -1
  35. package/dist/{client-CZPewB9h.d.ts → client-6eSYOl8h.d.ts} +159 -11
  36. package/dist/{dashboards-jGPM3AxF.d.ts → dashboards-DCOAXL54.d.ts} +6 -5
  37. package/dist/{deployments-BVFd7ddA.d.ts → deployments-BIfdCMd5.d.ts} +911 -309
  38. package/dist/{host-environment-FN4zg3hw.d.ts → host-environment-DUw5-Cvj.d.ts} +2 -1
  39. package/dist/{identity-integration-W1Vo3Ql9.d.ts → identity-integration-BlfOn8rc.d.ts} +3 -2
  40. package/dist/index.d.ts +16 -15
  41. package/dist/index.js +10 -10
  42. package/dist/internal.d.ts +155 -17
  43. package/dist/internal.js +266 -19
  44. package/dist/{limits-C4RzrOV4.d.ts → limits-Ctaeq23J.d.ts} +8 -2
  45. package/dist/{offers-BpYenB9i.d.ts → offers-COqHGbHm.d.ts} +4 -3
  46. package/dist/{participant-activity-DXRq4s6K.d.ts → participant-activity-BznrcePT.d.ts} +2 -1
  47. package/dist/{participant-rewards-BcWkBRn_.d.ts → participant-rewards-s5Gn23qb.d.ts} +23 -1
  48. package/dist/portal-proxy.d.ts +7 -4
  49. package/dist/portal-proxy.js +14 -18
  50. package/dist/profiles-CLDKZVFx.d.ts +370 -0
  51. package/dist/react/index.d.ts +71 -30
  52. package/dist/react/index.js +12 -13
  53. package/dist/{request-error-D_dUPLwo.d.ts → request-error-C24SY7n9.d.ts} +2 -1
  54. package/dist/{reward-deliveries-BOWpMytr.d.ts → reward-deliveries-DFhYGJdx.d.ts} +3 -2
  55. package/dist/runtime/authoring.js +1 -1
  56. package/dist/runtime/chunks/HKAI5OQA.js +1 -0
  57. package/dist/runtime/manifest.json +3 -3
  58. package/dist/runtime/schema.js +1 -1
  59. package/dist/schema.d.ts +556 -180
  60. package/dist/schema.js +70 -8
  61. package/dist/server/index.d.ts +15 -14
  62. package/dist/server/index.js +2053 -893
  63. package/dist/{sign-in-providers-BRYVOSlG.d.ts → sign-in-providers-C97mRNbG.d.ts} +4 -3
  64. package/dist/solana.d.ts +287 -0
  65. package/dist/solana.js +699 -0
  66. package/dist/{streaks-0YuipsUQ.d.ts → streaks-MAqKHbHC.d.ts} +2 -1
  67. package/dist/{submission-input-C152xIdn.d.ts → submission-input-BD7nORuh.d.ts} +4 -3
  68. package/dist/{telegram-browser-657QqiQl.d.ts → telegram-browser-gRMgGs7B.d.ts} +8 -109
  69. package/dist/telegram.d.ts +14 -12
  70. package/dist/telegram.js +2 -2
  71. package/dist/testing.d.ts +99 -18
  72. package/dist/testing.js +101 -11
  73. package/dist/{tracker-data-BqY-9Vu-.d.ts → tracker-data-DQgX3FIc.d.ts} +493 -1
  74. package/dist/{transport-CthYgZXK.d.ts → transport-BLU8jrhg.d.ts} +7340 -2134
  75. package/dist/vite.d.ts +2 -1
  76. package/dist/{wallet-Btng186v.d.ts → wallet-CPAjrW4k.d.ts} +339 -308
  77. package/dist/wallet-browser-BzPt_Qb5.d.ts +107 -0
  78. package/package.json +21 -3
  79. package/dist/chunk-UWUS4OOV.js +0 -59
  80. package/dist/chunk-UYVJZR33.js +0 -34
  81. package/dist/runtime/chunks/C2MGLQXC.js +0 -1
package/dist/solana.js ADDED
@@ -0,0 +1,699 @@
1
+ import {
2
+ maxCompletionReceipts,
3
+ walletLinkedEventDataSchema
4
+ } from "./chunk-WNEQEDMU.js";
5
+ import "./chunk-ODJGTFPY.js";
6
+ import "./chunk-DIXYVGXO.js";
7
+ import "./chunk-CZ23KRVK.js";
8
+ import "./chunk-MWMCQLCG.js";
9
+ import "./chunk-ME2KUAVJ.js";
10
+ import "./chunk-PO2ZDY27.js";
11
+ import "./chunk-2A3BJ262.js";
12
+ import {
13
+ paginate,
14
+ solanaDevnet,
15
+ solanaMainnet,
16
+ solanaMemoProgram
17
+ } from "./chunk-CQVKOD3B.js";
18
+ import "./chunk-VNEJH4NT.js";
19
+
20
+ // src/solana.ts
21
+ import {
22
+ address as address3,
23
+ generateKeyPairSigner as generateKeyPairSigner2
24
+ } from "@solana/kit";
25
+ import {
26
+ TOKEN_2022_PROGRAM_ADDRESS,
27
+ extension,
28
+ fetchMint,
29
+ findAssociatedTokenPda,
30
+ getCreateMintInstructionPlan,
31
+ getMintToATAInstructionPlan
32
+ } from "@solana-program/token-2022";
33
+
34
+ // src/solana-badge-transactions.ts
35
+ import {
36
+ appendTransactionMessageInstructions,
37
+ createTransactionMessage,
38
+ flattenInstructionPlan,
39
+ getBase64EncodedWireTransaction,
40
+ getSignatureFromTransaction,
41
+ pipe,
42
+ setTransactionMessageFeePayerSigner,
43
+ setTransactionMessageLifetimeUsingBlockhash,
44
+ signTransactionMessageWithSigners,
45
+ address
46
+ } from "@solana/kit";
47
+ var memoInstruction = (memo) => ({
48
+ programAddress: address(solanaMemoProgram),
49
+ data: new TextEncoder().encode(memo)
50
+ });
51
+ var instructions = (plan) => flattenInstructionPlan(plan).map((step) => {
52
+ if (step.kind !== "single") {
53
+ throw new Error("Expected a plan of single instructions");
54
+ }
55
+ return step.instruction;
56
+ });
57
+ async function sign(rpc, feePayer, steps) {
58
+ const { value: blockhash } = await rpc.getLatestBlockhash({ commitment: "confirmed" }).send();
59
+ const transaction = await signTransactionMessageWithSigners(
60
+ pipe(
61
+ createTransactionMessage({ version: 0 }),
62
+ (message) => setTransactionMessageFeePayerSigner(feePayer, message),
63
+ (message) => setTransactionMessageLifetimeUsingBlockhash(blockhash, message),
64
+ (message) => appendTransactionMessageInstructions(steps, message)
65
+ )
66
+ );
67
+ return {
68
+ wire: getBase64EncodedWireTransaction(transaction),
69
+ signature: getSignatureFromTransaction(transaction),
70
+ lastValidBlockHeight: blockhash.lastValidBlockHeight
71
+ };
72
+ }
73
+ async function sendAndConfirm(rpc, transaction) {
74
+ try {
75
+ await rpc.sendTransaction(transaction.wire, {
76
+ encoding: "base64",
77
+ preflightCommitment: "confirmed"
78
+ }).send();
79
+ } catch (error) {
80
+ const {
81
+ value: [status]
82
+ } = await rpc.getSignatureStatuses([transaction.signature]).send();
83
+ if (!status) {
84
+ throw error;
85
+ }
86
+ }
87
+ await confirmed(rpc, transaction.signature, transaction.lastValidBlockHeight);
88
+ return transaction.signature;
89
+ }
90
+ async function confirmed(rpc, signature, lastValidBlockHeight) {
91
+ for (; ; ) {
92
+ const {
93
+ value: [status]
94
+ } = await rpc.getSignatureStatuses([signature]).send();
95
+ if (status?.err) {
96
+ throw new Error(
97
+ `Transaction ${signature} failed: ${JSON.stringify(status.err, (_, value) => typeof value === "bigint" ? String(value) : value)}`
98
+ );
99
+ }
100
+ if (status?.confirmationStatus === "confirmed" || status?.confirmationStatus === "finalized") {
101
+ return;
102
+ }
103
+ if (await rpc.getBlockHeight({ commitment: "confirmed" }).send() > lastValidBlockHeight) {
104
+ throw new Error(
105
+ `Transaction ${signature} was not confirmed before its blockhash expired`
106
+ );
107
+ }
108
+ await new Promise((resolve) => setTimeout(resolve, 500));
109
+ }
110
+ }
111
+
112
+ // src/solana-compressed-badges.ts
113
+ import {
114
+ AccountRole,
115
+ addEncoderSizePrefix,
116
+ getAddressDecoder,
117
+ getAddressEncoder,
118
+ getArrayEncoder,
119
+ getBase58Encoder,
120
+ getBooleanEncoder,
121
+ getBytesEncoder,
122
+ fixEncoderSize,
123
+ getNullableEncoder,
124
+ getProgramDerivedAddress,
125
+ getStructEncoder,
126
+ getU16Encoder,
127
+ getU32Encoder,
128
+ getU64Decoder,
129
+ getU64Encoder,
130
+ getU8Encoder,
131
+ getUtf8Encoder,
132
+ address as address2,
133
+ decimalFixedPointToString,
134
+ fetchEncodedAccount,
135
+ generateKeyPairSigner,
136
+ lamports as toLamports,
137
+ lamportsToSol
138
+ } from "@solana/kit";
139
+ var bubblegumProgram = /* @__PURE__ */ (() => address2("BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY"))();
140
+ var coreProgram = /* @__PURE__ */ (() => address2("CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d"))();
141
+ var compressionProgram = /* @__PURE__ */ (() => address2(
142
+ "mcmt6YrQEMKw8Mw43FmpRLmf7BqRnFMKmAcbxE3xkAW"
143
+ ))();
144
+ var noopProgram = /* @__PURE__ */ (() => address2("mnoopTCrg4p8ry25e4bcWA9XZjbNjMTfgYVGGEdRsf3"))();
145
+ var systemProgram = /* @__PURE__ */ (() => address2("11111111111111111111111111111111"))();
146
+ var coreCpiSigner = /* @__PURE__ */ (() => address2("CbNY3JiXdXNE9tPNEk1aRZVEkWdj2v7kfJLNQwZZgpXk"))();
147
+ var string = () => addEncoderSizePrefix(getUtf8Encoder(), getU32Encoder());
148
+ var treeVersion2 = 1;
149
+ var coreCollectionKey = 5;
150
+ var discriminator = () => fixEncoderSize(getBytesEncoder(), 8);
151
+ var readonly = (account) => ({
152
+ address: account,
153
+ role: AccountRole.READONLY
154
+ });
155
+ var writable = (account) => ({
156
+ address: account,
157
+ role: AccountRole.WRITABLE
158
+ });
159
+ var signing = (signer, role) => ({
160
+ address: signer.address,
161
+ role,
162
+ signer
163
+ });
164
+ var treeConfigAddress = async (tree) => (await getProgramDerivedAddress({
165
+ programAddress: bubblegumProgram,
166
+ seeds: [getAddressEncoder().encode(tree)]
167
+ }))[0];
168
+ var mintV2Data = /* @__PURE__ */ (() => getStructEncoder([
169
+ ["discriminator", discriminator()],
170
+ ["name", string()],
171
+ ["symbol", string()],
172
+ ["uri", string()],
173
+ ["sellerFeeBasisPoints", getU16Encoder()],
174
+ ["primarySaleHappened", getBooleanEncoder()],
175
+ ["isMutable", getBooleanEncoder()],
176
+ ["tokenStandard", getNullableEncoder(getU8Encoder())],
177
+ ["creators", getArrayEncoder(getU8Encoder())],
178
+ ["collection", getNullableEncoder(getAddressEncoder())],
179
+ ["assetData", getNullableEncoder(getU8Encoder())],
180
+ ["assetDataSchema", getNullableEncoder(getU8Encoder())]
181
+ ]))();
182
+ async function mintV2(badge, authority, owner) {
183
+ const tree = address2(badge.tree);
184
+ const collection = address2(badge.collection);
185
+ return {
186
+ programAddress: bubblegumProgram,
187
+ accounts: [
188
+ writable(await treeConfigAddress(tree)),
189
+ signing(authority, AccountRole.WRITABLE_SIGNER),
190
+ signing(authority, AccountRole.READONLY_SIGNER),
191
+ signing(authority, AccountRole.READONLY_SIGNER),
192
+ readonly(owner),
193
+ readonly(owner),
194
+ writable(tree),
195
+ writable(collection),
196
+ readonly(coreCpiSigner),
197
+ readonly(noopProgram),
198
+ readonly(compressionProgram),
199
+ readonly(coreProgram),
200
+ readonly(systemProgram)
201
+ ],
202
+ data: mintV2Data.encode({
203
+ discriminator: Uint8Array.of(120, 121, 23, 146, 173, 110, 199, 205),
204
+ name: badge.metadata.name,
205
+ symbol: badge.metadata.symbol ?? "",
206
+ uri: badge.metadata.uri,
207
+ // No royalties: badges are not sold.
208
+ sellerFeeBasisPoints: 0,
209
+ primarySaleHappened: false,
210
+ isMutable: true,
211
+ // TokenStandard::NonFungible, the one Bubblegum accepts.
212
+ tokenStandard: 0,
213
+ creators: [],
214
+ collection,
215
+ assetData: null,
216
+ assetDataSchema: null
217
+ })
218
+ };
219
+ }
220
+ async function checkCompressedBadge(rpc, badge, authority) {
221
+ const tree = address2(badge.tree);
222
+ const collection = address2(badge.collection);
223
+ const read = (account) => fetchEncodedAccount(rpc, account, { commitment: "confirmed" });
224
+ const [config, core] = await Promise.all([
225
+ read(await treeConfigAddress(tree)),
226
+ read(collection)
227
+ ]);
228
+ if (!config.exists || config.programAddress !== bubblegumProgram || config.data.length < 91 || config.data[90] !== treeVersion2) {
229
+ throw new Error(`${tree} is not a Bubblegum v2 tree`);
230
+ }
231
+ if (getAddressDecoder().decode(config.data, 8) !== authority && getAddressDecoder().decode(config.data, 40) !== authority && config.data[88] !== 1) {
232
+ throw new Error(
233
+ `${authority} is neither the creator nor the delegate of ${tree}`
234
+ );
235
+ }
236
+ const capacity = getU64Decoder().decode(config.data, 72);
237
+ if (getU64Decoder().decode(config.data, 80) >= capacity) {
238
+ throw new Error(`${tree} is full: it holds ${capacity} badges`);
239
+ }
240
+ if (!core.exists || core.programAddress !== coreProgram || core.data[0] !== coreCollectionKey) {
241
+ throw new Error(`${collection} is not a Core collection`);
242
+ }
243
+ if (getAddressDecoder().decode(core.data, 1) !== authority) {
244
+ throw new Error(`${authority} is not the update authority of ${collection}`);
245
+ }
246
+ }
247
+ function compressedBadgeMinter(input) {
248
+ return {
249
+ async instructions(owner) {
250
+ await checkCompressedBadge(
251
+ input.rpc,
252
+ input.badge,
253
+ input.authority.address
254
+ );
255
+ return [await mintV2(input.badge, input.authority, owner)];
256
+ },
257
+ async asset(signature) {
258
+ for (let read = 1; ; read++) {
259
+ const asset = await mintedAsset(input.rpc, signature);
260
+ if (asset !== null || read === 5) {
261
+ return asset;
262
+ }
263
+ await new Promise((resolve) => setTimeout(resolve, 500));
264
+ }
265
+ }
266
+ };
267
+ }
268
+ async function mintedAsset(rpc, signature) {
269
+ const transaction = await rpc.getTransaction(signature, {
270
+ commitment: "confirmed",
271
+ encoding: "json",
272
+ maxSupportedTransactionVersion: 0
273
+ }).send();
274
+ if (!transaction) {
275
+ return null;
276
+ }
277
+ const keys = transaction.transaction.message.accountKeys;
278
+ const outer = transaction.transaction.message.instructions.findIndex(
279
+ (instruction) => keys[instruction.programIdIndex] === bubblegumProgram
280
+ );
281
+ const logged = transaction.meta?.innerInstructions?.find((group) => group.index === outer)?.instructions.map((instruction) => ({
282
+ program: keys[instruction.programIdIndex],
283
+ data: getBase58Encoder().encode(instruction.data)
284
+ })).find(
285
+ ({ program, data }) => program === noopProgram && data.length >= 41 && data[0] === 1 && data[1] === 0 && data[6] === 1 && data[7] === 1 && data[8] === 1
286
+ );
287
+ if (!logged) {
288
+ throw new Error(`Transaction ${signature} minted no compressed NFT`);
289
+ }
290
+ return getAddressDecoder().decode(logged.data, 9);
291
+ }
292
+ async function createSolanaBadgeTree(input) {
293
+ const { authority, rpc, maxDepth, maxBufferSize } = input;
294
+ const tree = input.tree ?? await generateKeyPairSigner();
295
+ const collection = input.collectionKey ?? await generateKeyPairSigner();
296
+ const soulbound = !input.collection.transferable;
297
+ const treeBytes = merkleTreeSize(maxDepth, maxBufferSize);
298
+ const collectionBytes = coreCollectionSize(input.collection, soulbound);
299
+ const rents = await Promise.all(
300
+ [treeBytes, treeConfigSize, collectionBytes].map(
301
+ (size) => rpc.getMinimumBalanceForRentExemption(BigInt(size)).send()
302
+ )
303
+ );
304
+ const lamports = toLamports(rents.reduce((sum, rent2) => sum + rent2, 0n));
305
+ const rent = {
306
+ lamports,
307
+ sol: decimalFixedPointToString(lamportsToSol(lamports)),
308
+ capacity: 2 ** maxDepth,
309
+ treeBytes
310
+ };
311
+ const confirm = input.confirmRent ?? ((cost) => {
312
+ console.info(
313
+ `Creating a badge tree for ${cost.capacity} badges and its collection costs ${cost.sol} SOL in rent (${cost.lamports} lamports)`
314
+ );
315
+ return true;
316
+ });
317
+ if (!await confirm(rent)) {
318
+ throw new Error("Badge tree creation was not confirmed; nothing was sent");
319
+ }
320
+ const signature = await sendAndConfirm(
321
+ rpc,
322
+ await sign(rpc, authority, [
323
+ createAccount(authority, tree, rents[0], treeBytes, compressionProgram),
324
+ await createTreeV2(authority, tree.address, maxDepth, maxBufferSize),
325
+ createCollectionV2(authority, collection, input.collection, soulbound)
326
+ ])
327
+ );
328
+ return { tree: tree.address, collection: collection.address, signature };
329
+ }
330
+ var merkleTreeSize = (maxDepth, maxBufferSize) => 1 + (1 + 4 + 4 + 32 + 8 + 1 + 5) + 8 * 3 + maxBufferSize * (32 + 32 * maxDepth + 8) + (32 * maxDepth + 32 + 8);
331
+ var treeConfigSize = 8 + 32 + 32 + 8 + 8 + 1 + 1 + 1 + 5;
332
+ var coreCollectionSize = (collection, soulbound) => {
333
+ const utf8 = (text) => new TextEncoder().encode(text).length;
334
+ const base = 1 + 32 + 4 + utf8(collection.name) + 4 + utf8(collection.uri) + 8;
335
+ let plugins = 1;
336
+ let records = 1 + 33 + 8;
337
+ if (soulbound) {
338
+ plugins += 1 + 1;
339
+ records += 1 + 1 + 8;
340
+ }
341
+ return base + (1 + 8) + plugins + (1 + 4 + records + 4);
342
+ };
343
+ function createAccount(payer, account, lamports, space, owner) {
344
+ return {
345
+ programAddress: systemProgram,
346
+ accounts: [
347
+ signing(payer, AccountRole.WRITABLE_SIGNER),
348
+ signing(account, AccountRole.WRITABLE_SIGNER)
349
+ ],
350
+ data: getStructEncoder([
351
+ ["instruction", getU32Encoder()],
352
+ ["lamports", getU64Encoder()],
353
+ ["space", getU64Encoder()],
354
+ ["owner", getAddressEncoder()]
355
+ ]).encode({ instruction: 0, lamports, space, owner })
356
+ };
357
+ }
358
+ async function createTreeV2(authority, tree, maxDepth, maxBufferSize) {
359
+ return {
360
+ programAddress: bubblegumProgram,
361
+ accounts: [
362
+ writable(await treeConfigAddress(tree)),
363
+ writable(tree),
364
+ signing(authority, AccountRole.WRITABLE_SIGNER),
365
+ signing(authority, AccountRole.READONLY_SIGNER),
366
+ readonly(noopProgram),
367
+ readonly(compressionProgram),
368
+ readonly(systemProgram)
369
+ ],
370
+ data: getStructEncoder([
371
+ ["discriminator", discriminator()],
372
+ ["maxDepth", getU32Encoder()],
373
+ ["maxBufferSize", getU32Encoder()],
374
+ ["public", getNullableEncoder(getBooleanEncoder())]
375
+ ]).encode({
376
+ discriminator: Uint8Array.of(55, 99, 95, 215, 142, 203, 227, 205),
377
+ maxDepth,
378
+ maxBufferSize,
379
+ public: false
380
+ })
381
+ };
382
+ }
383
+ var corePlugin = { permanentFreezeDelegate: 5, bubblegumV2: 15 };
384
+ var corePluginAuthority = { none: 0 };
385
+ function createCollectionV2(authority, collection, details, soulbound) {
386
+ const plugins = [
387
+ Uint8Array.of(corePlugin.bubblegumV2, 0),
388
+ ...soulbound ? [
389
+ Uint8Array.of(
390
+ corePlugin.permanentFreezeDelegate,
391
+ 1,
392
+ // frozen
393
+ 1,
394
+ // Some(
395
+ corePluginAuthority.none
396
+ )
397
+ ] : []
398
+ ];
399
+ return {
400
+ programAddress: coreProgram,
401
+ accounts: [
402
+ signing(collection, AccountRole.WRITABLE_SIGNER),
403
+ readonly(authority.address),
404
+ signing(authority, AccountRole.WRITABLE_SIGNER),
405
+ readonly(systemProgram)
406
+ ],
407
+ data: getStructEncoder([
408
+ ["instruction", getU8Encoder()],
409
+ ["name", string()],
410
+ ["uri", string()],
411
+ ["plugins", getNullableEncoder(getArrayEncoder(getBytesEncoder()))],
412
+ [
413
+ "externalPluginAdapters",
414
+ getNullableEncoder(getArrayEncoder(getU8Encoder()))
415
+ ]
416
+ ]).encode({
417
+ instruction: 21,
418
+ name: details.name,
419
+ uri: details.uri,
420
+ plugins,
421
+ externalPluginAdapters: []
422
+ })
423
+ };
424
+ }
425
+
426
+ // src/solana.ts
427
+ var solanaBadgeReceiptKey = "badge";
428
+ async function awardSolanaBadge(input) {
429
+ const completion = questCompletion(input.event);
430
+ if (!completion || input.quests && !input.quests.includes(completion.quest)) {
431
+ return { status: "ignored" };
432
+ }
433
+ return awardCompletion(input, completion, badgeLookups(input));
434
+ }
435
+ async function awardOwedSolanaBadges(input) {
436
+ const { event, management } = input;
437
+ const linked = event.type === "wallet.linked" ? walletLinkedEventDataSchema.safeParse(event.data) : void 0;
438
+ if (!linked?.success || linked.data.chain !== "solana") {
439
+ return { status: "ignored" };
440
+ }
441
+ const { member } = linked.data;
442
+ const lookups = badgeLookups(input);
443
+ const awards = [];
444
+ for (const quest of input.quests ?? [void 0]) {
445
+ for await (const completion of paginate(
446
+ (cursor) => management.completions.list({ member, quest, cursor, limit: 100 })
447
+ )) {
448
+ if (completion.source?.kind !== "quest") {
449
+ continue;
450
+ }
451
+ awards.push({
452
+ completion: completion.id,
453
+ quest: completion.quest,
454
+ award: await awardCompletion(
455
+ input,
456
+ { id: completion.id, quest: completion.quest, member },
457
+ lookups
458
+ )
459
+ });
460
+ }
461
+ }
462
+ return { status: "awarded", awards };
463
+ }
464
+ function badgeLookups(input) {
465
+ const once = (read) => {
466
+ let value;
467
+ return () => value ??= read();
468
+ };
469
+ const wallets = /* @__PURE__ */ new Map();
470
+ return {
471
+ wallet(member) {
472
+ if (!wallets.has(member)) {
473
+ wallets.set(
474
+ member,
475
+ once(() => provenSolanaWallet(input.management, member))
476
+ );
477
+ }
478
+ return wallets.get(member)();
479
+ },
480
+ minter: input.badge ? compressedBadgeMinter({ ...input, badge: input.badge }) : tokenBadgeMinter(input, address3(input.mint))
481
+ };
482
+ }
483
+ function tokenBadgeMinter(input, mint) {
484
+ let decimals;
485
+ return {
486
+ async instructions(owner) {
487
+ decimals ??= badgeDecimals(input.rpc, mint, input.authority.address);
488
+ const [token] = await findAssociatedTokenPda({
489
+ owner,
490
+ mint,
491
+ tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
492
+ });
493
+ return instructions(
494
+ getMintToATAInstructionPlan({
495
+ payer: input.authority,
496
+ ata: token,
497
+ owner,
498
+ mint,
499
+ mintAuthority: input.authority,
500
+ amount: 1n,
501
+ decimals: await decimals
502
+ })
503
+ );
504
+ },
505
+ asset: async () => mint
506
+ };
507
+ }
508
+ async function awardCompletion(input, completion, lookups) {
509
+ const { management, rpc, authority } = input;
510
+ let receipts = await management.completions.receipts(completion.id);
511
+ const existing = receipts.find(
512
+ (receipt) => receipt.key === solanaBadgeReceiptKey
513
+ );
514
+ if (existing) {
515
+ return { status: "already-minted", receipt: existing };
516
+ }
517
+ const record = async (attempt2) => {
518
+ const asset = await lookups.minter.asset(attempt2.signature);
519
+ if (asset === null) {
520
+ throw new SolanaBadgePendingError(attempt2.signature);
521
+ }
522
+ return management.completions.recordReceipt(completion.id, {
523
+ key: solanaBadgeReceiptKey,
524
+ network: attempt2.network,
525
+ signature: attempt2.signature,
526
+ asset,
527
+ ...attempt2.recipient === null ? {} : { recipient: attempt2.recipient },
528
+ ...input.label === void 0 ? {} : { label: input.label }
529
+ });
530
+ };
531
+ const settled = async () => {
532
+ const attempt2 = latestAttempt(receipts);
533
+ const outcome = attempt2 && await attemptOutcome(rpc, attempt2);
534
+ if (outcome === "landed") {
535
+ return { status: "minted", receipt: await record(attempt2) };
536
+ }
537
+ if (outcome === "pending") {
538
+ throw new SolanaBadgePendingError(attempt2.signature);
539
+ }
540
+ return attempt2 ? attemptNumber(attempt2.key) + 1 : 1;
541
+ };
542
+ const next = await settled();
543
+ if (typeof next !== "number") {
544
+ return next;
545
+ }
546
+ if (receipts.length >= maxCompletionReceipts - 1) {
547
+ throw new Error(
548
+ `Completion ${completion.id} holds ${receipts.length} receipts, leaving no room for another badge attempt and the badge`
549
+ );
550
+ }
551
+ const wallet = await lookups.wallet(completion.member);
552
+ if (!wallet) {
553
+ return { status: input.whenNoWallet === "defer" ? "deferred" : "no-wallet" };
554
+ }
555
+ const owner = address3(wallet);
556
+ const transaction = await sign(rpc, authority, [
557
+ ...await lookups.minter.instructions(owner),
558
+ memoInstruction(solanaBadgeMemo(completion.id))
559
+ ]);
560
+ let attempt;
561
+ try {
562
+ attempt = await management.completions.recordReceipt(completion.id, {
563
+ key: `${attemptPrefix}${next}`,
564
+ network: input.network,
565
+ signature: transaction.signature,
566
+ // A compressed badge's asset ID is known once its mint lands.
567
+ ...input.mint === void 0 ? {} : { asset: input.mint },
568
+ recipient: owner,
569
+ label: `Badge mint, valid through block height ${transaction.lastValidBlockHeight}`
570
+ });
571
+ } catch (error) {
572
+ if (error.code !== "receipt-conflict") {
573
+ throw error;
574
+ }
575
+ receipts = await management.completions.receipts(completion.id);
576
+ const answer = await settled();
577
+ if (typeof answer !== "number") {
578
+ return answer;
579
+ }
580
+ throw error;
581
+ }
582
+ await sendAndConfirm(rpc, transaction);
583
+ return { status: "minted", receipt: await record(attempt) };
584
+ }
585
+ var SolanaBadgePendingError = class extends Error {
586
+ constructor(signature) {
587
+ super(
588
+ `The badge transaction ${signature} for this completion is still confirming; try again later`
589
+ );
590
+ this.signature = signature;
591
+ this.name = "SolanaBadgePendingError";
592
+ }
593
+ signature;
594
+ code = "badge-pending";
595
+ };
596
+ async function createSolanaBadgeMint(input) {
597
+ const { authority, rpc } = input;
598
+ const mint = input.mint ?? await generateKeyPairSigner2();
599
+ const plan = await getCreateMintInstructionPlan(
600
+ {
601
+ getMinimumBalance: async (space) => rpc.getMinimumBalanceForRentExemption(BigInt(space)).send()
602
+ },
603
+ {
604
+ payer: authority,
605
+ newMint: mint,
606
+ decimals: 0,
607
+ mintAuthority: authority,
608
+ extensions: [
609
+ extension("NonTransferable", {}),
610
+ extension("MetadataPointer", {
611
+ authority: authority.address,
612
+ metadataAddress: mint.address
613
+ }),
614
+ extension("TokenMetadata", {
615
+ updateAuthority: authority.address,
616
+ mint: mint.address,
617
+ name: input.name,
618
+ symbol: input.symbol,
619
+ uri: input.uri,
620
+ additionalMetadata: /* @__PURE__ */ new Map()
621
+ })
622
+ ]
623
+ }
624
+ );
625
+ const signature = await sendAndConfirm(
626
+ rpc,
627
+ await sign(rpc, authority, instructions(plan))
628
+ );
629
+ return { mint: mint.address, signature };
630
+ }
631
+ var solanaBadgeMemo = (completion) => `domino-badge:${completion}`;
632
+ function questCompletion(event) {
633
+ const { data } = event;
634
+ const source = data.source;
635
+ const fromQuest = source === void 0 ? typeof data.attempt === "string" : source?.kind === "quest";
636
+ if (event.type !== "completion.created" || !fromQuest || typeof data.completion !== "string" || typeof data.quest !== "string" || typeof data.member !== "string") {
637
+ return null;
638
+ }
639
+ return { id: data.completion, quest: data.quest, member: data.member };
640
+ }
641
+ async function provenSolanaWallet(management, member) {
642
+ let newest;
643
+ for await (const identity of paginate(
644
+ (cursor) => management.members.identityStates.list(member, { cursor, limit: 100 })
645
+ )) {
646
+ if (identity.kind !== "wallet" || identity.chain !== "solana" || !identity.linked || identity.source === "import") {
647
+ continue;
648
+ }
649
+ const candidate = {
650
+ address: identity.address,
651
+ linkedAt: identity.linkedAt ?? -1,
652
+ revision: identity.revision
653
+ };
654
+ if (!newest || candidate.linkedAt > newest.linkedAt || candidate.linkedAt === newest.linkedAt && candidate.revision > newest.revision) {
655
+ newest = candidate;
656
+ }
657
+ }
658
+ return newest?.address;
659
+ }
660
+ async function badgeDecimals(rpc, mint, authority) {
661
+ const account = await fetchMint(rpc, mint, { commitment: "confirmed" });
662
+ if (account.programAddress !== TOKEN_2022_PROGRAM_ADDRESS) {
663
+ throw new Error(`${mint} is not a Token-2022 mint`);
664
+ }
665
+ const mintAuthority = account.data.mintAuthority;
666
+ if (mintAuthority.__option === "None" || mintAuthority.value !== authority) {
667
+ throw new Error(`${authority} is not the mint authority of ${mint}`);
668
+ }
669
+ return account.data.decimals;
670
+ }
671
+ var attemptPrefix = "badge-attempt-";
672
+ var attemptNumber = (key) => Number(key.slice(attemptPrefix.length));
673
+ function latestAttempt(receipts) {
674
+ return receipts.filter((receipt) => /^badge-attempt-[1-9][0-9]*$/.test(receipt.key)).sort((a, b) => attemptNumber(b.key) - attemptNumber(a.key))[0];
675
+ }
676
+ async function attemptOutcome(rpc, attempt) {
677
+ const lastValid = attempt.label?.match(/block height (\d+)$/)?.[1];
678
+ const height = await rpc.getBlockHeight({ commitment: "finalized" }).send();
679
+ const {
680
+ value: [status]
681
+ } = await rpc.getSignatureStatuses([attempt.signature], {
682
+ searchTransactionHistory: true
683
+ }).send();
684
+ if (status?.confirmationStatus === "confirmed" || status?.confirmationStatus === "finalized") {
685
+ return status.err ? "failed" : "landed";
686
+ }
687
+ return lastValid === void 0 || height > BigInt(lastValid) ? "expired" : "pending";
688
+ }
689
+ export {
690
+ SolanaBadgePendingError,
691
+ awardOwedSolanaBadges,
692
+ awardSolanaBadge,
693
+ createSolanaBadgeMint,
694
+ createSolanaBadgeTree,
695
+ solanaBadgeMemo,
696
+ solanaBadgeReceiptKey,
697
+ solanaDevnet,
698
+ solanaMainnet
699
+ };
@@ -68,4 +68,5 @@ declare const streakProgressSchema: z.ZodObject<{
68
68
  }, z.core.$strip>;
69
69
  type StreakProgress = z.infer<typeof streakProgressSchema>;
70
70
 
71
- export { type QuizContent as Q, type StreakProgress as S, type StreakPolicy as a, quizContentSchema as b, quizQuestionSchema as c, quizQuestionsSchema as d, streakProgressSchema as e, quizChoiceSchema as q, streakPolicySchema as s };
71
+ export { quizContentSchema as b, quizQuestionSchema as c, quizQuestionsSchema as d, streakProgressSchema as e, quizChoiceSchema as q, streakPolicySchema as s };
72
+ export type { QuizContent as Q, StreakProgress as S, StreakPolicy as a };