@domino-sdk/relay 1.67.0 → 1.68.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/dist/{accounts-C2O8mpB8.d.ts → accounts-DnpKoJCo.d.ts} +210 -3
- package/dist/{attempt-captures-ClHAoo_n.d.ts → attempt-captures-DMNFMYFb.d.ts} +9 -1
- package/dist/authoring.d.ts +349 -38
- package/dist/authoring.js +125 -18
- package/dist/{automatic-outcomes-BEnPn4Uh.d.ts → automatic-outcomes-CQ3vpiQl.d.ts} +2 -2
- package/dist/avatar.d.ts +1 -1
- package/dist/browser.d.ts +10 -9
- package/dist/browser.js +12 -13
- package/dist/{catalog-CbiftcxQ.d.ts → catalog-BLGie8Lh.d.ts} +60 -2
- package/dist/chunk-4JSPMFO2.js +427 -0
- package/dist/{chunk-5DZNMLDM.js → chunk-55WJVFWC.js} +2 -2
- package/dist/{chunk-Q5QVAF7R.js → chunk-5AKD4ZF3.js} +37 -25
- package/dist/{chunk-DSJ46QLB.js → chunk-6UBFSMCM.js} +1 -1
- package/dist/{chunk-P33ZAJMS.js → chunk-6YTSRWRB.js} +1199 -677
- package/dist/{chunk-RDUSFUXX.js → chunk-75KF633N.js} +9 -1
- package/dist/{chunk-Q6KTTVOI.js → chunk-7YSVZA7A.js} +1 -1
- package/dist/{chunk-BMJHFWVT.js → chunk-CZ7NQ7W7.js} +10 -43
- package/dist/{chunk-X3FMVRMM.js → chunk-DDJN2T5A.js} +1 -1
- package/dist/{chunk-KUNPCDN6.js → chunk-DNPDR4Z7.js} +16 -9
- package/dist/{chunk-RWR2LOPA.js → chunk-EXZVWQOQ.js} +2 -2
- package/dist/{chunk-MVQQDPQX.js → chunk-HXTKI34N.js} +14 -2
- package/dist/{chunk-FGXLXENM.js → chunk-IW46TW3A.js} +21 -1
- package/dist/{chunk-5SBA6X5X.js → chunk-KKHENO57.js} +2 -2
- package/dist/{chunk-U66GUVSG.js → chunk-LZXDYSUH.js} +2 -0
- package/dist/{chunk-QYC3CZVD.js → chunk-MEUAJIVO.js} +2 -2
- package/dist/{chunk-BQXRCJ3N.js → chunk-P4TPW4SY.js} +1 -1
- package/dist/{chunk-NRMQVK2W.js → chunk-R3MNZKNJ.js} +1 -1
- package/dist/{chunk-Z2Z5DBNW.js → chunk-SD74HD75.js} +45 -9
- package/dist/{chunk-JK3XV2CR.js → chunk-TYZFVL73.js} +50 -8
- package/dist/chunk-VAGGGB6B.js +87 -0
- package/dist/{chunk-2HHZV7U3.js → chunk-VRZZB7CQ.js} +1 -1
- package/dist/{client-CZPewB9h.d.ts → client-BMif22WQ.d.ts} +133 -7
- package/dist/{dashboards-jGPM3AxF.d.ts → dashboards-DMk-vL1q.d.ts} +4 -4
- package/dist/{deployments-BVFd7ddA.d.ts → deployments-BCr418BX.d.ts} +582 -173
- package/dist/{identity-integration-W1Vo3Ql9.d.ts → identity-integration-r76xaAax.d.ts} +1 -1
- package/dist/index.d.ts +10 -10
- package/dist/index.js +10 -10
- package/dist/internal.d.ts +137 -14
- package/dist/internal.js +240 -19
- package/dist/{limits-C4RzrOV4.d.ts → limits-ByVRQePO.d.ts} +6 -1
- package/dist/{offers-BpYenB9i.d.ts → offers-xcPbYaEv.d.ts} +2 -2
- package/dist/portal-proxy.d.ts +2 -2
- package/dist/portal-proxy.js +11 -11
- package/dist/react/index.d.ts +37 -15
- package/dist/react/index.js +12 -13
- package/dist/{reward-deliveries-BOWpMytr.d.ts → reward-deliveries-0VvT6LMj.d.ts} +1 -1
- package/dist/runtime/authoring.js +1 -1
- package/dist/runtime/chunks/2UDZ6TPL.js +1 -0
- package/dist/runtime/manifest.json +3 -3
- package/dist/runtime/schema.js +1 -1
- package/dist/schema.d.ts +398 -104
- package/dist/schema.js +62 -8
- package/dist/server/index.d.ts +12 -12
- package/dist/server/index.js +2046 -886
- package/dist/{sign-in-providers-BRYVOSlG.d.ts → sign-in-providers-C5_753DZ.d.ts} +2 -2
- package/dist/solana.d.ts +171 -0
- package/dist/solana.js +364 -0
- package/dist/{submission-input-C152xIdn.d.ts → submission-input-CaL8drIh.d.ts} +2 -2
- package/dist/{telegram-browser-657QqiQl.d.ts → telegram-browser-DLtHPRBI.d.ts} +6 -108
- package/dist/telegram.d.ts +8 -8
- package/dist/telegram.js +2 -2
- package/dist/testing.d.ts +85 -13
- package/dist/testing.js +101 -11
- package/dist/{tracker-data-BqY-9Vu-.d.ts → tracker-data-CAK942sx.d.ts} +298 -1
- package/dist/{transport-CthYgZXK.d.ts → transport-CkidqTOk.d.ts} +5250 -1226
- package/dist/{wallet-Btng186v.d.ts → wallet-DQtJelQQ.d.ts} +367 -13
- package/dist/wallet-browser-dpmr22Xv.d.ts +106 -0
- package/package.json +16 -1
- package/dist/chunk-UWUS4OOV.js +0 -59
- package/dist/chunk-UYVJZR33.js +0 -34
- package/dist/runtime/chunks/C2MGLQXC.js +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { J as SignInProvider } from './accounts-
|
|
1
|
+
import { J as SignInProvider } from './accounts-DnpKoJCo.js';
|
|
2
2
|
import * as z from 'zod';
|
|
3
|
-
import { a as TelegramSignInMethods } from './submission-input-
|
|
3
|
+
import { a as TelegramSignInMethods } from './submission-input-CaL8drIh.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* `GET /v1/auth/providers`, as `relay.auth.providers()` reads it. Exported as a schema only, for the
|
package/dist/solana.d.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { TransactionSigner, Rpc, GetAccountInfoApi, GetBlockHeightApi, GetLatestBlockhashApi, GetMinimumBalanceForRentExemptionApi, GetSignatureStatusesApi, SendTransactionApi, KeyPairSigner, Address, Signature } from '@solana/kit';
|
|
2
|
+
import { S as SolanaNetwork } from './wallet-DQtJelQQ.js';
|
|
3
|
+
export { s as solanaDevnet, t as solanaMainnet } from './wallet-DQtJelQQ.js';
|
|
4
|
+
import { M as ManagementClient, W as WebhookEvent, C as CompletionReceipt } from './transport-CkidqTOk.js';
|
|
5
|
+
import 'zod';
|
|
6
|
+
import './accounts-DnpKoJCo.js';
|
|
7
|
+
import './tracker-data-CAK942sx.js';
|
|
8
|
+
import './identity-integration-r76xaAax.js';
|
|
9
|
+
import './reward-deliveries-0VvT6LMj.js';
|
|
10
|
+
import './request-error-D_dUPLwo.js';
|
|
11
|
+
import './action-9Xl0StBg.js';
|
|
12
|
+
import './limits-ByVRQePO.js';
|
|
13
|
+
import './automatic-outcomes-CQ3vpiQl.js';
|
|
14
|
+
import './deployments-BCr418BX.js';
|
|
15
|
+
import './offers-xcPbYaEv.js';
|
|
16
|
+
import './catalog-BLGie8Lh.js';
|
|
17
|
+
import './attempt-captures-DMNFMYFb.js';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The RPC methods the badge helpers call. `createSolanaRpc(url)` from `@solana/kit` answers all of
|
|
21
|
+
* them.
|
|
22
|
+
*/
|
|
23
|
+
type SolanaBadgeRpc = Rpc<GetAccountInfoApi & GetBlockHeightApi & GetLatestBlockhashApi & GetMinimumBalanceForRentExemptionApi & GetSignatureStatusesApi & SendTransactionApi>;
|
|
24
|
+
/** The receipt key `awardSolanaBadge` records a badge under. */
|
|
25
|
+
declare const solanaBadgeReceiptKey = "badge";
|
|
26
|
+
/**
|
|
27
|
+
* What `awardSolanaBadge` did. `minted` and `already-minted` carry the completion's badge
|
|
28
|
+
* receipt; `no-wallet` means the member has no proven Solana wallet, and nothing was sent;
|
|
29
|
+
* `deferred` is `no-wallet` under `whenNoWallet: "defer"`, so `awardOwedSolanaBadges` mints the
|
|
30
|
+
* badge once the member links one; `ignored` means the event is not a quest completion, or its
|
|
31
|
+
* quest is outside `quests`.
|
|
32
|
+
*
|
|
33
|
+
* @experimental A minor release can change the Solana badge helpers.
|
|
34
|
+
*/
|
|
35
|
+
type SolanaBadgeAward = {
|
|
36
|
+
status: "minted";
|
|
37
|
+
receipt: CompletionReceipt;
|
|
38
|
+
} | {
|
|
39
|
+
status: "already-minted";
|
|
40
|
+
receipt: CompletionReceipt;
|
|
41
|
+
} | {
|
|
42
|
+
status: "no-wallet";
|
|
43
|
+
} | {
|
|
44
|
+
status: "deferred";
|
|
45
|
+
} | {
|
|
46
|
+
status: "ignored";
|
|
47
|
+
};
|
|
48
|
+
/** @experimental A minor release can change the Solana badge helpers. */
|
|
49
|
+
type AwardSolanaBadgeInput = {
|
|
50
|
+
/**
|
|
51
|
+
* A management client with `points` and `read` permission: it reads the member's wallets and
|
|
52
|
+
* completions and records the receipt.
|
|
53
|
+
*/
|
|
54
|
+
management: Pick<ManagementClient, "completions" | "members">;
|
|
55
|
+
/** A delivery `verifyWebhook` verified. Events other than a quest's `completion.created` are ignored. */
|
|
56
|
+
event: WebhookEvent;
|
|
57
|
+
/** The badge's Token-2022 mint, as `createSolanaBadgeMint` created it. */
|
|
58
|
+
mint: string;
|
|
59
|
+
/** The mint authority. It signs the mint and pays the fee and the member's token account rent. */
|
|
60
|
+
authority: TransactionSigner;
|
|
61
|
+
rpc: SolanaBadgeRpc;
|
|
62
|
+
/** The cluster `rpc` serves, recorded on the receipt: `solanaMainnet` or `solanaDevnet`. */
|
|
63
|
+
network: SolanaNetwork;
|
|
64
|
+
/** Award only completions of these quest IDs. Omit to award every quest's completions. */
|
|
65
|
+
quests?: readonly string[];
|
|
66
|
+
/**
|
|
67
|
+
* What happens when the member has no proven Solana wallet. Both send nothing: `skip` (the
|
|
68
|
+
* default) answers `no-wallet`, and `defer` answers `deferred`, for a server that also calls
|
|
69
|
+
* `awardOwedSolanaBadges` on `wallet.linked` to mint the badge once the member links a wallet.
|
|
70
|
+
*/
|
|
71
|
+
whenNoWallet?: "skip" | "defer";
|
|
72
|
+
/** Receipt `label` Console shows beside it. */
|
|
73
|
+
label?: string;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Mints one unit of a non-transferable Token-2022 badge to the member's most recently linked
|
|
77
|
+
* proven Solana wallet for a quest's `completion.created` event, and records the transaction as
|
|
78
|
+
* the completion's `badge` receipt. Call it from your webhook handler; your server holds the mint
|
|
79
|
+
* authority and pays the fees.
|
|
80
|
+
*
|
|
81
|
+
* Exactly once per completion, whatever the deliveries and retries. Before sending, it records the
|
|
82
|
+
* signed transaction as a `badge-attempt-<n>` receipt, which only one call can record, and only
|
|
83
|
+
* then sends it. A call that finds an earlier attempt records it as the badge once it landed,
|
|
84
|
+
* sends a new attempt once it failed or its blockhash expired, and otherwise throws
|
|
85
|
+
* `SolanaBadgePendingError` without sending, so the delivery is retried later. It waits for the
|
|
86
|
+
* `confirmed` commitment.
|
|
87
|
+
*
|
|
88
|
+
* Requires the optional peer dependencies `@solana/kit` and `@solana-program/token-2022`.
|
|
89
|
+
*
|
|
90
|
+
* @experimental A minor release can change the Solana badge helpers.
|
|
91
|
+
*/
|
|
92
|
+
declare function awardSolanaBadge(input: AwardSolanaBadgeInput): Promise<SolanaBadgeAward>;
|
|
93
|
+
/**
|
|
94
|
+
* What `awardOwedSolanaBadges` did: `awarded` with each owed completion and what
|
|
95
|
+
* `awardSolanaBadge` did for it (`minted`, `already-minted`, or `no-wallet` when the member has
|
|
96
|
+
* unlinked the wallet since), or `ignored` when the event is not a Solana `wallet.linked`.
|
|
97
|
+
*
|
|
98
|
+
* @experimental A minor release can change the Solana badge helpers.
|
|
99
|
+
*/
|
|
100
|
+
type OwedSolanaBadges = {
|
|
101
|
+
status: "awarded";
|
|
102
|
+
awards: {
|
|
103
|
+
completion: string;
|
|
104
|
+
quest: string;
|
|
105
|
+
award: SolanaBadgeAward;
|
|
106
|
+
}[];
|
|
107
|
+
} | {
|
|
108
|
+
status: "ignored";
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* `awardSolanaBadge`'s input for a `wallet.linked` event: the same badge, mint authority and
|
|
112
|
+
* `quests`.
|
|
113
|
+
*
|
|
114
|
+
* @experimental A minor release can change the Solana badge helpers.
|
|
115
|
+
*/
|
|
116
|
+
type AwardOwedSolanaBadgesInput = Omit<AwardSolanaBadgeInput, "whenNoWallet">;
|
|
117
|
+
/**
|
|
118
|
+
* Mints the badges a member is owed once they link a Solana wallet: call it from your webhook
|
|
119
|
+
* handler for `wallet.linked`, next to `awardSolanaBadge` with `whenNoWallet: "defer"` for
|
|
120
|
+
* `completion.created`. For a Solana wallet, it lists the member's completions that count (not
|
|
121
|
+
* revoked) of each quest in `quests` (every quest when omitted) and awards each one exactly as
|
|
122
|
+
* `awardSolanaBadge` does, so a completion that has its `badge` receipt mints nothing and a
|
|
123
|
+
* redelivered event mints nothing new. Other events and chains are `ignored`.
|
|
124
|
+
*
|
|
125
|
+
* It mints one completion at a time and throws on the first failure, such as
|
|
126
|
+
* `SolanaBadgePendingError`: fail the delivery so Domino retries it, and the retry skips the badges
|
|
127
|
+
* already minted.
|
|
128
|
+
*
|
|
129
|
+
* @experimental A minor release can change the Solana badge helpers.
|
|
130
|
+
*/
|
|
131
|
+
declare function awardOwedSolanaBadges(input: AwardOwedSolanaBadgesInput): Promise<OwedSolanaBadges>;
|
|
132
|
+
/**
|
|
133
|
+
* An earlier call's badge transaction for this completion has not landed yet, and its blockhash
|
|
134
|
+
* is still valid. Nothing was sent; call again later, for example by failing the webhook delivery
|
|
135
|
+
* so Domino retries it.
|
|
136
|
+
*
|
|
137
|
+
* @experimental A minor release can change the Solana badge helpers.
|
|
138
|
+
*/
|
|
139
|
+
declare class SolanaBadgePendingError extends Error {
|
|
140
|
+
readonly signature: string;
|
|
141
|
+
readonly code = "badge-pending";
|
|
142
|
+
constructor(signature: string);
|
|
143
|
+
}
|
|
144
|
+
/** @experimental A minor release can change the Solana badge helpers. */
|
|
145
|
+
type CreateSolanaBadgeMintInput = {
|
|
146
|
+
/** Becomes the mint and metadata authority, and pays for the mint account. */
|
|
147
|
+
authority: TransactionSigner;
|
|
148
|
+
rpc: SolanaBadgeRpc;
|
|
149
|
+
/** The badge's on-chain name, symbol and metadata JSON URI, which wallets and explorers show. */
|
|
150
|
+
name: string;
|
|
151
|
+
symbol: string;
|
|
152
|
+
uri: string;
|
|
153
|
+
/** The new mint's key pair. Omit to generate one. */
|
|
154
|
+
mint?: KeyPairSigner;
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Creates a badge mint for `awardSolanaBadge`: a Token-2022 mint with 0 decimals, the
|
|
158
|
+
* NonTransferable extension, so its tokens can't move from the wallet they were minted to, and
|
|
159
|
+
* on-mint metadata (the metadata pointer and token metadata extensions). Run it once per badge,
|
|
160
|
+
* for example from a setup script, and keep the mint address.
|
|
161
|
+
*
|
|
162
|
+
* @experimental A minor release can change the Solana badge helpers.
|
|
163
|
+
*/
|
|
164
|
+
declare function createSolanaBadgeMint(input: CreateSolanaBadgeMintInput): Promise<{
|
|
165
|
+
mint: Address;
|
|
166
|
+
signature: Signature;
|
|
167
|
+
}>;
|
|
168
|
+
/** The SPL Memo `awardSolanaBadge` attaches to a completion's mint. */
|
|
169
|
+
declare const solanaBadgeMemo: (completion: string) => string;
|
|
170
|
+
|
|
171
|
+
export { type AwardOwedSolanaBadgesInput, type AwardSolanaBadgeInput, type CreateSolanaBadgeMintInput, type OwedSolanaBadges, type SolanaBadgeAward, SolanaBadgePendingError, type SolanaBadgeRpc, SolanaNetwork, awardOwedSolanaBadges, awardSolanaBadge, createSolanaBadgeMint, solanaBadgeMemo, solanaBadgeReceiptKey };
|
package/dist/solana.js
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import {
|
|
2
|
+
maxCompletionReceipts,
|
|
3
|
+
walletLinkedEventDataSchema
|
|
4
|
+
} from "./chunk-4JSPMFO2.js";
|
|
5
|
+
import "./chunk-DNPDR4Z7.js";
|
|
6
|
+
import "./chunk-DDJN2T5A.js";
|
|
7
|
+
import "./chunk-MEUAJIVO.js";
|
|
8
|
+
import "./chunk-MWMCQLCG.js";
|
|
9
|
+
import "./chunk-R3MNZKNJ.js";
|
|
10
|
+
import "./chunk-6UBFSMCM.js";
|
|
11
|
+
import "./chunk-55WJVFWC.js";
|
|
12
|
+
import {
|
|
13
|
+
paginate,
|
|
14
|
+
solanaDevnet,
|
|
15
|
+
solanaMainnet,
|
|
16
|
+
solanaMemoProgram
|
|
17
|
+
} from "./chunk-6YTSRWRB.js";
|
|
18
|
+
import "./chunk-IW46TW3A.js";
|
|
19
|
+
|
|
20
|
+
// src/solana.ts
|
|
21
|
+
import {
|
|
22
|
+
appendTransactionMessageInstructions,
|
|
23
|
+
createTransactionMessage,
|
|
24
|
+
flattenInstructionPlan,
|
|
25
|
+
getBase64EncodedWireTransaction,
|
|
26
|
+
getSignatureFromTransaction,
|
|
27
|
+
pipe,
|
|
28
|
+
setTransactionMessageFeePayerSigner,
|
|
29
|
+
setTransactionMessageLifetimeUsingBlockhash,
|
|
30
|
+
signTransactionMessageWithSigners,
|
|
31
|
+
address,
|
|
32
|
+
generateKeyPairSigner
|
|
33
|
+
} from "@solana/kit";
|
|
34
|
+
import {
|
|
35
|
+
TOKEN_2022_PROGRAM_ADDRESS,
|
|
36
|
+
extension,
|
|
37
|
+
fetchMint,
|
|
38
|
+
findAssociatedTokenPda,
|
|
39
|
+
getCreateMintInstructionPlan,
|
|
40
|
+
getMintToATAInstructionPlan
|
|
41
|
+
} from "@solana-program/token-2022";
|
|
42
|
+
var solanaBadgeReceiptKey = "badge";
|
|
43
|
+
async function awardSolanaBadge(input) {
|
|
44
|
+
const completion = questCompletion(input.event);
|
|
45
|
+
if (!completion || input.quests && !input.quests.includes(completion.quest)) {
|
|
46
|
+
return { status: "ignored" };
|
|
47
|
+
}
|
|
48
|
+
return awardCompletion(input, completion, badgeLookups(input));
|
|
49
|
+
}
|
|
50
|
+
async function awardOwedSolanaBadges(input) {
|
|
51
|
+
const { event, management } = input;
|
|
52
|
+
const linked = event.type === "wallet.linked" ? walletLinkedEventDataSchema.safeParse(event.data) : void 0;
|
|
53
|
+
if (!linked?.success || linked.data.chain !== "solana") {
|
|
54
|
+
return { status: "ignored" };
|
|
55
|
+
}
|
|
56
|
+
const { member } = linked.data;
|
|
57
|
+
const lookups = badgeLookups(input);
|
|
58
|
+
const awards = [];
|
|
59
|
+
for (const quest of input.quests ?? [void 0]) {
|
|
60
|
+
for await (const completion of paginate(
|
|
61
|
+
(cursor) => management.completions.list({ member, quest, cursor, limit: 100 })
|
|
62
|
+
)) {
|
|
63
|
+
if (completion.source?.kind !== "quest") {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
awards.push({
|
|
67
|
+
completion: completion.id,
|
|
68
|
+
quest: completion.quest,
|
|
69
|
+
award: await awardCompletion(
|
|
70
|
+
input,
|
|
71
|
+
{ id: completion.id, quest: completion.quest, member },
|
|
72
|
+
lookups
|
|
73
|
+
)
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { status: "awarded", awards };
|
|
78
|
+
}
|
|
79
|
+
function badgeLookups(input) {
|
|
80
|
+
const once = (read) => {
|
|
81
|
+
let value;
|
|
82
|
+
return () => value ??= read();
|
|
83
|
+
};
|
|
84
|
+
const wallets = /* @__PURE__ */ new Map();
|
|
85
|
+
return {
|
|
86
|
+
wallet(member) {
|
|
87
|
+
if (!wallets.has(member)) {
|
|
88
|
+
wallets.set(
|
|
89
|
+
member,
|
|
90
|
+
once(() => provenSolanaWallet(input.management, member))
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
return wallets.get(member)();
|
|
94
|
+
},
|
|
95
|
+
decimals: once(
|
|
96
|
+
() => badgeDecimals(input.rpc, address(input.mint), input.authority.address)
|
|
97
|
+
)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
async function awardCompletion(input, completion, lookups) {
|
|
101
|
+
const { management, rpc, authority } = input;
|
|
102
|
+
let receipts = await management.completions.receipts(completion.id);
|
|
103
|
+
const existing = receipts.find(
|
|
104
|
+
(receipt) => receipt.key === solanaBadgeReceiptKey
|
|
105
|
+
);
|
|
106
|
+
if (existing) {
|
|
107
|
+
return { status: "already-minted", receipt: existing };
|
|
108
|
+
}
|
|
109
|
+
const record = (attempt2) => management.completions.recordReceipt(completion.id, {
|
|
110
|
+
key: solanaBadgeReceiptKey,
|
|
111
|
+
network: attempt2.network,
|
|
112
|
+
signature: attempt2.signature,
|
|
113
|
+
...attempt2.asset === null ? {} : { asset: attempt2.asset },
|
|
114
|
+
...attempt2.recipient === null ? {} : { recipient: attempt2.recipient },
|
|
115
|
+
...input.label === void 0 ? {} : { label: input.label }
|
|
116
|
+
});
|
|
117
|
+
const settled = async () => {
|
|
118
|
+
const attempt2 = latestAttempt(receipts);
|
|
119
|
+
const outcome = attempt2 && await attemptOutcome(rpc, attempt2);
|
|
120
|
+
if (outcome === "landed") {
|
|
121
|
+
return { status: "minted", receipt: await record(attempt2) };
|
|
122
|
+
}
|
|
123
|
+
if (outcome === "pending") {
|
|
124
|
+
throw new SolanaBadgePendingError(attempt2.signature);
|
|
125
|
+
}
|
|
126
|
+
return attempt2 ? attemptNumber(attempt2.key) + 1 : 1;
|
|
127
|
+
};
|
|
128
|
+
const next = await settled();
|
|
129
|
+
if (typeof next !== "number") {
|
|
130
|
+
return next;
|
|
131
|
+
}
|
|
132
|
+
if (receipts.length >= maxCompletionReceipts - 1) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
`Completion ${completion.id} holds ${receipts.length} receipts, leaving no room for another badge attempt and the badge`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
const wallet = await lookups.wallet(completion.member);
|
|
138
|
+
if (!wallet) {
|
|
139
|
+
return { status: input.whenNoWallet === "defer" ? "deferred" : "no-wallet" };
|
|
140
|
+
}
|
|
141
|
+
const mint = address(input.mint);
|
|
142
|
+
const owner = address(wallet);
|
|
143
|
+
const decimals = await lookups.decimals();
|
|
144
|
+
const [token] = await findAssociatedTokenPda({
|
|
145
|
+
owner,
|
|
146
|
+
mint,
|
|
147
|
+
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
|
|
148
|
+
});
|
|
149
|
+
const transaction = await sign(rpc, authority, [
|
|
150
|
+
...instructions(
|
|
151
|
+
getMintToATAInstructionPlan({
|
|
152
|
+
payer: authority,
|
|
153
|
+
ata: token,
|
|
154
|
+
owner,
|
|
155
|
+
mint,
|
|
156
|
+
mintAuthority: authority,
|
|
157
|
+
amount: 1n,
|
|
158
|
+
decimals
|
|
159
|
+
})
|
|
160
|
+
),
|
|
161
|
+
memoInstruction(solanaBadgeMemo(completion.id))
|
|
162
|
+
]);
|
|
163
|
+
let attempt;
|
|
164
|
+
try {
|
|
165
|
+
attempt = await management.completions.recordReceipt(completion.id, {
|
|
166
|
+
key: `${attemptPrefix}${next}`,
|
|
167
|
+
network: input.network,
|
|
168
|
+
signature: transaction.signature,
|
|
169
|
+
asset: mint,
|
|
170
|
+
recipient: owner,
|
|
171
|
+
label: `Badge mint, valid through block height ${transaction.lastValidBlockHeight}`
|
|
172
|
+
});
|
|
173
|
+
} catch (error) {
|
|
174
|
+
if (error.code !== "receipt-conflict") {
|
|
175
|
+
throw error;
|
|
176
|
+
}
|
|
177
|
+
receipts = await management.completions.receipts(completion.id);
|
|
178
|
+
const answer = await settled();
|
|
179
|
+
if (typeof answer !== "number") {
|
|
180
|
+
return answer;
|
|
181
|
+
}
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
await sendAndConfirm(rpc, transaction);
|
|
185
|
+
return { status: "minted", receipt: await record(attempt) };
|
|
186
|
+
}
|
|
187
|
+
var SolanaBadgePendingError = class extends Error {
|
|
188
|
+
constructor(signature) {
|
|
189
|
+
super(
|
|
190
|
+
`The badge transaction ${signature} for this completion is still confirming; try again later`
|
|
191
|
+
);
|
|
192
|
+
this.signature = signature;
|
|
193
|
+
this.name = "SolanaBadgePendingError";
|
|
194
|
+
}
|
|
195
|
+
signature;
|
|
196
|
+
code = "badge-pending";
|
|
197
|
+
};
|
|
198
|
+
async function createSolanaBadgeMint(input) {
|
|
199
|
+
const { authority, rpc } = input;
|
|
200
|
+
const mint = input.mint ?? await generateKeyPairSigner();
|
|
201
|
+
const plan = await getCreateMintInstructionPlan(
|
|
202
|
+
{
|
|
203
|
+
getMinimumBalance: async (space) => rpc.getMinimumBalanceForRentExemption(BigInt(space)).send()
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
payer: authority,
|
|
207
|
+
newMint: mint,
|
|
208
|
+
decimals: 0,
|
|
209
|
+
mintAuthority: authority,
|
|
210
|
+
extensions: [
|
|
211
|
+
extension("NonTransferable", {}),
|
|
212
|
+
extension("MetadataPointer", {
|
|
213
|
+
authority: authority.address,
|
|
214
|
+
metadataAddress: mint.address
|
|
215
|
+
}),
|
|
216
|
+
extension("TokenMetadata", {
|
|
217
|
+
updateAuthority: authority.address,
|
|
218
|
+
mint: mint.address,
|
|
219
|
+
name: input.name,
|
|
220
|
+
symbol: input.symbol,
|
|
221
|
+
uri: input.uri,
|
|
222
|
+
additionalMetadata: /* @__PURE__ */ new Map()
|
|
223
|
+
})
|
|
224
|
+
]
|
|
225
|
+
}
|
|
226
|
+
);
|
|
227
|
+
const signature = await sendAndConfirm(
|
|
228
|
+
rpc,
|
|
229
|
+
await sign(rpc, authority, instructions(plan))
|
|
230
|
+
);
|
|
231
|
+
return { mint: mint.address, signature };
|
|
232
|
+
}
|
|
233
|
+
var solanaBadgeMemo = (completion) => `domino-badge:${completion}`;
|
|
234
|
+
function questCompletion(event) {
|
|
235
|
+
const { data } = event;
|
|
236
|
+
const source = data.source;
|
|
237
|
+
const fromQuest = source === void 0 ? typeof data.attempt === "string" : source?.kind === "quest";
|
|
238
|
+
if (event.type !== "completion.created" || !fromQuest || typeof data.completion !== "string" || typeof data.quest !== "string" || typeof data.member !== "string") {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
return { id: data.completion, quest: data.quest, member: data.member };
|
|
242
|
+
}
|
|
243
|
+
async function provenSolanaWallet(management, member) {
|
|
244
|
+
let newest;
|
|
245
|
+
for await (const identity of paginate(
|
|
246
|
+
(cursor) => management.members.identityStates.list(member, { cursor, limit: 100 })
|
|
247
|
+
)) {
|
|
248
|
+
if (identity.kind !== "wallet" || identity.chain !== "solana" || !identity.linked || identity.source === "import") {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
const candidate = {
|
|
252
|
+
address: identity.address,
|
|
253
|
+
linkedAt: identity.linkedAt ?? -1,
|
|
254
|
+
revision: identity.revision
|
|
255
|
+
};
|
|
256
|
+
if (!newest || candidate.linkedAt > newest.linkedAt || candidate.linkedAt === newest.linkedAt && candidate.revision > newest.revision) {
|
|
257
|
+
newest = candidate;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return newest?.address;
|
|
261
|
+
}
|
|
262
|
+
async function badgeDecimals(rpc, mint, authority) {
|
|
263
|
+
const account = await fetchMint(rpc, mint, { commitment: "confirmed" });
|
|
264
|
+
if (account.programAddress !== TOKEN_2022_PROGRAM_ADDRESS) {
|
|
265
|
+
throw new Error(`${mint} is not a Token-2022 mint`);
|
|
266
|
+
}
|
|
267
|
+
const mintAuthority = account.data.mintAuthority;
|
|
268
|
+
if (mintAuthority.__option === "None" || mintAuthority.value !== authority) {
|
|
269
|
+
throw new Error(`${authority} is not the mint authority of ${mint}`);
|
|
270
|
+
}
|
|
271
|
+
return account.data.decimals;
|
|
272
|
+
}
|
|
273
|
+
var attemptPrefix = "badge-attempt-";
|
|
274
|
+
var attemptNumber = (key) => Number(key.slice(attemptPrefix.length));
|
|
275
|
+
function latestAttempt(receipts) {
|
|
276
|
+
return receipts.filter((receipt) => /^badge-attempt-[1-9][0-9]*$/.test(receipt.key)).sort((a, b) => attemptNumber(b.key) - attemptNumber(a.key))[0];
|
|
277
|
+
}
|
|
278
|
+
async function attemptOutcome(rpc, attempt) {
|
|
279
|
+
const lastValid = attempt.label?.match(/block height (\d+)$/)?.[1];
|
|
280
|
+
const height = await rpc.getBlockHeight({ commitment: "finalized" }).send();
|
|
281
|
+
const {
|
|
282
|
+
value: [status]
|
|
283
|
+
} = await rpc.getSignatureStatuses([attempt.signature], {
|
|
284
|
+
searchTransactionHistory: true
|
|
285
|
+
}).send();
|
|
286
|
+
if (status?.confirmationStatus === "confirmed" || status?.confirmationStatus === "finalized") {
|
|
287
|
+
return status.err ? "failed" : "landed";
|
|
288
|
+
}
|
|
289
|
+
return lastValid === void 0 || height > BigInt(lastValid) ? "expired" : "pending";
|
|
290
|
+
}
|
|
291
|
+
var memoInstruction = (memo) => ({
|
|
292
|
+
programAddress: address(solanaMemoProgram),
|
|
293
|
+
data: new TextEncoder().encode(memo)
|
|
294
|
+
});
|
|
295
|
+
var instructions = (plan) => flattenInstructionPlan(plan).map((step) => {
|
|
296
|
+
if (step.kind !== "single") {
|
|
297
|
+
throw new Error("Expected a plan of single instructions");
|
|
298
|
+
}
|
|
299
|
+
return step.instruction;
|
|
300
|
+
});
|
|
301
|
+
async function sign(rpc, feePayer, steps) {
|
|
302
|
+
const { value: blockhash } = await rpc.getLatestBlockhash({ commitment: "confirmed" }).send();
|
|
303
|
+
const transaction = await signTransactionMessageWithSigners(
|
|
304
|
+
pipe(
|
|
305
|
+
createTransactionMessage({ version: 0 }),
|
|
306
|
+
(message) => setTransactionMessageFeePayerSigner(feePayer, message),
|
|
307
|
+
(message) => setTransactionMessageLifetimeUsingBlockhash(blockhash, message),
|
|
308
|
+
(message) => appendTransactionMessageInstructions(steps, message)
|
|
309
|
+
)
|
|
310
|
+
);
|
|
311
|
+
return {
|
|
312
|
+
wire: getBase64EncodedWireTransaction(transaction),
|
|
313
|
+
signature: getSignatureFromTransaction(transaction),
|
|
314
|
+
lastValidBlockHeight: blockhash.lastValidBlockHeight
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
async function sendAndConfirm(rpc, transaction) {
|
|
318
|
+
try {
|
|
319
|
+
await rpc.sendTransaction(transaction.wire, {
|
|
320
|
+
encoding: "base64",
|
|
321
|
+
preflightCommitment: "confirmed"
|
|
322
|
+
}).send();
|
|
323
|
+
} catch (error) {
|
|
324
|
+
const {
|
|
325
|
+
value: [status]
|
|
326
|
+
} = await rpc.getSignatureStatuses([transaction.signature]).send();
|
|
327
|
+
if (!status) {
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
await confirmed(rpc, transaction.signature, transaction.lastValidBlockHeight);
|
|
332
|
+
return transaction.signature;
|
|
333
|
+
}
|
|
334
|
+
async function confirmed(rpc, signature, lastValidBlockHeight) {
|
|
335
|
+
for (; ; ) {
|
|
336
|
+
const {
|
|
337
|
+
value: [status]
|
|
338
|
+
} = await rpc.getSignatureStatuses([signature]).send();
|
|
339
|
+
if (status?.err) {
|
|
340
|
+
throw new Error(
|
|
341
|
+
`Transaction ${signature} failed: ${JSON.stringify(status.err, (_, value) => typeof value === "bigint" ? String(value) : value)}`
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
if (status?.confirmationStatus === "confirmed" || status?.confirmationStatus === "finalized") {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (await rpc.getBlockHeight({ commitment: "confirmed" }).send() > lastValidBlockHeight) {
|
|
348
|
+
throw new Error(
|
|
349
|
+
`Transaction ${signature} was not confirmed before its blockhash expired`
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
export {
|
|
356
|
+
SolanaBadgePendingError,
|
|
357
|
+
awardOwedSolanaBadges,
|
|
358
|
+
awardSolanaBadge,
|
|
359
|
+
createSolanaBadgeMint,
|
|
360
|
+
solanaBadgeMemo,
|
|
361
|
+
solanaBadgeReceiptKey,
|
|
362
|
+
solanaDevnet,
|
|
363
|
+
solanaMainnet
|
|
364
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as z from 'zod';
|
|
2
|
-
import { L as LedgerReference, Q as QuestHandle } from './tracker-data-
|
|
3
|
-
import { B as ProjectGroupReference } from './accounts-
|
|
2
|
+
import { L as LedgerReference, Q as QuestHandle } from './tracker-data-CAK942sx.js';
|
|
3
|
+
import { B as ProjectGroupReference } from './accounts-DnpKoJCo.js';
|
|
4
4
|
|
|
5
5
|
declare const completionPrerequisiteSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
6
6
|
kind: z.ZodLiteral<"completion">;
|
|
@@ -1,111 +1,9 @@
|
|
|
1
|
-
import { c as AuthProvider, J as SignInProvider } from './accounts-
|
|
2
|
-
import { p as createRelayClient, k as RelayRequestOptions, g as RelayError } from './client-
|
|
3
|
-
import { a as TelegramSignInMethods } from './submission-input-
|
|
1
|
+
import { c as AuthProvider, J as SignInProvider } from './accounts-DnpKoJCo.js';
|
|
2
|
+
import { p as createRelayClient, k as RelayRequestOptions, g as RelayError } from './client-BMif22WQ.js';
|
|
3
|
+
import { a as TelegramSignInMethods } from './submission-input-CaL8drIh.js';
|
|
4
4
|
import { b as ParticipantSession } from './participant-activity-DXRq4s6K.js';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
/** An EIP-1193 provider, such as `window.ethereum` or an EIP-6963 announcement's provider. */
|
|
8
|
-
type Eip1193Provider = {
|
|
9
|
-
request(args: {
|
|
10
|
-
method: string;
|
|
11
|
-
params?: unknown[] | object;
|
|
12
|
-
}): Promise<unknown>;
|
|
13
|
-
/** Subscribes to a provider event such as `accountsChanged`; wallets without events leave it out. */
|
|
14
|
-
on?(event: string, listener: (...args: unknown[]) => void): unknown;
|
|
15
|
-
removeListener?(event: string, listener: (...args: unknown[]) => void): unknown;
|
|
16
|
-
};
|
|
17
|
-
/** The legacy injected Solana shape Phantom, Solflare and Backpack expose. */
|
|
18
|
-
type SolanaInjectedProvider = {
|
|
19
|
-
connect(): Promise<unknown>;
|
|
20
|
-
publicKey?: {
|
|
21
|
-
toBase58(): string;
|
|
22
|
-
} | null;
|
|
23
|
-
signMessage(message: Uint8Array, display?: "utf8"): Promise<{
|
|
24
|
-
signature: Uint8Array;
|
|
25
|
-
} | Uint8Array>;
|
|
26
|
-
};
|
|
27
|
-
/** The part of a Wallet Standard account Relay uses. */
|
|
28
|
-
type StandardWalletAccount = {
|
|
29
|
-
readonly address: string;
|
|
30
|
-
readonly chains: readonly string[];
|
|
31
|
-
};
|
|
32
|
-
/** The part of a Wallet Standard wallet Relay uses; any conforming wallet object fits. */
|
|
33
|
-
type StandardWallet = {
|
|
34
|
-
readonly name: string;
|
|
35
|
-
readonly icon?: string;
|
|
36
|
-
readonly chains: readonly string[];
|
|
37
|
-
readonly accounts: readonly StandardWalletAccount[];
|
|
38
|
-
readonly features: Readonly<Record<string, unknown>>;
|
|
39
|
-
};
|
|
40
|
-
/** Keplr's API, which Leap and Cosmostation also implement. */
|
|
41
|
-
type KeplrLike = {
|
|
42
|
-
enable(chainId: string | string[]): Promise<void>;
|
|
43
|
-
getKey(chainId: string): Promise<{
|
|
44
|
-
bech32Address: string;
|
|
45
|
-
}>;
|
|
46
|
-
signArbitrary(chainId: string, signer: string, data: string): Promise<{
|
|
47
|
-
signature: string;
|
|
48
|
-
pub_key: {
|
|
49
|
-
type: string;
|
|
50
|
-
value: string;
|
|
51
|
-
};
|
|
52
|
-
}>;
|
|
53
|
-
/** Adds a chain the wallet does not know, after the user approves it. */
|
|
54
|
-
experimentalSuggestChain?(chainInfo: CosmosChain["chainInfo"]): Promise<void>;
|
|
55
|
-
};
|
|
56
|
-
/** A wallet found in the page, ready to pass to `relay.wallets.link`. */
|
|
57
|
-
type DiscoveredWallet = {
|
|
58
|
-
id: string;
|
|
59
|
-
name: string;
|
|
60
|
-
icon?: string;
|
|
61
|
-
signer: WalletSigner;
|
|
62
|
-
};
|
|
63
|
-
/** Signs with an EIP-1193 provider through `personal_sign`. */
|
|
64
|
-
declare function evmSigner(provider: Eip1193Provider, info?: {
|
|
65
|
-
name?: string;
|
|
66
|
-
}): WalletSigner;
|
|
67
|
-
/** Signs with a legacy injected Solana provider, such as `window.phantom.solana`. */
|
|
68
|
-
declare function solanaSigner(provider: SolanaInjectedProvider, info?: {
|
|
69
|
-
name?: string;
|
|
70
|
-
}): WalletSigner;
|
|
71
|
-
/** Signs with a Wallet Standard wallet's `solana:signMessage` feature. */
|
|
72
|
-
declare function walletStandardSolanaSigner(wallet: StandardWallet): WalletSigner;
|
|
73
|
-
/**
|
|
74
|
-
* Signs an ADR-36 message with Keplr or a wallet that implements its API, on the app's chain:
|
|
75
|
-
* `{ chainId, chainInfo? }` or `"cosmos:<chain ID>"`. When the wallet does not know the chain and
|
|
76
|
-
* `chainInfo` is given, it suggests the chain to the wallet (`experimentalSuggestChain`) and tries
|
|
77
|
-
* again; without `chainInfo`, or with a wallet that cannot add chains, it throws an error that
|
|
78
|
-
* names the chain. Other failures, such as a rejected request, pass through.
|
|
79
|
-
*/
|
|
80
|
-
declare function cosmosSigner(provider: KeplrLike, chain: CosmosChain | CosmosNetwork, info?: {
|
|
81
|
-
name?: string;
|
|
82
|
-
}): WalletSigner;
|
|
83
|
-
/** EIP-6963 wallets, or `window.ethereum` when none announce themselves within `timeoutMs`. */
|
|
84
|
-
declare function discoverEvmWallets(timeoutMs?: number): Promise<DiscoveredWallet[]>;
|
|
85
|
-
/** Wallet Standard wallets that can sign Solana messages, then legacy injected providers. */
|
|
86
|
-
declare function discoverSolanaWallets(): DiscoveredWallet[];
|
|
87
|
-
/**
|
|
88
|
-
* Keplr, Leap and Cosmostation, each signing on the app's chain (see `cosmosSigner`). IDs end with
|
|
89
|
-
* the chain ID.
|
|
90
|
-
*/
|
|
91
|
-
declare function discoverCosmosWallets(chain: CosmosChain | CosmosNetwork): DiscoveredWallet[];
|
|
92
|
-
/**
|
|
93
|
-
* The Cosmos SDK chains an app offers wallets on: one chain or several, each as
|
|
94
|
-
* `{ chainId, chainInfo? }` or `"cosmos:<chain ID>"`. Relay has no chain list of its own.
|
|
95
|
-
*/
|
|
96
|
-
type CosmosChains = CosmosChain | CosmosNetwork | readonly (CosmosChain | CosmosNetwork)[];
|
|
97
|
-
/** The chains in `CosmosChains`, as a list. */
|
|
98
|
-
declare function cosmosChainList(chains: CosmosChains | undefined): (CosmosChain | CosmosNetwork)[];
|
|
99
|
-
/** An installed wallet that can sign in on one of the project's enabled wallet families. */
|
|
100
|
-
type SignInWallet = DiscoveredWallet & {
|
|
101
|
-
network: WalletSignInNetwork;
|
|
102
|
-
};
|
|
103
|
-
/**
|
|
104
|
-
* The wallets installed in this browser that can sign in with `families`: EVM wallets first, then
|
|
105
|
-
* Solana wallets, then Cosmos wallets once per chain in `cosmos`. Without `cosmos` there are no
|
|
106
|
-
* Cosmos wallets. Empty during SSR.
|
|
107
|
-
*/
|
|
108
|
-
declare function discoverSignInWallets(families: readonly WalletSignInNetwork[], cosmos?: CosmosChains): Promise<SignInWallet[]>;
|
|
5
|
+
import { m as WalletSignInNetwork, o as WalletSigner } from './wallet-DQtJelQQ.js';
|
|
6
|
+
import { C as CosmosChains } from './wallet-browser-dpmr22Xv.js';
|
|
109
7
|
|
|
110
8
|
type Auth = ReturnType<typeof createRelayClient>["auth"];
|
|
111
9
|
/**
|
|
@@ -286,4 +184,4 @@ declare function signInOptions(relay: SignInClient, input?: {
|
|
|
286
184
|
*/
|
|
287
185
|
declare function telegramMiniAppInitData(): string | null;
|
|
288
186
|
|
|
289
|
-
export { type
|
|
187
|
+
export { type EmailSignInOption as E, type OAuthSignInOption as O, type ProviderSignInOption as P, type SignInClient as S, type TelegramSignInOption as T, type WalletSignInOption as W, type SignInIcon as a, type SignInMethods as b, type SignInOption as c, type SignInOptions as d, type SignInUnavailable as e, signInOptions as s, telegramMiniAppInitData as t };
|