@phala/pay 0.10.10 → 0.11.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/README.md +99 -11
- package/dist/chains.d.ts +4 -0
- package/dist/chains.d.ts.map +1 -1
- package/dist/chains.js +12 -1
- package/dist/chains.js.map +1 -1
- package/dist/icon-names.d.ts +4 -0
- package/dist/icon-names.d.ts.map +1 -1
- package/dist/icon-names.js +20 -7
- package/dist/icon-names.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/options.d.ts +30 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +20 -0
- package/dist/options.js.map +1 -0
- package/package.json +1 -1
- package/src/chains.ts +15 -1
- package/src/icon-names.ts +24 -8
- package/src/index.ts +10 -2
- package/src/options.ts +54 -0
package/README.md
CHANGED
|
@@ -57,6 +57,9 @@ connects a wallet with wagmi, RainbowKit, ConnectKit, or AppKit, pass it in inst
|
|
|
57
57
|
3. Credit the account when your webhook endpoint receives `deposit.credited`. `onSuccess` is for the
|
|
58
58
|
UI only: the browser is not a trusted source of payment.
|
|
59
59
|
|
|
60
|
+
To let the payer choose the token and network first and create the quote only when they submit,
|
|
61
|
+
render [`<PaymentElement>`](#the-payment-element) instead.
|
|
62
|
+
|
|
60
63
|
The component reads `GET /v1/quotes/{id}?client_secret=…` about every three seconds. That endpoint is
|
|
61
64
|
public (`Access-Control-Allow-Origin: *`) and shows only what the payer needs: the amount, the
|
|
62
65
|
token, the chain, the deposit address, the EIP-681 payment request, the expiry, and the payment
|
|
@@ -154,12 +157,95 @@ export function TopUp(props: { clientSecret: string; expectedAddress: string })
|
|
|
154
157
|
While no wallet is connected (`walletClient` is `undefined`), the tab lists the browser's wallets
|
|
155
158
|
as usual. The QR code and manual tabs do not change.
|
|
156
159
|
|
|
160
|
+
### The payment element
|
|
161
|
+
|
|
162
|
+
`<PaymentElement>` is the whole payment in one component, like Stripe's Payment Element with a
|
|
163
|
+
deferred intent: it offers your tokens and networks, creates nothing until the payer submits, then
|
|
164
|
+
calls your `createQuote` with the chosen option and an idempotency key, and shows that quote's
|
|
165
|
+
`<Checkout>`. Your backend creates the quote with its API key, for the chosen `chain_id` and
|
|
166
|
+
`asset`, with that key as its `Idempotency-Key`, and returns its checkout params
|
|
167
|
+
(`pay.checkoutParams(quote)` in `@phala/pay-server`).
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
import { paymentOptions } from "@phala/pay";
|
|
171
|
+
import { PaymentElement } from "@phala/pay-react";
|
|
172
|
+
|
|
173
|
+
<PaymentElement
|
|
174
|
+
options={paymentOptions(config.assets)} // GET /v1/config's assets, from your backend
|
|
175
|
+
amount={2500} // minor units of `currency` (default "usd"): "Pay $25.00 in USDC"
|
|
176
|
+
createQuote={(option, { idempotencyKey }) =>
|
|
177
|
+
api.createTopUp({ amount: 2500, chain_id: option.chain_id, asset: option.asset, idempotencyKey })
|
|
178
|
+
}
|
|
179
|
+
createDepositAddress={() => api.depositAddress()} // optional: "Use a deposit address"
|
|
180
|
+
apiBase="https://pay.example.com"
|
|
181
|
+
renderDetail={(option) => (option.asset === "usdc" ? "$1.00" : "Market rate")}
|
|
182
|
+
onSuccess={() => router.refresh()}
|
|
183
|
+
/>;
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
- `createQuote(option, { idempotencyKey })` is called once per submit, with the very object of
|
|
187
|
+
`options` the payer chose; a submit while one is pending is ignored. It resolves with
|
|
188
|
+
`{ clientSecret, expectedAddress, apiBase? }`; `apiBase` falls back to the prop. A rejection
|
|
189
|
+
shows "Could not start the payment. Try again." and calls `onError(error)`; show your own
|
|
190
|
+
message from there.
|
|
191
|
+
- Create the quote with `idempotencyKey` as its `Idempotency-Key`, not an order id of yours: the
|
|
192
|
+
key is a new random UUID for each quote the payer asks for (another option or amount, or a new
|
|
193
|
+
quote after going back from one) and the same only when they retry after `createQuote` failed
|
|
194
|
+
with the same option, `amount`, and `currency`, so that a retry returns the quote a lost response
|
|
195
|
+
created. One key per order would answer another option with `400 idempotency_key_reused`, and a
|
|
196
|
+
new quote with the expired one. If your quote varies by anything else between attempts (a field
|
|
197
|
+
of your own form, say), pass it as `amount` or give the element a new `key` when it changes, or
|
|
198
|
+
a retry would reuse a key with another body.
|
|
199
|
+
- After the quote: the checkout, and a way back to the options ("Choose another token or
|
|
200
|
+
network") until a payment is on its way, then "Start over" if it does not complete or "Start a
|
|
201
|
+
new payment" once credited.
|
|
202
|
+
- `createDepositAddress(option)` adds "Use a deposit address", for payers sending from an exchange
|
|
203
|
+
or any wallet: it resolves with the deposit address's `address` and `networks` and, to follow its
|
|
204
|
+
payments, `clientSecret`; the element shows `<DepositAddress>` at the chosen option.
|
|
205
|
+
- Your own button: pass `hideSubmit` and an `id`, and give your button `type="submit" form={id}`
|
|
206
|
+
(or call `requestSubmit()` on the form with that id). The element is a `<form>`: do not nest it
|
|
207
|
+
in another one.
|
|
208
|
+
- `value` and `onOptionChange` control the choice (`defaultValue` sets the first one otherwise);
|
|
209
|
+
`onChange({ step, checkout })` reports each step (`options`, `creating`, `checkout`,
|
|
210
|
+
`deposit_address`) and, while paying, each checkout status change; `onSuccess`, `onExpire`,
|
|
211
|
+
`onWalletError`, `walletClient`, `pollInterval`, and `appearance` are `<Checkout>`'s.
|
|
212
|
+
|
|
213
|
+
### Payment options
|
|
214
|
+
|
|
215
|
+
`<PaymentOptionPicker>` is the element's choice on its own, as exchanges and wallets ask for it:
|
|
216
|
+
a "Token" field, then a "Network" field listing only the networks that take the chosen token,
|
|
217
|
+
side by side where the container is 480px or wider and stacked below that. Each is a select-only
|
|
218
|
+
combobox (WAI-ARIA Authoring Practices): a quiet field showing the chosen item's icon and name,
|
|
219
|
+
whose listbox opens under it (over it where there is more room above), by pointer or keyboard
|
|
220
|
+
(arrows, Home, End, Page Up and Down, typing the name, Enter or Space to choose, Escape or a
|
|
221
|
+
press elsewhere to close); its label focuses it. Where the browser has popovers, the open listbox
|
|
222
|
+
is in the top layer, so a card or modal with `overflow: hidden` does not clip it, while it stays
|
|
223
|
+
inside your dialog in the document (a modal library does not take a press on it for one outside
|
|
224
|
+
the dialog). Changing the token keeps the network
|
|
225
|
+
when it takes the new token, else takes the first that does. A test network shows a muted
|
|
226
|
+
"Testnet" after its name; `renderDetail(option)` is one muted line under the fields, about the
|
|
227
|
+
chosen option. Both fields show even with one option. It is controlled (`value`, `onChange`), and
|
|
228
|
+
`onChange` receives the very object of `options` the payer chose; `label` (default "Pay with")
|
|
229
|
+
names the group for assistive technology.
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
<PaymentOptionPicker options={options} value={option} onChange={setOption} label="Pay with" />
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
`paymentOptions(source)` builds the options, in order and each once: from a flat list such as
|
|
236
|
+
`GET /v1/config`'s `assets` (the same objects), or from networks with their tokens such as a
|
|
237
|
+
deposit address's `networks` (each option then carries its `network` and `token`).
|
|
238
|
+
`samePaymentOption(a, b)` compares by chain and case-insensitive asset code;
|
|
239
|
+
`paymentOptionLabel(option)` is `USDC · Ethereum`; `assetName("usdc")` is `USD Coin`,
|
|
240
|
+
`assetSymbol` the upper-case code, `networkName(chainId)` the chain's name, `isTestnet(chainId)`
|
|
241
|
+
whether it is a known test network, and `transactionUrl` / `addressUrl` its block explorer links.
|
|
242
|
+
|
|
157
243
|
### A customer's deposit address
|
|
158
244
|
|
|
159
245
|
For top-ups within your deposit limits, your backend creates the customer's persistent deposit address with
|
|
160
246
|
`POST /v1/deposit_addresses` (its API key) and passes its `address` and `networks` to the page:
|
|
161
|
-
one address for all supported tokens and networks. `<DepositAddress>` lets the payer pick a
|
|
162
|
-
network
|
|
247
|
+
one address for all supported tokens and networks. `<DepositAddress>` lets the payer pick a token
|
|
248
|
+
and its network (the payment options' two fields, shown even when there is only one of each) and shows a QR code of that token's transfer request, the token contract, and
|
|
163
249
|
the address to copy, with the selected token’s per-transfer USD credit minimum (`min_amount`,
|
|
164
250
|
in cents) and token maximum (`max_deposit_atomic`). A positive `min_deposit_atomic` adds the
|
|
165
251
|
independent token minimum; a zero atomic minimum is omitted. Atomic-unit strings are formatted
|
|
@@ -223,14 +309,14 @@ the theme (or map the colors) that suits its background.
|
|
|
223
309
|
|
|
224
310
|
| CSS custom property | Light default | Dark default | Use |
|
|
225
311
|
| ------------------------------- | ----------------- | ------------ | --------------------------------------------------- |
|
|
226
|
-
| `--pp-color-surface` | `#f4f4f5` | `#18181b` | Status row,
|
|
312
|
+
| `--pp-color-surface` | `#f4f4f5` | `#18181b` | Status row, placeholders, listboxes, copy hover |
|
|
227
313
|
| `--pp-color-text` | `#18181b` | `#fafafa` | Text |
|
|
228
314
|
| `--pp-color-text-muted` | `#52525b` | `#a1a1aa` | Labels, hints, in-progress status icon |
|
|
229
315
|
| `--pp-color-border` | `#e4e4e7` | `#27272a` | Dividers and the QR code's frame |
|
|
230
|
-
| `--pp-color-input` | `#8a8a93` | `#71717a` | Edges of the
|
|
316
|
+
| `--pp-color-input` | `#8a8a93` | `#71717a` | Edges of the token and network fields |
|
|
231
317
|
| `--pp-color-primary` | `#171717` | `#fafafa` | Pay button |
|
|
232
318
|
| `--pp-color-primary-foreground` | `#fafafa` | `#18181b` | Text on the primary color |
|
|
233
|
-
| `--pp-color-selected` | primary | primary | Selected tab's underline
|
|
319
|
+
| `--pp-color-selected` | primary | primary | Selected tab's underline |
|
|
234
320
|
| `--pp-color-focus` | `#2563eb` | `#60a5fa` | Keyboard focus ring |
|
|
235
321
|
| `--pp-color-success` | `#15803d` | `#4ade80` | Credited icon |
|
|
236
322
|
| `--pp-color-warning` | `#b45309` | `#fbbf24` | "Test mode" |
|
|
@@ -239,7 +325,7 @@ the theme (or map the colors) that suits its background.
|
|
|
239
325
|
| `--pp-font-family-mono` | `ui-monospace, …` | same | Addresses, amounts to copy, hashes |
|
|
240
326
|
| `--pp-font-size` | `14px` | `14px` | Root text size; other text sizes are relative to it |
|
|
241
327
|
| `--pp-radius` | `8px` | `8px` | Corner radius of controls and the status row |
|
|
242
|
-
| `--pp-control-height` | `44px` | `44px` | Minimum height of
|
|
328
|
+
| `--pp-control-height` | `44px` | `44px` | Minimum height of buttons, tabs, and fields |
|
|
243
329
|
|
|
244
330
|
Import the static stylesheet once in your application entry point:
|
|
245
331
|
|
|
@@ -287,13 +373,15 @@ group by group with what their wallet shows; selecting and copying it gives the
|
|
|
287
373
|
spaces. The QR code keeps the standard quiet zone of four modules inside 8px of white, so it scans
|
|
288
374
|
on a dark page too. The status row's text stays the body color on a neutral surface; its icon
|
|
289
375
|
carries the tone. Transitions and the loading placeholder's pulse stop under
|
|
290
|
-
`prefers-reduced-motion: reduce`, and the selected
|
|
291
|
-
forced-colors mode.
|
|
376
|
+
`prefers-reduced-motion: reduce`, and the selected tab and a listbox's active option keep a system
|
|
377
|
+
color in forced-colors mode.
|
|
292
378
|
|
|
293
379
|
### Content Security Policy
|
|
294
380
|
|
|
295
|
-
The components inject no style elements or style attributes. Serve the bundled
|
|
296
|
-
own origin with `style-src 'self'`; no `unsafe-inline` style permission is needed.
|
|
381
|
+
The components inject no style elements or style attributes in their markup. Serve the bundled
|
|
382
|
+
CSS from your own origin with `style-src 'self'`; no `unsafe-inline` style permission is needed.
|
|
383
|
+
An open token or network listbox is placed beside its field through the CSSOM
|
|
384
|
+
(`element.style.setProperty`), which that policy allows. Allow the
|
|
297
385
|
payment service origin in `connect-src` for public status reads and `img-src data:` for browser
|
|
298
386
|
wallet icons. Configure script and font sources for your application's own bundles.
|
|
299
387
|
|
|
@@ -340,7 +428,7 @@ holding less of the token than that sends nothing: `WalletError` with `code`
|
|
|
340
428
|
|
|
341
429
|
## React components
|
|
342
430
|
|
|
343
|
-
Install `@phala/pay-react` for `Checkout`, `DepositAddress`, hooks, icons, and styles:
|
|
431
|
+
Install `@phala/pay-react` for `PaymentElement`, `Checkout`, `DepositAddress`, `PaymentOptionPicker`, hooks, icons, and styles:
|
|
344
432
|
|
|
345
433
|
```sh
|
|
346
434
|
npm install @phala/pay-react react react-dom @phala/pay viem
|
package/dist/chains.d.ts
CHANGED
|
@@ -4,6 +4,10 @@ export declare function networkIconName(chainId: number): "ethereum" | "base" |
|
|
|
4
4
|
export declare function knownChain(chainId: number): Chain | undefined;
|
|
5
5
|
/** A human name for the network, for example `Sepolia`. */
|
|
6
6
|
export declare function networkName(chainId: number): string;
|
|
7
|
+
/** Whether the chain is a known test network, such as Sepolia; false for an unknown chain. */
|
|
8
|
+
export declare function isTestnet(chainId: number): boolean;
|
|
7
9
|
/** The block explorer link for a transaction, when the chain is known. */
|
|
8
10
|
export declare function transactionUrl(chainId: number, hash: string): string | undefined;
|
|
11
|
+
/** The block explorer link for an address or token contract, when the chain is known. */
|
|
12
|
+
export declare function addressUrl(chainId: number, address: string): string | undefined;
|
|
9
13
|
//# sourceMappingURL=chains.d.ts.map
|
package/dist/chains.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chains.d.ts","sourceRoot":"","sources":["../src/chains.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAWlC,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAEhF;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAE7D;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"chains.d.ts","sourceRoot":"","sources":["../src/chains.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAWlC,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAEhF;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAE7D;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,8FAA8F;AAC9F,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAElD;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEhF;AAED,yFAAyF;AACzF,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE/E"}
|
package/dist/chains.js
CHANGED
|
@@ -17,9 +17,20 @@ export function knownChain(chainId) {
|
|
|
17
17
|
export function networkName(chainId) {
|
|
18
18
|
return knownChain(chainId)?.name ?? `Chain ${chainId}`;
|
|
19
19
|
}
|
|
20
|
+
/** Whether the chain is a known test network, such as Sepolia; false for an unknown chain. */
|
|
21
|
+
export function isTestnet(chainId) {
|
|
22
|
+
return knownChain(chainId)?.testnet === true;
|
|
23
|
+
}
|
|
20
24
|
/** The block explorer link for a transaction, when the chain is known. */
|
|
21
25
|
export function transactionUrl(chainId, hash) {
|
|
26
|
+
return explorerUrl(chainId, "tx", hash);
|
|
27
|
+
}
|
|
28
|
+
/** The block explorer link for an address or token contract, when the chain is known. */
|
|
29
|
+
export function addressUrl(chainId, address) {
|
|
30
|
+
return explorerUrl(chainId, "address", address);
|
|
31
|
+
}
|
|
32
|
+
function explorerUrl(chainId, kind, value) {
|
|
22
33
|
const explorer = knownChain(chainId)?.blockExplorers?.default.url;
|
|
23
|
-
return explorer === undefined ? undefined : `${explorer}
|
|
34
|
+
return explorer === undefined ? undefined : `${explorer}/${kind}/${value}`;
|
|
24
35
|
}
|
|
25
36
|
//# sourceMappingURL=chains.js.map
|
package/dist/chains.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chains.js","sourceRoot":"","sources":["../src/chains.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAElE,0FAA0F;AAC1F,MAAM,MAAM,GAA2D;IACrE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE;IACpC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE;IACpC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE;IAC7B,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE;CACrC,CAAC;AAEF,sEAAsE;AACtE,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,IAAI,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,KAAK,CAAC;AACjE,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,IAAI,SAAS,OAAO,EAAE,CAAC;AACzD,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,IAAY;IAC1D,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC;IAClE,OAAO,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,QAAQ,
|
|
1
|
+
{"version":3,"file":"chains.js","sourceRoot":"","sources":["../src/chains.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAElE,0FAA0F;AAC1F,MAAM,MAAM,GAA2D;IACrE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE;IACpC,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE;IACpC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE;IAC7B,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE;CACrC,CAAC;AAEF,sEAAsE;AACtE,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,IAAI,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,KAAK,CAAC;AACjE,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,OAAO,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,IAAI,SAAS,OAAO,EAAE,CAAC;AACzD,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,OAAO,UAAU,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;AAC/C,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,IAAY;IAC1D,OAAO,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAC1C,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,OAAe;IACzD,OAAO,WAAW,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,WAAW,CAAC,OAAe,EAAE,IAAsB,EAAE,KAAa;IACzE,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC;IAClE,OAAO,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC;AAC7E,CAAC"}
|
package/dist/icon-names.d.ts
CHANGED
|
@@ -2,6 +2,10 @@ import type { ICON_SVG } from "./icon-svg.js";
|
|
|
2
2
|
export type IconName = keyof typeof ICON_SVG;
|
|
3
3
|
/** Case-insensitive token symbol; unrecognized symbols use a neutral monogram. */
|
|
4
4
|
export declare function assetIconName(asset: string): IconName | undefined;
|
|
5
|
+
/** The token's symbol as payers read it, for example `USDC` for `usdc`. */
|
|
6
|
+
export declare function assetSymbol(asset: string): string;
|
|
7
|
+
/** The token's full name, for example `USD Coin`, or its symbol when the SDK does not know it. */
|
|
8
|
+
export declare function assetName(asset: string): string;
|
|
5
9
|
/** First character for a neutral fallback, including an empty-symbol placeholder. */
|
|
6
10
|
export declare function iconMonogram(label: string): string;
|
|
7
11
|
//# sourceMappingURL=icon-names.d.ts.map
|
package/dist/icon-names.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-names.d.ts","sourceRoot":"","sources":["../src/icon-names.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"icon-names.d.ts","sourceRoot":"","sources":["../src/icon-names.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,QAAQ,CAAC;AAe7C,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAEjE;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,kGAAkG;AAClG,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,qFAAqF;AACrF,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD"}
|
package/dist/icon-names.js
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
|
+
/** The tokens the SDK knows, by lowercase code: their icon and full name. */
|
|
2
|
+
const ASSETS = {
|
|
3
|
+
usdc: { icon: "usdc", name: "USD Coin" },
|
|
4
|
+
usdt: { icon: "usdt", name: "Tether USD" },
|
|
5
|
+
pha: { icon: "pha", name: "Phala Network" },
|
|
6
|
+
eth: { icon: "eth", name: "Ether" },
|
|
7
|
+
};
|
|
8
|
+
function knownAsset(asset) {
|
|
9
|
+
const code = asset.trim().toLowerCase();
|
|
10
|
+
return Object.hasOwn(ASSETS, code) ? ASSETS[code] : undefined;
|
|
11
|
+
}
|
|
1
12
|
/** Case-insensitive token symbol; unrecognized symbols use a neutral monogram. */
|
|
2
13
|
export function assetIconName(asset) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
return knownAsset(asset)?.icon;
|
|
15
|
+
}
|
|
16
|
+
/** The token's symbol as payers read it, for example `USDC` for `usdc`. */
|
|
17
|
+
export function assetSymbol(asset) {
|
|
18
|
+
return asset.trim().toUpperCase();
|
|
19
|
+
}
|
|
20
|
+
/** The token's full name, for example `USD Coin`, or its symbol when the SDK does not know it. */
|
|
21
|
+
export function assetName(asset) {
|
|
22
|
+
return knownAsset(asset)?.name ?? assetSymbol(asset);
|
|
10
23
|
}
|
|
11
24
|
/** First character for a neutral fallback, including an empty-symbol placeholder. */
|
|
12
25
|
export function iconMonogram(label) {
|
package/dist/icon-names.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon-names.js","sourceRoot":"","sources":["../src/icon-names.ts"],"names":[],"mappings":"AAIA,
|
|
1
|
+
{"version":3,"file":"icon-names.js","sourceRoot":"","sources":["../src/icon-names.ts"],"names":[],"mappings":"AAIA,6EAA6E;AAC7E,MAAM,MAAM,GAA+D;IACzE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE;IACxC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE;IAC1C,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE;IAC3C,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE;CACpC,CAAC;AAEF,SAAS,UAAU,CAAC,KAAa;IAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACxC,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAChE,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;AACjC,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACpC,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC;AACvD,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,GAAG,CAAC;AAC3D,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
export { CheckoutError, checkoutStatus, pollDelay, createCheckout, retrieveQuote, type CheckoutErrorCode, type CheckoutErrorOptions, type CheckoutOptions, type CheckoutSession, type CheckoutState, type CheckoutStatus, type RetrieveQuoteOptions, } from "./checkout.js";
|
|
2
2
|
export { PhalaPay, type PhalaPayOptions } from "./client.js";
|
|
3
3
|
export { depositAddressIdFromClientSecret, parseClientDepositAddress, retrieveDepositAddress, type ClientDepositAddress, type ClientDepositAddressNetwork, type DepositAddressPayment, type RetrieveDepositAddressOptions, } from "./deposit-address.js";
|
|
4
|
-
export { knownChain, networkName, transactionUrl, networkIconName } from "./chains.js";
|
|
4
|
+
export { addressUrl, isTestnet, knownChain, networkName, transactionUrl, networkIconName } from "./chains.js";
|
|
5
5
|
export { formatAmount, formatCountdown, formatMinorAmount, formatTokenAmount, formatUnitsGrouped, formatWait, tokenAmount } from "./format.js";
|
|
6
6
|
export { depositAddressTransfer, parseTransferUri, quoteTransfer, type DepositAddressAsset, type DepositAddressDetails, type DepositAddressNetwork, type TokenTransfer, type TransferRequest, } from "./payment.js";
|
|
7
7
|
export { parseClientQuote, quoteIdFromClientSecret, type ClientQuote } from "./quote.js";
|
|
8
|
-
export { assetIconName, iconMonogram, type IconName } from "./icon-names.js";
|
|
8
|
+
export { assetIconName, assetName, assetSymbol, iconMonogram, type IconName } from "./icon-names.js";
|
|
9
|
+
export { paymentOptionLabel, paymentOptions, samePaymentOption, type NetworkPaymentOption, type PaymentNetwork, type PaymentOption, } from "./options.js";
|
|
9
10
|
export { INJECTED_WALLET_UUID, WalletError, payWithWallet, watchWallets, type EthereumProvider, type Wallet, type WalletErrorCode, type WalletInfo, } from "./wallet.js";
|
|
10
11
|
export { networkIcon, assetIcon } from "./icons.js";
|
|
11
12
|
export type { CheckoutParams } from "./shared/checkout-params.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,SAAS,EACT,cAAc,EACd,aAAa,EACb,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,oBAAoB,GAC1B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EACL,gCAAgC,EAChC,yBAAyB,EACzB,sBAAsB,EACtB,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,GACnC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,SAAS,EACT,cAAc,EACd,aAAa,EACb,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,oBAAoB,GAC1B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EACL,gCAAgC,EAChC,yBAAyB,EACzB,sBAAsB,EACtB,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,GACnC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9G,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/I,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,aAAa,EACb,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAClB,KAAK,eAAe,GACrB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACrG,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,aAAa,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,MAAM,EACX,KAAK,eAAe,EACpB,KAAK,UAAU,GAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACpD,YAAY,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,OAAO,EAAE,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
export { CheckoutError, checkoutStatus, pollDelay, createCheckout, retrieveQuote, } from "./checkout.js";
|
|
2
2
|
export { PhalaPay } from "./client.js";
|
|
3
3
|
export { depositAddressIdFromClientSecret, parseClientDepositAddress, retrieveDepositAddress, } from "./deposit-address.js";
|
|
4
|
-
export { knownChain, networkName, transactionUrl, networkIconName } from "./chains.js";
|
|
4
|
+
export { addressUrl, isTestnet, knownChain, networkName, transactionUrl, networkIconName } from "./chains.js";
|
|
5
5
|
export { formatAmount, formatCountdown, formatMinorAmount, formatTokenAmount, formatUnitsGrouped, formatWait, tokenAmount } from "./format.js";
|
|
6
6
|
export { depositAddressTransfer, parseTransferUri, quoteTransfer, } from "./payment.js";
|
|
7
7
|
export { parseClientQuote, quoteIdFromClientSecret } from "./quote.js";
|
|
8
|
-
export { assetIconName, iconMonogram } from "./icon-names.js";
|
|
8
|
+
export { assetIconName, assetName, assetSymbol, iconMonogram } from "./icon-names.js";
|
|
9
|
+
export { paymentOptionLabel, paymentOptions, samePaymentOption, } from "./options.js";
|
|
9
10
|
export { INJECTED_WALLET_UUID, WalletError, payWithWallet, watchWallets, } from "./wallet.js";
|
|
10
11
|
export { networkIcon, assetIcon } from "./icons.js";
|
|
11
12
|
export { submitTransaction } from "./transactions.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,SAAS,EACT,cAAc,EACd,aAAa,GAQd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAwB,MAAM,aAAa,CAAC;AAC7D,OAAO,EACL,gCAAgC,EAChC,yBAAyB,EACzB,sBAAsB,GAKvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,SAAS,EACT,cAAc,EACd,aAAa,GAQd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAwB,MAAM,aAAa,CAAC;AAC7D,OAAO,EACL,gCAAgC,EAChC,yBAAyB,EACzB,sBAAsB,GAKvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9G,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/I,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,aAAa,GAMd,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAoB,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAiB,MAAM,iBAAiB,CAAC;AACrG,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,iBAAiB,GAIlB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,aAAa,EACb,YAAY,GAKb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGpD,OAAO,EAAE,iBAAiB,EAAiC,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** A token on a network that a payer can pay with, for example `usdc` on chain 8453. */
|
|
2
|
+
export interface PaymentOption {
|
|
3
|
+
chain_id: number;
|
|
4
|
+
/** The token's code, for example `usdc`. */
|
|
5
|
+
asset: string;
|
|
6
|
+
}
|
|
7
|
+
/** A network with the tokens it takes, as a deposit address's `networks` list them. */
|
|
8
|
+
export interface PaymentNetwork {
|
|
9
|
+
chain_id: number;
|
|
10
|
+
assets: readonly {
|
|
11
|
+
asset: string;
|
|
12
|
+
}[];
|
|
13
|
+
}
|
|
14
|
+
/** One token of a `PaymentNetwork`, with the network and token objects it came from. */
|
|
15
|
+
export type NetworkPaymentOption<N extends PaymentNetwork> = PaymentOption & {
|
|
16
|
+
network: N;
|
|
17
|
+
token: N["assets"][number];
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* The options to offer, in the order given and each once (the first of any duplicate): either a
|
|
21
|
+
* flat list such as `GET /v1/config`'s `assets`, returned as the same objects, or networks with
|
|
22
|
+
* their tokens such as a deposit address's `networks`, flattened network by network.
|
|
23
|
+
*/
|
|
24
|
+
export declare function paymentOptions<T extends PaymentOption>(options: readonly T[]): T[];
|
|
25
|
+
export declare function paymentOptions<N extends PaymentNetwork>(networks: readonly N[]): NetworkPaymentOption<N>[];
|
|
26
|
+
/** Whether `a` and `b` are the same token on the same network; asset codes are case-insensitive. */
|
|
27
|
+
export declare function samePaymentOption(a: PaymentOption | null | undefined, b: PaymentOption | null | undefined): boolean;
|
|
28
|
+
/** The option as one line of text, for example `USDC · Ethereum`. */
|
|
29
|
+
export declare function paymentOptionLabel(option: PaymentOption): string;
|
|
30
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAGA,wFAAwF;AACxF,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACtC;AAED,wFAAwF;AACxF,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,cAAc,IAAI,aAAa,GAAG;IAC3E,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;CAC5B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,aAAa,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AACpF,wBAAgB,cAAc,CAAC,CAAC,SAAS,cAAc,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,GAAG,oBAAoB,CAAC,CAAC,CAAC,EAAE,CAAC;AAY5G,oGAAoG;AACpG,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,EAAE,CAAC,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAOnH;AAED,qEAAqE;AACrE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAEhE"}
|
package/dist/options.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { networkName } from "./chains.js";
|
|
2
|
+
import { assetSymbol } from "./icon-names.js";
|
|
3
|
+
export function paymentOptions(source) {
|
|
4
|
+
const flat = source.flatMap((each) => "assets" in each
|
|
5
|
+
? each.assets.map((token) => ({ chain_id: each.chain_id, asset: token.asset, network: each, token }))
|
|
6
|
+
: [each]);
|
|
7
|
+
return flat.filter((option, index) => flat.findIndex((other) => samePaymentOption(option, other)) === index);
|
|
8
|
+
}
|
|
9
|
+
/** Whether `a` and `b` are the same token on the same network; asset codes are case-insensitive. */
|
|
10
|
+
export function samePaymentOption(a, b) {
|
|
11
|
+
return (a != null &&
|
|
12
|
+
b != null &&
|
|
13
|
+
a.chain_id === b.chain_id &&
|
|
14
|
+
a.asset.trim().toLowerCase() === b.asset.trim().toLowerCase());
|
|
15
|
+
}
|
|
16
|
+
/** The option as one line of text, for example `USDC · Ethereum`. */
|
|
17
|
+
export function paymentOptionLabel(option) {
|
|
18
|
+
return `${assetSymbol(option.asset)} · ${networkName(option.chain_id)}`;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AA4B9C,MAAM,UAAU,cAAc,CAC5B,MAAmD;IAEnD,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CACnC,QAAQ,IAAI,IAAI;QACd,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACrG,CAAC,CAAC,CAAC,IAAI,CAAC,CACX,CAAC;IACF,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC;AAC/G,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,iBAAiB,CAAC,CAAmC,EAAE,CAAmC;IACxG,OAAO,CACL,CAAC,IAAI,IAAI;QACT,CAAC,IAAI,IAAI;QACT,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ;QACzB,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAC9D,CAAC;AACJ,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,kBAAkB,CAAC,MAAqB;IACtD,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC1E,CAAC"}
|
package/package.json
CHANGED
package/src/chains.ts
CHANGED
|
@@ -23,8 +23,22 @@ export function networkName(chainId: number): string {
|
|
|
23
23
|
return knownChain(chainId)?.name ?? `Chain ${chainId}`;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/** Whether the chain is a known test network, such as Sepolia; false for an unknown chain. */
|
|
27
|
+
export function isTestnet(chainId: number): boolean {
|
|
28
|
+
return knownChain(chainId)?.testnet === true;
|
|
29
|
+
}
|
|
30
|
+
|
|
26
31
|
/** The block explorer link for a transaction, when the chain is known. */
|
|
27
32
|
export function transactionUrl(chainId: number, hash: string): string | undefined {
|
|
33
|
+
return explorerUrl(chainId, "tx", hash);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** The block explorer link for an address or token contract, when the chain is known. */
|
|
37
|
+
export function addressUrl(chainId: number, address: string): string | undefined {
|
|
38
|
+
return explorerUrl(chainId, "address", address);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function explorerUrl(chainId: number, kind: "tx" | "address", value: string): string | undefined {
|
|
28
42
|
const explorer = knownChain(chainId)?.blockExplorers?.default.url;
|
|
29
|
-
return explorer === undefined ? undefined : `${explorer}
|
|
43
|
+
return explorer === undefined ? undefined : `${explorer}/${kind}/${value}`;
|
|
30
44
|
}
|
package/src/icon-names.ts
CHANGED
|
@@ -2,19 +2,35 @@ import type { ICON_SVG } from "./icon-svg.js";
|
|
|
2
2
|
|
|
3
3
|
export type IconName = keyof typeof ICON_SVG;
|
|
4
4
|
|
|
5
|
+
/** The tokens the SDK knows, by lowercase code: their icon and full name. */
|
|
6
|
+
const ASSETS: Readonly<Record<string, { icon: IconName; name: string }>> = {
|
|
7
|
+
usdc: { icon: "usdc", name: "USD Coin" },
|
|
8
|
+
usdt: { icon: "usdt", name: "Tether USD" },
|
|
9
|
+
pha: { icon: "pha", name: "Phala Network" },
|
|
10
|
+
eth: { icon: "eth", name: "Ether" },
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
function knownAsset(asset: string) {
|
|
14
|
+
const code = asset.trim().toLowerCase();
|
|
15
|
+
return Object.hasOwn(ASSETS, code) ? ASSETS[code] : undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
5
18
|
/** Case-insensitive token symbol; unrecognized symbols use a neutral monogram. */
|
|
6
19
|
export function assetIconName(asset: string): IconName | undefined {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
20
|
+
return knownAsset(asset)?.icon;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The token's symbol as payers read it, for example `USDC` for `usdc`. */
|
|
24
|
+
export function assetSymbol(asset: string): string {
|
|
25
|
+
return asset.trim().toUpperCase();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The token's full name, for example `USD Coin`, or its symbol when the SDK does not know it. */
|
|
29
|
+
export function assetName(asset: string): string {
|
|
30
|
+
return knownAsset(asset)?.name ?? assetSymbol(asset);
|
|
14
31
|
}
|
|
15
32
|
|
|
16
33
|
/** First character for a neutral fallback, including an empty-symbol placeholder. */
|
|
17
34
|
export function iconMonogram(label: string): string {
|
|
18
35
|
return Array.from(label.trim())[0]?.toUpperCase() ?? "?";
|
|
19
36
|
}
|
|
20
|
-
|
package/src/index.ts
CHANGED
|
@@ -22,7 +22,7 @@ export {
|
|
|
22
22
|
type DepositAddressPayment,
|
|
23
23
|
type RetrieveDepositAddressOptions,
|
|
24
24
|
} from "./deposit-address.js";
|
|
25
|
-
export { knownChain, networkName, transactionUrl, networkIconName } from "./chains.js";
|
|
25
|
+
export { addressUrl, isTestnet, knownChain, networkName, transactionUrl, networkIconName } from "./chains.js";
|
|
26
26
|
export { formatAmount, formatCountdown, formatMinorAmount, formatTokenAmount, formatUnitsGrouped, formatWait, tokenAmount } from "./format.js";
|
|
27
27
|
export {
|
|
28
28
|
depositAddressTransfer,
|
|
@@ -35,7 +35,15 @@ export {
|
|
|
35
35
|
type TransferRequest,
|
|
36
36
|
} from "./payment.js";
|
|
37
37
|
export { parseClientQuote, quoteIdFromClientSecret, type ClientQuote } from "./quote.js";
|
|
38
|
-
export { assetIconName, iconMonogram, type IconName } from "./icon-names.js";
|
|
38
|
+
export { assetIconName, assetName, assetSymbol, iconMonogram, type IconName } from "./icon-names.js";
|
|
39
|
+
export {
|
|
40
|
+
paymentOptionLabel,
|
|
41
|
+
paymentOptions,
|
|
42
|
+
samePaymentOption,
|
|
43
|
+
type NetworkPaymentOption,
|
|
44
|
+
type PaymentNetwork,
|
|
45
|
+
type PaymentOption,
|
|
46
|
+
} from "./options.js";
|
|
39
47
|
export {
|
|
40
48
|
INJECTED_WALLET_UUID,
|
|
41
49
|
WalletError,
|
package/src/options.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { networkName } from "./chains.js";
|
|
2
|
+
import { assetSymbol } from "./icon-names.js";
|
|
3
|
+
|
|
4
|
+
/** A token on a network that a payer can pay with, for example `usdc` on chain 8453. */
|
|
5
|
+
export interface PaymentOption {
|
|
6
|
+
chain_id: number;
|
|
7
|
+
/** The token's code, for example `usdc`. */
|
|
8
|
+
asset: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** A network with the tokens it takes, as a deposit address's `networks` list them. */
|
|
12
|
+
export interface PaymentNetwork {
|
|
13
|
+
chain_id: number;
|
|
14
|
+
assets: readonly { asset: string }[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** One token of a `PaymentNetwork`, with the network and token objects it came from. */
|
|
18
|
+
export type NetworkPaymentOption<N extends PaymentNetwork> = PaymentOption & {
|
|
19
|
+
network: N;
|
|
20
|
+
token: N["assets"][number];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The options to offer, in the order given and each once (the first of any duplicate): either a
|
|
25
|
+
* flat list such as `GET /v1/config`'s `assets`, returned as the same objects, or networks with
|
|
26
|
+
* their tokens such as a deposit address's `networks`, flattened network by network.
|
|
27
|
+
*/
|
|
28
|
+
export function paymentOptions<T extends PaymentOption>(options: readonly T[]): T[];
|
|
29
|
+
export function paymentOptions<N extends PaymentNetwork>(networks: readonly N[]): NetworkPaymentOption<N>[];
|
|
30
|
+
export function paymentOptions(
|
|
31
|
+
source: readonly (PaymentOption | PaymentNetwork)[],
|
|
32
|
+
): (PaymentOption | NetworkPaymentOption<PaymentNetwork>)[] {
|
|
33
|
+
const flat = source.flatMap((each) =>
|
|
34
|
+
"assets" in each
|
|
35
|
+
? each.assets.map((token) => ({ chain_id: each.chain_id, asset: token.asset, network: each, token }))
|
|
36
|
+
: [each],
|
|
37
|
+
);
|
|
38
|
+
return flat.filter((option, index) => flat.findIndex((other) => samePaymentOption(option, other)) === index);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Whether `a` and `b` are the same token on the same network; asset codes are case-insensitive. */
|
|
42
|
+
export function samePaymentOption(a: PaymentOption | null | undefined, b: PaymentOption | null | undefined): boolean {
|
|
43
|
+
return (
|
|
44
|
+
a != null &&
|
|
45
|
+
b != null &&
|
|
46
|
+
a.chain_id === b.chain_id &&
|
|
47
|
+
a.asset.trim().toLowerCase() === b.asset.trim().toLowerCase()
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** The option as one line of text, for example `USDC · Ethereum`. */
|
|
52
|
+
export function paymentOptionLabel(option: PaymentOption): string {
|
|
53
|
+
return `${assetSymbol(option.asset)} · ${networkName(option.chain_id)}`;
|
|
54
|
+
}
|