@joeywallet/wallet-sdk 0.2.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/LICENSE +21 -0
- package/README.md +705 -0
- package/dist/client.d.ts +55 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +224 -0
- package/dist/client.js.map +1 -0
- package/dist/detect.d.ts +45 -0
- package/dist/detect.d.ts.map +1 -0
- package/dist/detect.js +238 -0
- package/dist/detect.js.map +1 -0
- package/dist/errors.d.ts +75 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +120 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/mutation.d.ts +46 -0
- package/dist/mutation.d.ts.map +1 -0
- package/dist/mutation.js +67 -0
- package/dist/mutation.js.map +1 -0
- package/dist/provider.d.ts +159 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +142 -0
- package/dist/provider.js.map +1 -0
- package/dist/react.d.ts +76 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +225 -0
- package/dist/react.js.map +1 -0
- package/dist/types.d.ts +391 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +38 -0
- package/dist/types.js.map +1 -0
- package/dist/vanilla.d.ts +58 -0
- package/dist/vanilla.d.ts.map +1 -0
- package/dist/vanilla.js +161 -0
- package/dist/vanilla.js.map +1 -0
- package/package.json +70 -0
- package/src/client.ts +342 -0
- package/src/detect.ts +278 -0
- package/src/errors.ts +133 -0
- package/src/index.ts +97 -0
- package/src/mutation.ts +109 -0
- package/src/provider.ts +229 -0
- package/src/react.ts +375 -0
- package/src/types.ts +440 -0
- package/src/vanilla.ts +239 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for `@joeywallet/wallet-sdk`.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the injected provider's surface field for field
|
|
5
|
+
* (`apps/extension/src/provider/`). Where the two could drift, the provider
|
|
6
|
+
* wins: this package is a convenience layer, not a second definition of the
|
|
7
|
+
* protocol.
|
|
8
|
+
*
|
|
9
|
+
* Nothing here imports from `xrpl`. A published `.d.ts` that did would fail to
|
|
10
|
+
* resolve for the (many) dapps that talk to a wallet without depending on
|
|
11
|
+
* xrpl.js, and `skipLibCheck` only hides that, it does not fix it. Instead the
|
|
12
|
+
* transaction argument of every signing method is generic over
|
|
13
|
+
* {@link TransactionLike}, so a caller who *does* have xrpl.js can pass a
|
|
14
|
+
* `Payment` / `TrustSet` / `SubmittableTransaction` and keep full checking on
|
|
15
|
+
* their own side. `test/xrpl-types.test.ts` pins that assignability against the
|
|
16
|
+
* real xrpl.js types.
|
|
17
|
+
*/
|
|
18
|
+
/** CAIP-2 chain ids, as XLS-72d defines them. Mainnet 0, testnet 1, devnet 2. */
|
|
19
|
+
export declare const JOEY_CHAINS: readonly ["xrpl:0", "xrpl:1", "xrpl:2"];
|
|
20
|
+
export type JoeyChain = (typeof JOEY_CHAINS)[number];
|
|
21
|
+
export interface JoeyNetwork {
|
|
22
|
+
chain: JoeyChain;
|
|
23
|
+
/** The XRPL `NetworkID`. Same number as the chain id suffix. */
|
|
24
|
+
networkId: number;
|
|
25
|
+
/** The wallet's own name for the network, e.g. `mainnet`. */
|
|
26
|
+
name: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function isJoeyChain(value: unknown): value is JoeyChain;
|
|
29
|
+
/** `xrpl:0` for network id 0, and so on. Throws for anything else. */
|
|
30
|
+
export declare function chainForNetworkId(networkId: number): JoeyChain;
|
|
31
|
+
/** The `NetworkID` a chain id refers to, or `null` when it is not an XRPL chain. */
|
|
32
|
+
export declare function networkIdForChain(chain: string): number | null;
|
|
33
|
+
/** An account as the wallet reports it. Never carries secret material. */
|
|
34
|
+
export interface JoeyAccount {
|
|
35
|
+
/** Classic `r...` address. */
|
|
36
|
+
address: string;
|
|
37
|
+
/** Hex-encoded public key. Absent for a watch-only account, which cannot sign. */
|
|
38
|
+
publicKey?: string;
|
|
39
|
+
/** The nickname the user gave the account, when they chose to share it. */
|
|
40
|
+
label?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface IssuedCurrencyAmount {
|
|
43
|
+
/** Three-character code or 40-character hex. */
|
|
44
|
+
currency: string;
|
|
45
|
+
issuer: string;
|
|
46
|
+
/** Decimal string. Never a JS number — XRPL values exceed float64 precision. */
|
|
47
|
+
value: string;
|
|
48
|
+
}
|
|
49
|
+
export interface MPTAmount {
|
|
50
|
+
mpt_issuance_id: string;
|
|
51
|
+
value: string;
|
|
52
|
+
}
|
|
53
|
+
/** A bare string is drops of XRP. */
|
|
54
|
+
export type Amount = string | IssuedCurrencyAmount | MPTAmount;
|
|
55
|
+
export interface Memo {
|
|
56
|
+
Memo: {
|
|
57
|
+
/** Hex-encoded. */
|
|
58
|
+
MemoData?: string;
|
|
59
|
+
MemoType?: string;
|
|
60
|
+
MemoFormat?: string;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export interface Signer {
|
|
64
|
+
Signer: {
|
|
65
|
+
Account: string;
|
|
66
|
+
TxnSignature: string;
|
|
67
|
+
SigningPubKey: string;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export interface PathStep {
|
|
71
|
+
account?: string;
|
|
72
|
+
currency?: string;
|
|
73
|
+
issuer?: string;
|
|
74
|
+
type?: number;
|
|
75
|
+
type_hex?: string;
|
|
76
|
+
}
|
|
77
|
+
export type Path = PathStep[];
|
|
78
|
+
/**
|
|
79
|
+
* The common fields of every XRPL transaction, used only as a generic
|
|
80
|
+
* constraint.
|
|
81
|
+
*
|
|
82
|
+
* `Flags` is deliberately `number | object` rather than a flags interface:
|
|
83
|
+
* xrpl.js models per-transaction flags as separate interfaces, and a TypeScript
|
|
84
|
+
* interface is not assignable to an index-signature type, so anything narrower
|
|
85
|
+
* here would reject a real `Payment`.
|
|
86
|
+
*/
|
|
87
|
+
export interface TransactionLike {
|
|
88
|
+
TransactionType: string;
|
|
89
|
+
Account?: string;
|
|
90
|
+
Fee?: string;
|
|
91
|
+
Sequence?: number;
|
|
92
|
+
AccountTxnID?: string;
|
|
93
|
+
Flags?: number | object;
|
|
94
|
+
LastLedgerSequence?: number;
|
|
95
|
+
Memos?: Memo[];
|
|
96
|
+
NetworkID?: number;
|
|
97
|
+
Signers?: Signer[];
|
|
98
|
+
SourceTag?: number;
|
|
99
|
+
SigningPubKey?: string;
|
|
100
|
+
TicketSequence?: number;
|
|
101
|
+
TxnSignature?: string;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* A transaction written inline, with no xrpl.js types to hand. The index
|
|
105
|
+
* signature is what lets an object literal carry `Destination`, `Amount` and
|
|
106
|
+
* the rest without an excess-property error.
|
|
107
|
+
*/
|
|
108
|
+
export interface AnyTransaction extends TransactionLike {
|
|
109
|
+
[field: string]: unknown;
|
|
110
|
+
}
|
|
111
|
+
export interface ConnectParams {
|
|
112
|
+
/** Chain the dapp wants. Rejected with 4902 when it is not an XRPL chain. */
|
|
113
|
+
chain?: JoeyChain;
|
|
114
|
+
/**
|
|
115
|
+
* Only return accounts this origin has already been granted, with no prompt.
|
|
116
|
+
* Resolves with an empty `accounts` array rather than an error, so it says
|
|
117
|
+
* nothing about whether a wallet is installed, locked, or in use.
|
|
118
|
+
*/
|
|
119
|
+
silent?: boolean;
|
|
120
|
+
/** Your dapp's name, shown on the approval screen. Up to 128 characters. */
|
|
121
|
+
name?: string;
|
|
122
|
+
/**
|
|
123
|
+
* An `https:` or `data:` URL for your dapp's icon, shown beside the name.
|
|
124
|
+
* Anything else is ignored rather than rendered.
|
|
125
|
+
*/
|
|
126
|
+
icon?: string;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* The fields every signing method accepts on top of its own.
|
|
130
|
+
*
|
|
131
|
+
* Both are optional and both are worth sending. Omitting `account` is only safe
|
|
132
|
+
* for an origin the user granted exactly one address; omitting `chain` means
|
|
133
|
+
* you are signing whatever network the wallet happens to be on.
|
|
134
|
+
*/
|
|
135
|
+
export interface SigningContextParams {
|
|
136
|
+
/**
|
|
137
|
+
* Which granted address signs. Defaults to the first the user granted.
|
|
138
|
+
*
|
|
139
|
+
* A user may grant several, so send this whenever your transaction carries an
|
|
140
|
+
* `Account`. The wallet refuses to sign a transaction whose `Account` is not
|
|
141
|
+
* the signing address — `INVALID_PARAMS` (-32602), before the user is
|
|
142
|
+
* prompted — rather than producing a valid signature over somebody else's
|
|
143
|
+
* transaction and resolving as if it had worked.
|
|
144
|
+
*
|
|
145
|
+
* `signTransactionFor` is the exception, and there `tx_signer` says who
|
|
146
|
+
* signs: a multisign entry is by definition a signature over a transaction
|
|
147
|
+
* belonging to another account.
|
|
148
|
+
*/
|
|
149
|
+
account?: string;
|
|
150
|
+
/**
|
|
151
|
+
* The chain you believe you are on.
|
|
152
|
+
*
|
|
153
|
+
* When it is not the chain the wallet is on, the request is refused with
|
|
154
|
+
* `CHAIN_DISCONNECTED` (4901) rather than signed. Joey has no
|
|
155
|
+
* `switchNetwork`: a page-driven, wallet-wide network switch is a phishing
|
|
156
|
+
* surface, so the user changes network in the wallet and the dapp is told
|
|
157
|
+
* through `networkChanged`.
|
|
158
|
+
*/
|
|
159
|
+
chain?: JoeyChain;
|
|
160
|
+
}
|
|
161
|
+
export interface ConnectResult {
|
|
162
|
+
accounts: JoeyAccount[];
|
|
163
|
+
/** `null` when the wallet granted no accounts, so there is no chain to report. */
|
|
164
|
+
chain: JoeyChain | null;
|
|
165
|
+
networkId: number | null;
|
|
166
|
+
}
|
|
167
|
+
export interface SignTransactionParams<TTx extends TransactionLike = AnyTransaction> extends SigningContextParams {
|
|
168
|
+
tx_json: TTx;
|
|
169
|
+
/** Let the wallet fill Fee / Sequence / LastLedgerSequence. Default true. */
|
|
170
|
+
autofill?: boolean;
|
|
171
|
+
}
|
|
172
|
+
export interface SignTransactionResult {
|
|
173
|
+
/**
|
|
174
|
+
* The transaction as signed — decoded back out of `tx_blob`, not echoed from
|
|
175
|
+
* what you sent.
|
|
176
|
+
*
|
|
177
|
+
* That is the point of it: it carries the `Fee`, `Sequence` and
|
|
178
|
+
* `LastLedgerSequence` the wallet filled in, the `SigningPubKey` and
|
|
179
|
+
* `TxnSignature` it produced, and any normalisation the serialiser applied.
|
|
180
|
+
* If it does not say what you expected, the bytes are what it says and not
|
|
181
|
+
* what you sent.
|
|
182
|
+
*/
|
|
183
|
+
tx_json: Record<string, unknown>;
|
|
184
|
+
/** Hex-encoded signed transaction blob, ready to submit. */
|
|
185
|
+
tx_blob: string;
|
|
186
|
+
/** Hash of the signed blob. Not a confirmation on its own. */
|
|
187
|
+
hash: string;
|
|
188
|
+
}
|
|
189
|
+
export interface SignAndSubmitTransactionResult extends SignTransactionResult {
|
|
190
|
+
/** Preliminary engine result, e.g. `tesSUCCESS`. Not final until validated. */
|
|
191
|
+
engine_result?: string;
|
|
192
|
+
engine_result_message?: string;
|
|
193
|
+
}
|
|
194
|
+
export interface SignTransactionForParams<TTx extends TransactionLike = AnyTransaction> extends SigningContextParams {
|
|
195
|
+
/**
|
|
196
|
+
* The address whose signature is being produced, which is *not* the
|
|
197
|
+
* transaction's `Account` — that stays the multisigned account.
|
|
198
|
+
*
|
|
199
|
+
* It must be one of the addresses the user granted this origin; the wallet
|
|
200
|
+
* answers `UNAUTHORIZED` (4100) rather than substituting one of its own.
|
|
201
|
+
*/
|
|
202
|
+
tx_signer: string;
|
|
203
|
+
tx_json: TTx;
|
|
204
|
+
/**
|
|
205
|
+
* **Ignored on this method.** Joey never autofills a multisign entry, and
|
|
206
|
+
* passing `true` does not make it.
|
|
207
|
+
*
|
|
208
|
+
* The field is here because the parameter shape is shared with the other
|
|
209
|
+
* signing methods, not because it does anything. Your `tx_json` is signed
|
|
210
|
+
* exactly as you sent it, so it must already carry `Fee`, `Sequence` and
|
|
211
|
+
* `LastLedgerSequence` — otherwise you get a real signature over a
|
|
212
|
+
* transaction `rippled` will not accept, and no error until you submit it.
|
|
213
|
+
*
|
|
214
|
+
* The reason is that a multisign signature is one of several over *identical
|
|
215
|
+
* bytes*. All three fields are inside the signed bytes, so two signers who
|
|
216
|
+
* approve a few seconds apart would read two different `LastLedgerSequence`
|
|
217
|
+
* values and the assembled transaction would validate at most one of their
|
|
218
|
+
* signatures. The `Fee` is worse: the rule is `base_fee x (1 + signatures)`,
|
|
219
|
+
* a wallet contributes one signature and cannot know how many others the
|
|
220
|
+
* signer list requires, and a coordinator cannot raise a `Fee` afterwards
|
|
221
|
+
* without discarding every signature it has already collected. The one party
|
|
222
|
+
* who can choose these is the coordinator assembling the transaction — you.
|
|
223
|
+
*/
|
|
224
|
+
autofill?: boolean;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* N independent transactions, one approval, signed in order.
|
|
228
|
+
*
|
|
229
|
+
* **This is not XLS-56 `Batch`, and the two must not be confused.** A `Batch`
|
|
230
|
+
* is a single transaction that carries others inside `RawTransactions` and
|
|
231
|
+
* commits them atomically on-ledger; Joey refuses to sign one for a website
|
|
232
|
+
* (see {@link JOEY_DAPP_FORBIDDEN_TRANSACTION_TYPES}) because its approval
|
|
233
|
+
* screen renders the outer transaction and a user cannot consent to inner ones
|
|
234
|
+
* they were never shown. `signTransactionBulk` is the opposite arrangement:
|
|
235
|
+
* ordinary, separate transactions, each rendered on its own page of the
|
|
236
|
+
* approval, each signed on its own, with no on-ledger atomicity at all. If
|
|
237
|
+
* transaction 3 fails, 1 and 2 have still happened.
|
|
238
|
+
*/
|
|
239
|
+
export interface SignTransactionBulkParams<TTx extends TransactionLike = AnyTransaction> extends SigningContextParams {
|
|
240
|
+
/** At most `MAX_BULK_TRANSACTIONS` entries; the wallet rejects a longer list. */
|
|
241
|
+
tx_list: Array<{
|
|
242
|
+
tx_json: TTx;
|
|
243
|
+
}>;
|
|
244
|
+
autofill?: boolean;
|
|
245
|
+
/**
|
|
246
|
+
* Whether the wallet broadcasts each transaction after signing it, or hands
|
|
247
|
+
* the signed blobs back for you to submit.
|
|
248
|
+
*
|
|
249
|
+
* Required, with no default, because the two are not interchangeable and a
|
|
250
|
+
* dapp that guesses wrong either double-spends or never spends. Joey mobile
|
|
251
|
+
* defaults this to `true` over WalletConnect and the extension defaults it to
|
|
252
|
+
* `false`; state your intent and neither default applies to you.
|
|
253
|
+
*/
|
|
254
|
+
submit: boolean;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* What became of one transaction of a bulk request that failed part way.
|
|
258
|
+
*
|
|
259
|
+
* The five values divide on two questions only the wallet can answer: did this
|
|
260
|
+
* transaction get a definite answer, and is the replay protection it holds —
|
|
261
|
+
* its sequence number, or its ticket — still reachable?
|
|
262
|
+
*
|
|
263
|
+
* - `submitted` — validated `tesSUCCESS`. It happened; `hash` is on the ledger.
|
|
264
|
+
* - `failed` — a definite answer that is not success. `engine_result` says
|
|
265
|
+
* which. Resubmitting this blob is pointless.
|
|
266
|
+
* - `unknown` — **do not treat this as `failed`.** Either the submission got
|
|
267
|
+
* no answer at all, or it sits behind one that did not. It may yet be
|
|
268
|
+
* validated, so resubmitting is not safe. Resolve it by its `hash` first.
|
|
269
|
+
* - `signed` — signed, never broadcast, and still submittable exactly as it
|
|
270
|
+
* stands: it spends a ticket nothing touched, or it holds the sequence
|
|
271
|
+
* number the account is now at. Submit the `signed` entries in the order
|
|
272
|
+
* they appear — they are a chain.
|
|
273
|
+
* - `stranded` — signed, never broadcast, and dead. The sequence it holds is
|
|
274
|
+
* either already consumed or sits behind a gap this batch will never fill,
|
|
275
|
+
* so it can never apply. Discard it and ask the user again.
|
|
276
|
+
*
|
|
277
|
+
* The last two are decided per entry against the account's actual sequence, not
|
|
278
|
+
* per batch off the failing transaction's code — the code alone is right only
|
|
279
|
+
* for a contiguous run the wallet numbered itself, and both a ticket and a
|
|
280
|
+
* `Sequence` you set yourself break that assumption, in opposite directions.
|
|
281
|
+
*/
|
|
282
|
+
export type BulkEntryStatus = 'submitted' | 'failed' | 'unknown' | 'signed' | 'stranded';
|
|
283
|
+
/** One entry of {@link SignTransactionBulkFailure.results}. */
|
|
284
|
+
export interface BulkEntryResult extends SignTransactionResult {
|
|
285
|
+
status: BulkEntryStatus;
|
|
286
|
+
/** The ledger's own token for this transaction, when it produced one. */
|
|
287
|
+
engine_result?: string;
|
|
288
|
+
engine_result_message?: string;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* The `data` on the error a partially-executed `signTransactionBulk` rejects
|
|
292
|
+
* with.
|
|
293
|
+
*
|
|
294
|
+
* A bulk request with `submit: true` signs every transaction before it
|
|
295
|
+
* broadcasts any of them, so the blobs exist whatever happens at index 3 and
|
|
296
|
+
* you get all of them back. Resume from `failedIndex` rather than asking the
|
|
297
|
+
* user to approve the whole batch again.
|
|
298
|
+
*
|
|
299
|
+
* ```ts
|
|
300
|
+
* try {
|
|
301
|
+
* await joey.signTransactionBulk({ tx_list, submit: true })
|
|
302
|
+
* } catch (error) {
|
|
303
|
+
* const data = (error as JoeyRpcError).data as SignTransactionBulkFailure | undefined
|
|
304
|
+
* if (data) {
|
|
305
|
+
* // data.results[i].status tells you what to do with entry i.
|
|
306
|
+
* }
|
|
307
|
+
* }
|
|
308
|
+
* ```
|
|
309
|
+
*
|
|
310
|
+
* Joey mobile rejects a bulk request over WalletConnect with the same
|
|
311
|
+
* `failedIndex` — zero-based, every earlier transaction succeeded, and the one
|
|
312
|
+
* thing that transfers between the two wallets unchanged. The record carrying
|
|
313
|
+
* it does not: mobile's `data` is a JSON *string* (WalletConnect types error
|
|
314
|
+
* `data` as one) holding `{failedIndex, signedTxs}`, where `signedTxs` is bare
|
|
315
|
+
* `tx_json` with no `status` on it, and its `message` is the engine token
|
|
316
|
+
* alone. Branch on the container and the array name; do not write one handler
|
|
317
|
+
* for both and expect it to parse.
|
|
318
|
+
*/
|
|
319
|
+
export interface SignTransactionBulkFailure {
|
|
320
|
+
/**
|
|
321
|
+
* Zero-based index of the first entry that did not succeed.
|
|
322
|
+
*
|
|
323
|
+
* The error's `message` names the same number the same way — "transaction at
|
|
324
|
+
* index 2 of 5 did not succeed: tecUNFUNDED_PAYMENT" — so the sentence and
|
|
325
|
+
* the field cannot be read as disagreeing. It said "transaction 2 of 5" for
|
|
326
|
+
* that case until this was written, which is the third transaction and the
|
|
327
|
+
* one wording that can be read two ways.
|
|
328
|
+
*/
|
|
329
|
+
failedIndex: number;
|
|
330
|
+
/** Every transaction in the batch, in the order you sent them. */
|
|
331
|
+
results: BulkEntryResult[];
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Sign-in modes.
|
|
335
|
+
*
|
|
336
|
+
* One, and it is the safe one: `caip122` signs a human-readable CAIP-122 /
|
|
337
|
+
* EIP-4361 string under a non-transaction domain separator, so the signature is
|
|
338
|
+
* cryptographically incapable of being a transaction signature.
|
|
339
|
+
*
|
|
340
|
+
* **`xaman` has been removed.** It signed the `{TransactionType:'SignIn'}`
|
|
341
|
+
* pseudo-transaction, and the property that made it safe — `rippled` has no
|
|
342
|
+
* such type, so the blob is unsubmittable — is exactly why it could not be
|
|
343
|
+
* produced: `ripple-binary-codec` has no `SignIn` either, so serialising one
|
|
344
|
+
* threw, every time, *after* the user had approved. The wallet refuses
|
|
345
|
+
* `mode: 'xaman'` by name rather than silently signing a CAIP-122 message in
|
|
346
|
+
* its place, so an existing Xaman integration gets one clear error instead of a
|
|
347
|
+
* result with no `tx_blob` in it.
|
|
348
|
+
*/
|
|
349
|
+
export type SignInMode = 'caip122';
|
|
350
|
+
export interface SignInParams {
|
|
351
|
+
/** Default, and the only value. */
|
|
352
|
+
mode?: SignInMode;
|
|
353
|
+
/** Human-readable line the wallet shows. At most 512 characters. */
|
|
354
|
+
statement?: string;
|
|
355
|
+
/** The wallet generates one when omitted. At most 128 characters. */
|
|
356
|
+
nonce?: string;
|
|
357
|
+
/**
|
|
358
|
+
* Up to 16 URI strings naming the scope you are asking for.
|
|
359
|
+
*
|
|
360
|
+
* Shown on the approval screen and written into the message's `Resources:`
|
|
361
|
+
* section, so they are part of what the signature covers: rebuild the message
|
|
362
|
+
* with the same list, in the same order, to verify one.
|
|
363
|
+
*/
|
|
364
|
+
resources?: string[];
|
|
365
|
+
}
|
|
366
|
+
export interface SignInResult {
|
|
367
|
+
address: string;
|
|
368
|
+
publicKey: string;
|
|
369
|
+
/** Hex-encoded signature. */
|
|
370
|
+
signature: string;
|
|
371
|
+
/** The exact string that was signed. Rebuild it to verify the signature. */
|
|
372
|
+
message: string;
|
|
373
|
+
}
|
|
374
|
+
export interface JoeyEventMap {
|
|
375
|
+
/** The origin became authorised. */
|
|
376
|
+
connect: {
|
|
377
|
+
accounts: JoeyAccount[];
|
|
378
|
+
chain: JoeyChain | null;
|
|
379
|
+
};
|
|
380
|
+
/** The origin lost authorisation, or the wallet locked. */
|
|
381
|
+
disconnect: {
|
|
382
|
+
reason?: string;
|
|
383
|
+
};
|
|
384
|
+
/** The granted account set changed. Empty means the grant was revoked. */
|
|
385
|
+
accountsChanged: JoeyAccount[];
|
|
386
|
+
/** `null` when the wallet reported a chain this SDK does not recognise. */
|
|
387
|
+
networkChanged: JoeyNetwork | null;
|
|
388
|
+
}
|
|
389
|
+
export type JoeyEventName = keyof JoeyEventMap;
|
|
390
|
+
export type JoeyEventListener<K extends JoeyEventName> = (payload: JoeyEventMap[K]) => void;
|
|
391
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for `@joeywallet/wallet-sdk`.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the injected provider's surface field for field
|
|
5
|
+
* (`apps/extension/src/provider/`). Where the two could drift, the provider
|
|
6
|
+
* wins: this package is a convenience layer, not a second definition of the
|
|
7
|
+
* protocol.
|
|
8
|
+
*
|
|
9
|
+
* Nothing here imports from `xrpl`. A published `.d.ts` that did would fail to
|
|
10
|
+
* resolve for the (many) dapps that talk to a wallet without depending on
|
|
11
|
+
* xrpl.js, and `skipLibCheck` only hides that, it does not fix it. Instead the
|
|
12
|
+
* transaction argument of every signing method is generic over
|
|
13
|
+
* {@link TransactionLike}, so a caller who *does* have xrpl.js can pass a
|
|
14
|
+
* `Payment` / `TrustSet` / `SubmittableTransaction` and keep full checking on
|
|
15
|
+
* their own side. `test/xrpl-types.test.ts` pins that assignability against the
|
|
16
|
+
* real xrpl.js types.
|
|
17
|
+
*/
|
|
18
|
+
/* ------------------------------------------------------------------- chains */
|
|
19
|
+
/** CAIP-2 chain ids, as XLS-72d defines them. Mainnet 0, testnet 1, devnet 2. */
|
|
20
|
+
export const JOEY_CHAINS = ['xrpl:0', 'xrpl:1', 'xrpl:2'];
|
|
21
|
+
export function isJoeyChain(value) {
|
|
22
|
+
return typeof value === 'string' && JOEY_CHAINS.includes(value);
|
|
23
|
+
}
|
|
24
|
+
/** `xrpl:0` for network id 0, and so on. Throws for anything else. */
|
|
25
|
+
export function chainForNetworkId(networkId) {
|
|
26
|
+
const chain = `xrpl:${networkId}`;
|
|
27
|
+
if (!isJoeyChain(chain)) {
|
|
28
|
+
throw new RangeError(`Unrecognised XRPL network id: ${networkId}`);
|
|
29
|
+
}
|
|
30
|
+
return chain;
|
|
31
|
+
}
|
|
32
|
+
/** The `NetworkID` a chain id refers to, or `null` when it is not an XRPL chain. */
|
|
33
|
+
export function networkIdForChain(chain) {
|
|
34
|
+
if (!isJoeyChain(chain))
|
|
35
|
+
return null;
|
|
36
|
+
return Number(chain.slice('xrpl:'.length));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,gFAAgF;AAEhF,iFAAiF;AACjF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAA;AAYlE,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,WAAiC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AACxF,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IACjD,MAAM,KAAK,GAAG,QAAQ,SAAS,EAAE,CAAA;IACjC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,UAAU,CAAC,iCAAiC,SAAS,EAAE,CAAC,CAAA;IACpE,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACpC,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;AAC5C,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@joeywallet/wallet-sdk/vanilla`.
|
|
3
|
+
*
|
|
4
|
+
* A connection session with a subscribe/getState store, for pages that have no
|
|
5
|
+
* framework. It holds the two pieces of state every dapp ends up re-writing by
|
|
6
|
+
* hand — the connected account and the current network — and keeps them correct
|
|
7
|
+
* when the user switches account or network in the wallet.
|
|
8
|
+
*/
|
|
9
|
+
import type { Joey } from './client.js';
|
|
10
|
+
import { JoeyRpcError } from './errors.js';
|
|
11
|
+
import type { ConnectParams, JoeyNetwork } from './types.js';
|
|
12
|
+
export interface JoeySessionState {
|
|
13
|
+
/** `null` while detection is still running, and if it never finds a provider. */
|
|
14
|
+
joey: Joey | null;
|
|
15
|
+
isAvailable: boolean;
|
|
16
|
+
isReady: boolean;
|
|
17
|
+
isConnecting: boolean;
|
|
18
|
+
accounts: string[];
|
|
19
|
+
/** The first granted address. `null` when this origin has no grant. */
|
|
20
|
+
account: string | null;
|
|
21
|
+
network: JoeyNetwork | null;
|
|
22
|
+
error: JoeyRpcError | null;
|
|
23
|
+
}
|
|
24
|
+
export interface JoeySession {
|
|
25
|
+
getState(): JoeySessionState;
|
|
26
|
+
/** Called immediately with the current state, then on every change. */
|
|
27
|
+
subscribe(listener: (state: JoeySessionState) => void): () => void;
|
|
28
|
+
connect(params?: ConnectParams): Promise<string | null>;
|
|
29
|
+
disconnect(): Promise<void>;
|
|
30
|
+
/** Removes every listener this session registered. */
|
|
31
|
+
destroy(): void;
|
|
32
|
+
}
|
|
33
|
+
export interface CreateJoeySessionOptions {
|
|
34
|
+
/** Try a silent reconnect once the provider is found. Default true. */
|
|
35
|
+
autoConnect?: boolean;
|
|
36
|
+
/** How long to wait for a late-injected provider. Default 3000ms. */
|
|
37
|
+
detectTimeoutMs?: number;
|
|
38
|
+
}
|
|
39
|
+
export declare function createJoeySession(options?: CreateJoeySessionOptions): JoeySession;
|
|
40
|
+
export interface BindConnectButtonOptions {
|
|
41
|
+
/** Text while disconnected. Default "Connect Joey". */
|
|
42
|
+
connectLabel?: string;
|
|
43
|
+
/** Rendered with the connected address. Default is a truncated address. */
|
|
44
|
+
connectedLabel?(address: string): string;
|
|
45
|
+
/** Text when no provider was found. Default "Install Joey". */
|
|
46
|
+
notInstalledLabel?: string;
|
|
47
|
+
/** Where to send a user with no wallet. Opened in a new tab when clicked. */
|
|
48
|
+
installUrl?: string;
|
|
49
|
+
onError?(error: JoeyRpcError): void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Wire a `<button>` to a session: label, disabled state and click handler.
|
|
53
|
+
*
|
|
54
|
+
* The whole point of the vanilla entry point — this is the twenty lines every
|
|
55
|
+
* script-tag dapp writes, and gets subtly wrong around the not-installed case.
|
|
56
|
+
*/
|
|
57
|
+
export declare function bindConnectButton(button: HTMLButtonElement, session: JoeySession, options?: BindConnectButtonOptions): () => void;
|
|
58
|
+
//# sourceMappingURL=vanilla.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vanilla.d.ts","sourceRoot":"","sources":["../src/vanilla.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAEvC,OAAO,EAAoB,YAAY,EAAE,MAAM,aAAa,CAAA;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE5D,MAAM,WAAW,gBAAgB;IAC/B,iFAAiF;IACjF,IAAI,EAAE,IAAI,GAAG,IAAI,CAAA;IACjB,WAAW,EAAE,OAAO,CAAA;IACpB,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,OAAO,CAAA;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,uEAAuE;IACvE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,OAAO,EAAE,WAAW,GAAG,IAAI,CAAA;IAC3B,KAAK,EAAE,YAAY,GAAG,IAAI,CAAA;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,IAAI,gBAAgB,CAAA;IAC5B,uEAAuE;IACvE,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAA;IAClE,OAAO,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IACvD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,sDAAsD;IACtD,OAAO,IAAI,IAAI,CAAA;CAChB;AAED,MAAM,WAAW,wBAAwB;IACvC,uEAAuE;IACvE,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,qEAAqE;IACrE,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,WAAW,CA+HrF;AAED,MAAM,WAAW,wBAAwB;IACvC,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,2EAA2E;IAC3E,cAAc,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAA;IACxC,+DAA+D;IAC/D,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAA;CACpC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,WAAW,EACpB,OAAO,GAAE,wBAA6B,GACrC,MAAM,IAAI,CA4CZ"}
|
package/dist/vanilla.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { getJoey, waitForJoey } from './detect.js';
|
|
2
|
+
import { JOEY_ERROR_CODES, JoeyRpcError } from './errors.js';
|
|
3
|
+
export function createJoeySession(options = {}) {
|
|
4
|
+
const { autoConnect = true, detectTimeoutMs = 3000 } = options;
|
|
5
|
+
const initial = getJoey();
|
|
6
|
+
let state = {
|
|
7
|
+
joey: initial,
|
|
8
|
+
isAvailable: initial !== null,
|
|
9
|
+
isReady: initial !== null,
|
|
10
|
+
isConnecting: false,
|
|
11
|
+
accounts: [],
|
|
12
|
+
account: null,
|
|
13
|
+
network: null,
|
|
14
|
+
error: null,
|
|
15
|
+
};
|
|
16
|
+
const listeners = new Set();
|
|
17
|
+
const teardown = [];
|
|
18
|
+
let destroyed = false;
|
|
19
|
+
const set = (patch) => {
|
|
20
|
+
const next = { ...state, ...patch };
|
|
21
|
+
// `account` is always derived, never set directly, so the two can't drift.
|
|
22
|
+
next.account = next.accounts[0] ?? null;
|
|
23
|
+
state = next;
|
|
24
|
+
for (const listener of listeners)
|
|
25
|
+
listener(state);
|
|
26
|
+
};
|
|
27
|
+
const attach = (joey) => {
|
|
28
|
+
teardown.push(joey.on('accountsChanged', (accounts) => set({ accounts: accounts.map((account) => account.address) })));
|
|
29
|
+
teardown.push(joey.on('networkChanged', (network) => set({ network })));
|
|
30
|
+
teardown.push(joey.on('connect', (result) => set({ accounts: result.accounts.map((account) => account.address) })));
|
|
31
|
+
teardown.push(joey.on('disconnect', () => set({ accounts: [] })));
|
|
32
|
+
};
|
|
33
|
+
const hydrate = async (joey) => {
|
|
34
|
+
const [accounts, network] = await Promise.all([
|
|
35
|
+
joey.getAccounts().catch(() => []),
|
|
36
|
+
joey.getNetwork().catch(() => null),
|
|
37
|
+
]);
|
|
38
|
+
if (!destroyed)
|
|
39
|
+
set({ accounts, network });
|
|
40
|
+
};
|
|
41
|
+
const adopt = async (joey) => {
|
|
42
|
+
if (destroyed)
|
|
43
|
+
return;
|
|
44
|
+
set({ joey, isAvailable: true, isReady: true });
|
|
45
|
+
attach(joey);
|
|
46
|
+
if (autoConnect) {
|
|
47
|
+
try {
|
|
48
|
+
const result = await joey.connect({ silent: true });
|
|
49
|
+
if (destroyed)
|
|
50
|
+
return;
|
|
51
|
+
if (result.accounts.length > 0) {
|
|
52
|
+
set({ accounts: result.accounts.map((account) => account.address) });
|
|
53
|
+
const network = await joey.getNetwork().catch(() => null);
|
|
54
|
+
if (!destroyed)
|
|
55
|
+
set({ network });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Not yet authorised. Expected on a first visit.
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
await hydrate(joey);
|
|
64
|
+
};
|
|
65
|
+
if (initial !== null) {
|
|
66
|
+
void adopt(initial);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
void waitForJoey({ timeoutMs: detectTimeoutMs })
|
|
70
|
+
.then(adopt)
|
|
71
|
+
.catch(() => {
|
|
72
|
+
if (!destroyed)
|
|
73
|
+
set({ isReady: true });
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
getState: () => state,
|
|
78
|
+
subscribe(listener) {
|
|
79
|
+
listeners.add(listener);
|
|
80
|
+
listener(state);
|
|
81
|
+
return () => listeners.delete(listener);
|
|
82
|
+
},
|
|
83
|
+
async connect(params) {
|
|
84
|
+
const joey = state.joey ?? getJoey();
|
|
85
|
+
if (joey === null) {
|
|
86
|
+
const error = new JoeyRpcError(JOEY_ERROR_CODES.DISCONNECTED, 'Joey Wallet is not installed, or its provider has not been injected into this page.');
|
|
87
|
+
set({ error });
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
set({ isConnecting: true, error: null });
|
|
91
|
+
try {
|
|
92
|
+
const result = await joey.connect(params);
|
|
93
|
+
const accounts = result.accounts.map((account) => account.address);
|
|
94
|
+
const network = await joey.getNetwork().catch(() => state.network);
|
|
95
|
+
set({ accounts, network, isConnecting: false });
|
|
96
|
+
return accounts[0] ?? null;
|
|
97
|
+
}
|
|
98
|
+
catch (cause) {
|
|
99
|
+
const error = JoeyRpcError.from(cause);
|
|
100
|
+
set({ isConnecting: false, error });
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
async disconnect() {
|
|
105
|
+
const joey = state.joey;
|
|
106
|
+
if (joey === null)
|
|
107
|
+
return;
|
|
108
|
+
await joey.disconnect();
|
|
109
|
+
set({ accounts: [] });
|
|
110
|
+
},
|
|
111
|
+
destroy() {
|
|
112
|
+
destroyed = true;
|
|
113
|
+
for (const off of teardown.splice(0))
|
|
114
|
+
off();
|
|
115
|
+
listeners.clear();
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Wire a `<button>` to a session: label, disabled state and click handler.
|
|
121
|
+
*
|
|
122
|
+
* The whole point of the vanilla entry point — this is the twenty lines every
|
|
123
|
+
* script-tag dapp writes, and gets subtly wrong around the not-installed case.
|
|
124
|
+
*/
|
|
125
|
+
export function bindConnectButton(button, session, options = {}) {
|
|
126
|
+
const { connectLabel = 'Connect Joey', connectedLabel = (address) => `${address.slice(0, 6)}…${address.slice(-4)}`, notInstalledLabel = 'Install Joey', installUrl, onError, } = options;
|
|
127
|
+
const render = (state) => {
|
|
128
|
+
if (!state.isReady) {
|
|
129
|
+
button.disabled = true;
|
|
130
|
+
button.textContent = connectLabel;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (!state.isAvailable) {
|
|
134
|
+
button.disabled = installUrl === undefined;
|
|
135
|
+
button.textContent = notInstalledLabel;
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
button.disabled = state.isConnecting;
|
|
139
|
+
button.textContent = state.account !== null ? connectedLabel(state.account) : connectLabel;
|
|
140
|
+
};
|
|
141
|
+
const onClick = () => {
|
|
142
|
+
const state = session.getState();
|
|
143
|
+
if (!state.isAvailable) {
|
|
144
|
+
if (installUrl !== undefined)
|
|
145
|
+
window.open(installUrl, '_blank', 'noopener,noreferrer');
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
// `session.connect` already stored the error in state; this catch only
|
|
149
|
+
// exists so the rejection is not unhandled.
|
|
150
|
+
void session.connect().catch((error) => {
|
|
151
|
+
onError?.(JoeyRpcError.from(error));
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
button.addEventListener('click', onClick);
|
|
155
|
+
const unsubscribe = session.subscribe(render);
|
|
156
|
+
return () => {
|
|
157
|
+
button.removeEventListener('click', onClick);
|
|
158
|
+
unsubscribe();
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=vanilla.js.map
|