@phala/pay 0.3.0 → 0.4.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 CHANGED
@@ -6,6 +6,37 @@ All notable changes to `@phala/pay` are recorded here. The format follows
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.4.0] - 2026-10-01
10
+
11
+ ### Added
12
+
13
+ - `payWithWallet` reads the account's token balance before sending and, when it is below the
14
+ quote's amount, sends nothing and throws `WalletError` with the new code
15
+ `insufficient_balance`: the transfer would revert and still cost gas. `<Checkout>` shows the
16
+ error's message (what the wallet holds and what the quote needs). A wallet that cannot read the
17
+ balance still pays.
18
+ - `<Checkout onWalletError>`: called with the `WalletError` and the wallet it tried (the chosen
19
+ browser wallet's provider, or `walletClient`) when the wallet tab could not send the payment, for
20
+ example to offer your own way to fund that wallet on `insufficient_balance`.
21
+ - `ClientQuote.amount_credited`, what a credited payment credited in cents (it differs from
22
+ `amount` for a payment of another amount or a late one), and `ClientQuote.typical_credit_seconds`,
23
+ the typical credit time at the quote's confirmation.
24
+
25
+ ### Changed (breaking)
26
+
27
+ - `parseClientQuote`, and so `<Checkout>` and `createCheckout`, require `amount_credited` (an
28
+ integer or `null`) and `typical_credit_seconds`, which the service sends from v0.3.4: upgrade
29
+ the service before the SDK.
30
+
31
+ ### Fixed
32
+
33
+ - `<Checkout>` showed the quoted amount as credited ("Payment credited: $25.00" for a $25 quote
34
+ paid with $10). It now shows what was credited and, when that differs from the quote, says so
35
+ ("Payment credited: $10.00 of $25.00"); `onSuccess(quote)` carries it as `amount_credited`.
36
+ - `<Checkout>` told a payer "crediting in about 30 seconds" on every chain. It now states the
37
+ quote's typical wait: about 5 minutes at Base's `safe` block, 15 minutes under a `finalized`
38
+ policy.
39
+
9
40
  ## [0.3.0] - 2026-10-01
10
41
 
11
42
  ### Changed (breaking)
@@ -152,7 +183,8 @@ All notable changes to `@phala/pay` are recorded here. The format follows
152
183
  without trailing zeros (`1,273.9185`); `tokenAmount(quote)` is the plain decimal a wallet
153
184
  accepts, which `<Checkout>`'s "Exact amount" copies.
154
185
 
155
- [Unreleased]: https://github.com/Phala-Network/phala-pay/compare/sdk-js-v0.3.0...HEAD
186
+ [unreleased]: https://github.com/Phala-Network/phala-pay/compare/sdk-js-v0.4.0...HEAD
187
+ [0.4.0]: https://github.com/Phala-Network/phala-pay/compare/sdk-js-v0.3.0...sdk-js-v0.4.0
156
188
  [0.3.0]: https://github.com/Phala-Network/phala-pay/compare/sdk-js-v0.2.0...sdk-js-v0.3.0
157
189
  [0.2.0]: https://github.com/Phala-Network/phala-pay/compare/sdk-js-v0.1.2...sdk-js-v0.2.0
158
190
  [0.1.2]: https://github.com/Phala-Network/phala-pay/compare/sdk-js-v0.1.1...sdk-js-v0.1.2
package/README.md CHANGED
@@ -66,9 +66,9 @@ mode".
66
66
  |---|---|
67
67
  | `loading` | Loading payment details |
68
68
  | `waiting` | Payment options, the exact amount, and the time left |
69
- | `seen` | Payment in a block, with its confirmations (a reorg can still remove it) |
69
+ | `seen` | Payment in a block, with its confirmations and the typical wait for the credit (a reorg can still remove it) |
70
70
  | `confirming` | Payment at the route's confirmation (two blocks on Ethereum), being valued and screened |
71
- | `credited` | Credited, typically about 30 seconds after paying; `onSuccess` is called once |
71
+ | `credited` | What was credited, typically `typical_credit_seconds` after paying; `onSuccess(quote)` is called once |
72
72
  | `rejected` | Will not be credited; the payer contacts support |
73
73
  | `reversed` | Credited, then its transaction left the chain before finality: the payment did not happen |
74
74
  | `expired`, `canceled` | The address is hidden; `onExpire` is called once |
@@ -78,17 +78,27 @@ mode".
78
78
  Elements' `onChange`, for example to hide your own "new payment" control while a payment is
79
79
  `seen` or `confirming`.
80
80
 
81
+ Before the wallet tab sends a payment, it reads the wallet's token balance; when the wallet holds
82
+ less than the quote, it sends nothing (the transfer would revert and still cost gas) and says how
83
+ much the wallet holds. `onWalletError(error, wallet)` is called with the `WalletError` and the
84
+ wallet it tried (the chosen browser wallet's EIP-1193 provider, or your `walletClient`) whenever the
85
+ wallet tab could not send (`code` `insufficient_balance`, `rejected`, `wrong_chain`, …), for example
86
+ to offer your own way to fund that wallet.
87
+
81
88
  To resume after a reload, keep the client secret in the browser (for example `localStorage`, per
82
89
  signed-in account) until the status is `credited`, `expired`, `canceled`, or `error`. Tell a
83
- payer who is waiting that the payment is credited in about 30 seconds and the credit arrives on
84
- its own.
90
+ payer who is waiting that the payment is credited in about the quote's `typical_credit_seconds`
91
+ (30 seconds on Ethereum, about 5 minutes on Base, 15 minutes under a `finalized` policy) and the
92
+ credit arrives on its own.
85
93
 
86
94
  A credit is made before Ethereum finality (about 15 minutes). In the rare case that a reorg drops
87
95
  the payment's transaction, your backend receives `deposit.reversed` and claws the credit back as
88
96
  for `deposit.refunded`; the checkout itself only reflects the quote.
89
97
 
90
98
  The payment options disappear once a payment is seen, and at `expires_at`. A payment of a different
91
- amount, or after expiry, is still credited, at the market price instead of the quote's.
99
+ amount, or after expiry, is still credited, at the market price instead of the quote's: the
100
+ checkout then says so ("Payment credited: $10.00 of $25.00"), and `onSuccess` receives the quote
101
+ with what was credited as `amount_credited`, beside the quoted `amount`.
92
102
 
93
103
  ### Your own wallet connection
94
104
 
@@ -214,7 +224,9 @@ checkout.destroy();
214
224
  wagmi's `useWalletClient()` or `getWalletClient(config)`; its account is used without asking to
215
225
  connect again). It connects, switches the wallet to the quote's chain (adding Ethereum, Sepolia,
216
226
  Base, or Base Sepolia when the wallet lacks it), and sends the ERC-20 `transfer` stated by the
217
- quote's `payment_uri`, after checking that it pays exactly `amount_atomic` to `address`.
227
+ quote's `payment_uri`, after checking that it pays exactly `amount_atomic` to `address`. A wallet
228
+ holding less of the token than that sends nothing: `WalletError` with `code`
229
+ `insufficient_balance`.
218
230
 
219
231
  ## Server helpers
220
232
 
@@ -5,8 +5,8 @@ import { type ClientQuote } from "./quote.js";
5
5
  * - `waiting` for a payment, until `expires_at`;
6
6
  * - `seen` once a transfer is in a block, `confirming` once it reaches the route's confirmation
7
7
  * (two blocks on Ethereum) and is being valued;
8
- * - `credited` (about 30 seconds after paying), or `rejected` for a payment that will not be
9
- * credited;
8
+ * - `credited` (typically the quote's `typical_credit_seconds` after paying), or `rejected` for a
9
+ * payment that will not be credited;
10
10
  * - `reversed` when a credited payment's transaction left the chain before finality;
11
11
  * - `expired` or `canceled` without a payment;
12
12
  * - `error` when the client secret is not valid, or the quote's address is not the one your
package/dist/format.d.ts CHANGED
@@ -4,10 +4,16 @@ import type { ClientQuote } from "./quote.js";
4
4
  * `1,273.9185`. Every digit is kept: the service rounds a quote to a few decimals.
5
5
  */
6
6
  export declare function formatTokenAmount(quote: ClientQuote, locale?: string): string;
7
+ /** An atomic token amount, grouped for `locale` and without trailing zeros, as `formatTokenAmount`. */
8
+ export declare function formatUnitsGrouped(atomic: bigint, decimals: number, locale?: string): string;
7
9
  /** The exact token amount as a plain decimal, for copying into a wallet, for example `1273.9185`. */
8
10
  export declare function tokenAmount(quote: ClientQuote): string;
9
11
  /** The credit in the quote's currency, for example `$25.00`. */
10
12
  export declare function formatAmount(quote: ClientQuote, locale?: string): string;
13
+ /** `minor` units of the quote's currency, for example `$10.00` for 1000. */
14
+ export declare function formatMinorAmount(quote: ClientQuote, minor: number, locale?: string): string;
15
+ /** A typical wait, for example `about 30 seconds` or `about 15 minutes`. */
16
+ export declare function formatWait(seconds: number): string;
11
17
  /** `mm:ss` (or `h:mm:ss`) until `expiresAt` Unix seconds, never negative. */
12
18
  export declare function formatCountdown(expiresAt: number, nowMs: number): string;
13
19
  //# sourceMappingURL=format.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAS7E;AAED,qGAAqG;AACrG,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAEtD;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAKxE;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQxE"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,uGAAuG;AACvG,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAS5F;AAED,qGAAqG;AACrG,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAEtD;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAK5F;AAED,4EAA4E;AAC5E,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQxE"}
package/dist/format.js CHANGED
@@ -4,7 +4,11 @@ import { formatUnits } from "viem";
4
4
  * `1,273.9185`. Every digit is kept: the service rounds a quote to a few decimals.
5
5
  */
6
6
  export function formatTokenAmount(quote, locale) {
7
- const [whole = "0", fraction] = tokenAmount(quote).split(".");
7
+ return formatUnitsGrouped(BigInt(quote.amount_atomic), quote.decimals, locale);
8
+ }
9
+ /** An atomic token amount, grouped for `locale` and without trailing zeros, as `formatTokenAmount`. */
10
+ export function formatUnitsGrouped(atomic, decimals, locale) {
11
+ const [whole = "0", fraction] = formatUnits(atomic, decimals).split(".");
8
12
  const format = new Intl.NumberFormat(locale);
9
13
  const grouped = format.format(BigInt(whole));
10
14
  if (fraction === undefined) {
@@ -19,10 +23,21 @@ export function tokenAmount(quote) {
19
23
  }
20
24
  /** The credit in the quote's currency, for example `$25.00`. */
21
25
  export function formatAmount(quote, locale) {
26
+ return formatMinorAmount(quote, quote.amount, locale);
27
+ }
28
+ /** `minor` units of the quote's currency, for example `$10.00` for 1000. */
29
+ export function formatMinorAmount(quote, minor, locale) {
22
30
  return new Intl.NumberFormat(locale, {
23
31
  style: "currency",
24
32
  currency: quote.currency.toUpperCase(),
25
- }).format(quote.amount / 100);
33
+ }).format(minor / 100);
34
+ }
35
+ /** A typical wait, for example `about 30 seconds` or `about 15 minutes`. */
36
+ export function formatWait(seconds) {
37
+ if (seconds < 90) {
38
+ return `about ${seconds} second${seconds === 1 ? "" : "s"}`;
39
+ }
40
+ return `about ${Math.round(seconds / 60)} minutes`;
26
41
  }
27
42
  /** `mm:ss` (or `h:mm:ss`) until `expiresAt` Unix seconds, never negative. */
28
43
  export function formatCountdown(expiresAt, nowMs) {
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAGnC;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAkB,EAAE,MAAe;IACnE,MAAM,CAAC,KAAK,GAAG,GAAG,EAAE,QAAQ,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,EAAE,KAAK,IAAI,GAAG,CAAC;IAClG,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,EAAE,CAAC;AAC7C,CAAC;AAED,qGAAqG;AACrG,MAAM,UAAU,WAAW,CAAC,KAAkB;IAC5C,OAAO,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;AAClE,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,YAAY,CAAC,KAAkB,EAAE,MAAe;IAC9D,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE;QACnC,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE;KACvC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,eAAe,CAAC,SAAiB,EAAE,KAAa;IAC9D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACpD,OAAO,KAAK,GAAG,CAAC;QACd,CAAC,CAAC,GAAG,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,OAAO,EAAE;QAC3D,CAAC,CAAC,GAAG,OAAO,IAAI,OAAO,EAAE,CAAC;AAC9B,CAAC"}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
package/dist/quote.d.ts CHANGED
@@ -8,7 +8,7 @@ export interface ClientQuote {
8
8
  livemode: boolean;
9
9
  /** `open` until a matching payment completes it, it expires by chain time, or it is canceled. */
10
10
  status: "open" | "complete" | "expired" | "canceled";
11
- /** Credit in the currency's minor unit (US cents). */
11
+ /** The quoted credit in the currency's minor unit (US cents). */
12
12
  amount: number;
13
13
  currency: string;
14
14
  /** The token's code, for example `pha`. */
@@ -25,13 +25,24 @@ export interface ClientQuote {
25
25
  expires_at: number;
26
26
  /**
27
27
  * `seen` once in a block (a reorg can remove it), `confirming` while a payment at the route's
28
- * confirmation is valued and screened, `credited` once it is credited (about 30 seconds after
29
- * paying), `rejected` when it will not be, `reversed` when a credited payment's transaction
30
- * left the chain before finality (the payment did not happen).
28
+ * confirmation is valued and screened, `credited` once it is credited (typically
29
+ * `typical_credit_seconds` after paying), `rejected` when it will not be, `reversed` when a
30
+ * credited payment's transaction left the chain before finality (the payment did not happen).
31
31
  */
32
32
  payment_status: "none" | "seen" | "confirming" | "credited" | "rejected" | "reversed";
33
33
  /** Block confirmations while `payment_status` is `seen`, otherwise `null`. */
34
34
  confirmations: number | null;
35
+ /**
36
+ * While `payment_status` is `credited`: what was credited, in the currency's minor unit. It
37
+ * differs from `amount` for a payment valued at the market price (another amount, or paid late);
38
+ * otherwise `null`.
39
+ */
40
+ amount_credited: number | null;
41
+ /**
42
+ * Typical seconds from paying to the credit at the confirmation this quote's payments need:
43
+ * 30 on Ethereum (two blocks), about 300 at an OP-stack chain's `safe` block, 900 at finality.
44
+ */
45
+ typical_credit_seconds: number;
35
46
  }
36
47
  /** Returns the quote id a client secret belongs to (`qt_…_secret_…`), or throws. */
37
48
  export declare function quoteIdFromClientSecret(clientSecret: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"quote.d.ts","sourceRoot":"","sources":["../src/quote.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,0EAA0E;IAC1E,QAAQ,EAAE,OAAO,CAAC;IAClB,iGAAiG;IACjG,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;IACrD,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,yFAAyF;IACzF,aAAa,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;IACtF,8EAA8E;IAC9E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAKD,oFAAoF;AACpF,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAMpE;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CA4C5D"}
1
+ {"version":3,"file":"quote.d.ts","sourceRoot":"","sources":["../src/quote.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,0EAA0E;IAC1E,QAAQ,EAAE,OAAO,CAAC;IAClB,iGAAiG;IACjG,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;IACrD,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,yFAAyF;IACzF,aAAa,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;IACtF,8EAA8E;IAC9E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;;OAIG;IACH,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B;;;OAGG;IACH,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAKD,oFAAoF;AACpF,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAMpE;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAiD5D"}
package/dist/quote.js CHANGED
@@ -15,6 +15,7 @@ export function parseClientQuote(value) {
15
15
  }
16
16
  const v = value;
17
17
  const confirmations = v["confirmations"];
18
+ const amountCredited = v["amount_credited"];
18
19
  if (typeof v["id"] !== "string" ||
19
20
  v["object"] !== "quote" ||
20
21
  typeof v["livemode"] !== "boolean" ||
@@ -31,7 +32,9 @@ export function parseClientQuote(value) {
31
32
  typeof v["payment_uri"] !== "string" ||
32
33
  !isSafeInteger(v["expires_at"]) ||
33
34
  !oneOf(v["payment_status"], PAYMENT_STATUSES) ||
34
- !(confirmations === null || isSafeInteger(confirmations))) {
35
+ !(confirmations === null || isSafeInteger(confirmations)) ||
36
+ !(amountCredited === null || isSafeInteger(amountCredited)) ||
37
+ !isSafeInteger(v["typical_credit_seconds"])) {
35
38
  throw new TypeError("quote response does not match the public quote view");
36
39
  }
37
40
  return {
@@ -50,6 +53,8 @@ export function parseClientQuote(value) {
50
53
  expires_at: v["expires_at"],
51
54
  payment_status: v["payment_status"],
52
55
  confirmations,
56
+ amount_credited: amountCredited,
57
+ typical_credit_seconds: v["typical_credit_seconds"],
53
58
  };
54
59
  }
55
60
  function oneOf(value, allowed) {
package/dist/quote.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"quote.js","sourceRoot":"","sources":["../src/quote.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"quote.js","sourceRoot":"","sources":["../src/quote.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import type { WalletClient } from "viem";
2
2
  import type { CheckoutState } from "../checkout.js";
3
3
  import type { ClientQuote } from "../quote.js";
4
+ import { WalletError, type EthereumProvider } from "../wallet.js";
4
5
  import { type Appearance } from "./appearance.js";
5
6
  export interface CheckoutProps {
6
7
  /** The quote's `client_secret`, from your backend's `POST /v1/quotes`. */
@@ -13,13 +14,20 @@ export interface CheckoutProps {
13
14
  expectedAddress: string;
14
15
  /** The service origin, for example `https://topup.example.com`. */
15
16
  apiBase: string;
16
- /** Called once when the payment is credited. Fulfil from the `deposit.credited` webhook, not here. */
17
+ /** Called once when the payment is credited, with the quote: its `amount_credited` is what was
18
+ * credited, which differs from `amount` for a payment of another amount or a late one. Fulfil
19
+ * from the `deposit.credited` webhook, not here. */
17
20
  onSuccess?: (quote: ClientQuote) => void;
18
21
  /** Called once when the quote expires or is canceled without a payment. */
19
22
  onExpire?: (quote: ClientQuote) => void;
20
23
  /** Called whenever the checkout's status changes, like Stripe Elements' `onChange`: for example,
21
24
  * to hide your own "new payment" control while a payment is `seen` or `confirming`. */
22
25
  onChange?: (state: CheckoutState) => void;
26
+ /** Called when the wallet tab could not send the payment, with the `WalletError` and the wallet
27
+ * it tried (the chosen browser wallet's provider, or `walletClient`): for example on
28
+ * `insufficient_balance` (nothing was sent), to offer your own way to fund that wallet. The
29
+ * checkout shows the error's message itself. */
30
+ onWalletError?: (error: WalletError, wallet: WalletClient | EthereumProvider) => void;
23
31
  appearance?: Appearance;
24
32
  /** Milliseconds between status reads; default 3000. */
25
33
  pollInterval?: number;
@@ -31,5 +39,5 @@ export interface CheckoutProps {
31
39
  walletClient?: WalletClient | undefined;
32
40
  }
33
41
  /** A checkout for one quote: pay from a browser wallet, by QR code, or manually, with live status. */
34
- export declare function Checkout({ clientSecret, expectedAddress, apiBase, onSuccess, onExpire, onChange, appearance, pollInterval, className, buttonText, walletClient, }: CheckoutProps): import("react").JSX.Element;
42
+ export declare function Checkout({ clientSecret, expectedAddress, apiBase, onSuccess, onExpire, onChange, onWalletError, appearance, pollInterval, className, buttonText, walletClient, }: CheckoutProps): import("react").JSX.Element;
35
43
  //# sourceMappingURL=Checkout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Checkout.d.ts","sourceRoot":"","sources":["../../src/react/Checkout.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAQ,YAAY,EAAE,MAAM,MAAM,CAAC;AAC/C,OAAO,KAAK,EAAqB,aAAa,EAAkB,MAAM,gBAAgB,CAAC;AAIvF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ/C,OAAO,EAA2B,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAK3E,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,sGAAsG;IACtG,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACzC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC;2FACuF;IACvF,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;2FACuF;IACvF,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CACzC;AAUD,sGAAsG;AACtG,wBAAgB,QAAQ,CAAC,EACvB,YAAY,EACZ,eAAe,EACf,OAAO,EACP,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,SAAS,EACT,UAA8B,EAC9B,YAAY,GACb,EAAE,aAAa,+BAoEf"}
1
+ {"version":3,"file":"Checkout.d.ts","sourceRoot":"","sources":["../../src/react/Checkout.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAQ,YAAY,EAAE,MAAM,MAAM,CAAC;AAC/C,OAAO,KAAK,EAAqB,aAAa,EAAkB,MAAM,gBAAgB,CAAC;AAWvF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EACL,WAAW,EAGX,KAAK,gBAAgB,EAEtB,MAAM,cAAc,CAAC;AACtB,OAAO,EAA2B,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAK3E,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB;;wDAEoD;IACpD,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACzC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC;2FACuF;IACvF,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C;;;oDAGgD;IAChD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,GAAG,gBAAgB,KAAK,IAAI,CAAC;IACtF,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;2FACuF;IACvF,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CACzC;AAUD,sGAAsG;AACtG,wBAAgB,QAAQ,CAAC,EACvB,YAAY,EACZ,eAAe,EACf,OAAO,EACP,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,UAAU,EACV,YAAY,EACZ,SAAS,EACT,UAA8B,EAC9B,YAAY,GACb,EAAE,aAAa,+BAqEf"}
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useEffect, useId, useRef, useState } from "react";
4
4
  import { networkName, transactionUrl } from "../chains.js";
5
- import { formatAmount, formatCountdown, formatTokenAmount, tokenAmount } from "../format.js";
5
+ import { formatAmount, formatCountdown, formatMinorAmount, formatTokenAmount, formatWait, tokenAmount, } from "../format.js";
6
6
  import { quoteTransfer } from "../payment.js";
7
7
  import { WalletError, payWithWallet, watchWallets, } from "../wallet.js";
8
8
  import { STYLES, appearanceStyle } from "./appearance.js";
@@ -15,7 +15,7 @@ const METHODS = [
15
15
  { id: "manual", label: "Send manually" },
16
16
  ];
17
17
  /** A checkout for one quote: pay from a browser wallet, by QR code, or manually, with live status. */
18
- export function Checkout({ clientSecret, expectedAddress, apiBase, onSuccess, onExpire, onChange, appearance, pollInterval, className, buttonText = "Pay with crypto", walletClient, }) {
18
+ export function Checkout({ clientSecret, expectedAddress, apiBase, onSuccess, onExpire, onChange, onWalletError, appearance, pollInterval, className, buttonText = "Pay with crypto", walletClient, }) {
19
19
  const { status, quote, error, refresh } = useCheckout({
20
20
  clientSecret,
21
21
  expectedAddress,
@@ -51,7 +51,7 @@ export function Checkout({ clientSecret, expectedAddress, apiBase, onSuccess, on
51
51
  return (_jsxs("div", { className: className === undefined ? "pp-root" : `pp-root ${className}`, "data-theme": appearance?.theme ?? "light", style: appearanceStyle(appearance), children: [_jsx("style", { children: STYLES }), quote !== null && (_jsxs(_Fragment, { children: [_jsxs("p", { className: "pp-amount", children: [formatTokenAmount(quote), " ", quote.asset.toUpperCase()] }), _jsxs("p", { className: "pp-subtitle", children: [formatAmount(quote), " top-up \u00B7 ", networkName(quote.chain_id), !quote.livemode && _jsx("span", { className: "pp-badge", children: " \u00B7 Test mode" })] })] })), _jsx(StatusLine, { status: status, quote: quote, now: now, error: error }), txHash !== null && quote !== null && _jsx(Transaction, { hash: txHash, chainId: quote.chain_id }), status === "waiting" && quote !== null && (_jsx(PaymentOptions, { quote: quote, buttonText: buttonText, walletClient: walletClient, now: now, onSent: (hash) => {
52
52
  setTxHash(hash);
53
53
  refresh();
54
- } }))] }));
54
+ }, onWalletError: onWalletError }))] }));
55
55
  }
56
56
  function StatusLine({ status, quote, now, error, }) {
57
57
  const tone = status === "credited"
@@ -68,13 +68,11 @@ function statusMessage(status, quote, code) {
68
68
  case "waiting":
69
69
  return "Waiting for your payment";
70
70
  case "seen":
71
- return quote?.confirmations == null
72
- ? "Payment received, crediting in about 30 seconds"
73
- : `Payment received, ${quote.confirmations} confirmation${quote.confirmations === 1 ? "" : "s"}. Crediting in about 30 seconds`;
71
+ return seenMessage(quote);
74
72
  case "confirming":
75
73
  return "Payment confirmed on chain, crediting…";
76
74
  case "credited":
77
- return quote === null ? "Payment credited" : `Payment credited: ${formatAmount(quote)}`;
75
+ return creditedMessage(quote);
78
76
  case "rejected":
79
77
  return "This payment cannot be credited. Contact support with your transaction.";
80
78
  case "reversed":
@@ -89,11 +87,34 @@ function statusMessage(status, quote, code) {
89
87
  : "This payment link is not valid. Start a new top-up.";
90
88
  }
91
89
  }
90
+ function seenMessage(quote) {
91
+ if (quote === null) {
92
+ return "Payment received, crediting once it is confirmed";
93
+ }
94
+ const wait = formatWait(quote.typical_credit_seconds);
95
+ return quote.confirmations === null
96
+ ? `Payment received, crediting in ${wait}`
97
+ : `Payment received, ${quote.confirmations} confirmation${quote.confirmations === 1 ? "" : "s"}. Crediting in ${wait}`;
98
+ }
99
+ /** What was credited and, when the payment was valued at the market price, the quote it missed. */
100
+ function creditedMessage(quote) {
101
+ if (quote?.amount_credited == null) {
102
+ return "Payment credited";
103
+ }
104
+ const credited = formatMinorAmount(quote, quote.amount_credited);
105
+ if (quote.amount_credited < quote.amount) {
106
+ return `Payment credited: ${credited} of ${formatAmount(quote)}`;
107
+ }
108
+ if (quote.amount_credited > quote.amount) {
109
+ return `Payment credited: ${credited}, more than the ${formatAmount(quote)} quoted`;
110
+ }
111
+ return `Payment credited: ${credited}`;
112
+ }
92
113
  function Transaction({ hash, chainId }) {
93
114
  const url = transactionUrl(chainId, hash);
94
115
  return (_jsxs("p", { className: "pp-tx", children: ["Transaction sent:", " ", url === undefined ? (_jsx("span", { className: "pp-value", children: hash })) : (_jsx("a", { className: "pp-value", href: url, target: "_blank", rel: "noreferrer", children: hash }))] }));
95
116
  }
96
- function PaymentOptions({ quote, now, buttonText, walletClient, onSent, }) {
117
+ function PaymentOptions({ quote, now, buttonText, walletClient, onSent, onWalletError, }) {
97
118
  const [method, setMethod] = useState("wallet");
98
119
  const id = useId();
99
120
  const tabs = useRef([]);
@@ -118,9 +139,9 @@ function PaymentOptions({ quote, now, buttonText, walletClient, onSent, }) {
118
139
  };
119
140
  return (_jsxs(_Fragment, { children: [_jsxs("p", { className: "pp-notice", children: ["Send ", _jsxs("strong", { children: ["exactly ", amount] }), " on ", networkName(quote.chain_id), " in one transfer before the timer ends. A different amount, or a payment after expiry, is credited at the market price instead of this quote. Exchanges may deduct a withdrawal fee, so the amount that arrives must be exact."] }), _jsx("div", { className: "pp-tabs", role: "tablist", "aria-label": "Payment method", onKeyDown: onKeyDown, children: METHODS.map((m, index) => (_jsx("button", { ref: (element) => {
120
141
  tabs.current[index] = element;
121
- }, type: "button", role: "tab", className: "pp-tab", id: `${id}-tab-${m.id}`, "aria-selected": method === m.id, "aria-controls": `${id}-panel-${m.id}`, tabIndex: method === m.id ? 0 : -1, onClick: () => setMethod(m.id), children: m.label }, m.id))) }), _jsxs("div", { role: "tabpanel", id: `${id}-panel-${method}`, "aria-labelledby": `${id}-tab-${method}`, tabIndex: 0, children: [method === "wallet" && (_jsx(WalletPanel, { quote: quote, buttonText: buttonText, walletClient: walletClient, onSent: onSent })), method === "qr" && (_jsxs("div", { className: "pp-qr-panel", children: [_jsx(QrCode, { value: quote.payment_uri, label: `Payment request for ${amount}` }), _jsxs("p", { className: "pp-message", children: ["Scan with a wallet app that reads payment links, and check that it shows ", amount, " on", " ", networkName(quote.chain_id), " before you confirm."] })] })), method === "manual" && _jsx(ManualPanel, { quote: quote, now: now })] })] }));
142
+ }, type: "button", role: "tab", className: "pp-tab", id: `${id}-tab-${m.id}`, "aria-selected": method === m.id, "aria-controls": `${id}-panel-${m.id}`, tabIndex: method === m.id ? 0 : -1, onClick: () => setMethod(m.id), children: m.label }, m.id))) }), _jsxs("div", { role: "tabpanel", id: `${id}-panel-${method}`, "aria-labelledby": `${id}-tab-${method}`, tabIndex: 0, children: [method === "wallet" && (_jsx(WalletPanel, { quote: quote, buttonText: buttonText, walletClient: walletClient, onSent: onSent, onWalletError: onWalletError })), method === "qr" && (_jsxs("div", { className: "pp-qr-panel", children: [_jsx(QrCode, { value: quote.payment_uri, label: `Payment request for ${amount}` }), _jsxs("p", { className: "pp-message", children: ["Scan with a wallet app that reads payment links, and check that it shows ", amount, " on", " ", networkName(quote.chain_id), " before you confirm."] })] })), method === "manual" && _jsx(ManualPanel, { quote: quote, now: now })] })] }));
122
143
  }
123
- function WalletPanel({ quote, buttonText, walletClient, onSent, }) {
144
+ function WalletPanel({ quote, buttonText, walletClient, onSent, onWalletError, }) {
124
145
  const [discovered, setDiscovered] = useState([]);
125
146
  const [step, setStep] = useState({ kind: "idle" });
126
147
  useEffect(() => (walletClient === undefined ? watchWallets(setDiscovered) : undefined), [walletClient]);
@@ -138,6 +159,9 @@ function WalletPanel({ quote, buttonText, walletClient, onSent, }) {
138
159
  kind: "failed",
139
160
  message: error instanceof WalletError ? error.message : "The payment could not be sent",
140
161
  });
162
+ if (error instanceof WalletError) {
163
+ onWalletError?.(error, wallet);
164
+ }
141
165
  }
142
166
  };
143
167
  if (wallets.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"Checkout.js","sourceRoot":"","sources":["../../src/react/Checkout.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Checkout.js","sourceRoot":"","sources":["../../src/react/Checkout.tsx"],"names":[],"mappings":"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"}
package/dist/wallet.d.ts CHANGED
@@ -27,7 +27,7 @@ export declare const INJECTED_WALLET_UUID = "injected";
27
27
  * itself. Returns the function that stops listening.
28
28
  */
29
29
  export declare function watchWallets(onChange: (wallets: Wallet[]) => void): () => void;
30
- export type WalletErrorCode = "rejected" | "no_account" | "wrong_chain" | "failed";
30
+ export type WalletErrorCode = "rejected" | "no_account" | "wrong_chain" | "insufficient_balance" | "failed";
31
31
  export declare class WalletError extends Error {
32
32
  readonly code: WalletErrorCode;
33
33
  readonly name = "WalletError";
@@ -37,8 +37,10 @@ export declare class WalletError extends Error {
37
37
  * Pays a quote from a wallet: a viem `WalletClient` (for example wagmi's `useWalletClient()`), or an
38
38
  * EIP-1193 provider such as a discovered `Wallet`'s. Connects (unless the client already has an
39
39
  * account), switches to (or adds) the quote's chain, and sends the ERC-20 `transfer` that the quote's
40
- * `payment_uri` states. Resolves with the transaction hash once the wallet has broadcast it; the
41
- * checkout's status follows the payment from there.
40
+ * `payment_uri` states. Before sending, it reads the account's token balance and, when it is below
41
+ * the quote's amount, sends nothing and throws `WalletError` `insufficient_balance`: the transfer
42
+ * would revert and still cost gas. Resolves with the transaction hash once the wallet has broadcast
43
+ * it; the checkout's status follows the payment from there.
42
44
  */
43
45
  export declare function payWithWallet(wallet: WalletClient | EthereumProvider, quote: ClientQuote): Promise<Hash>;
44
46
  //# sourceMappingURL=wallet.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wallet.d.ts","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"AACA,OAAO,EAOL,KAAK,IAAI,EACT,KAAK,YAAY,EAClB,MAAM,MAAM,CAAC;AAGd,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,8BAA8B;AAC9B,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,2FAA2F;AAC3F,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACvE;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED,iGAAiG;AACjG,eAAO,MAAM,oBAAoB,aAAa,CAAC;AAE/C;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAa9E;AA8BD,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,YAAY,GAAG,aAAa,GAAG,QAAQ,CAAC;AAEnF,qBAAa,WAAY,SAAQ,KAAK;IAIlC,QAAQ,CAAC,IAAI,EAAE,eAAe;IAHhC,SAAkB,IAAI,iBAAiB;gBAG5B,IAAI,EAAE,eAAe,EAC9B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY;CAIzB;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,GAAG,gBAAgB,EACvC,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
1
+ {"version":3,"file":"wallet.d.ts","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"AACA,OAAO,EAQL,KAAK,IAAI,EACT,KAAK,YAAY,EAClB,MAAM,MAAM,CAAC;AAKd,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,8BAA8B;AAC9B,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,2FAA2F;AAC3F,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACvE;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,gBAAgB,CAAC;CAC5B;AAED,iGAAiG;AACjG,eAAO,MAAM,oBAAoB,aAAa,CAAC;AAE/C;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAa9E;AA8BD,MAAM,MAAM,eAAe,GACvB,UAAU,GACV,YAAY,GACZ,aAAa,GACb,sBAAsB,GACtB,QAAQ,CAAC;AAEb,qBAAa,WAAY,SAAQ,KAAK;IAIlC,QAAQ,CAAC,IAAI,EAAE,eAAe;IAHhC,SAAkB,IAAI,iBAAiB;gBAG5B,IAAI,EAAE,eAAe,EAC9B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,YAAY;CAIzB;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,GAAG,gBAAgB,EACvC,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,IAAI,CAAC,CAoCf"}
package/dist/wallet.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { createStore } from "mipd";
2
2
  import { BaseError, createWalletClient, custom, erc20Abi, SwitchChainError, UserRejectedRequestError, } from "viem";
3
+ import { readContract } from "viem/actions";
3
4
  import { knownChain, networkName } from "./chains.js";
5
+ import { formatTokenAmount, formatUnitsGrouped } from "./format.js";
4
6
  import { quoteTransfer } from "./payment.js";
5
7
  /** The legacy `window.ethereum` provider, offered when no wallet announces itself (EIP-6963). */
6
8
  export const INJECTED_WALLET_UUID = "injected";
@@ -59,8 +61,10 @@ export class WalletError extends Error {
59
61
  * Pays a quote from a wallet: a viem `WalletClient` (for example wagmi's `useWalletClient()`), or an
60
62
  * EIP-1193 provider such as a discovered `Wallet`'s. Connects (unless the client already has an
61
63
  * account), switches to (or adds) the quote's chain, and sends the ERC-20 `transfer` that the quote's
62
- * `payment_uri` states. Resolves with the transaction hash once the wallet has broadcast it; the
63
- * checkout's status follows the payment from there.
64
+ * `payment_uri` states. Before sending, it reads the account's token balance and, when it is below
65
+ * the quote's amount, sends nothing and throws `WalletError` `insufficient_balance`: the transfer
66
+ * would revert and still cost gas. Resolves with the transaction hash once the wallet has broadcast
67
+ * it; the checkout's status follows the payment from there.
64
68
  */
65
69
  export async function payWithWallet(wallet, quote) {
66
70
  const transfer = quoteTransfer(quote);
@@ -71,6 +75,13 @@ export async function payWithWallet(wallet, quote) {
71
75
  throw new WalletError("no_account", "The wallet shared no account");
72
76
  }
73
77
  await ensureChain(client, transfer.chainId);
78
+ const address = typeof account === "string" ? account : account.address;
79
+ const balance = await tokenBalance(client, transfer.token, address);
80
+ if (balance !== undefined && balance < transfer.amount) {
81
+ const symbol = quote.asset.toUpperCase();
82
+ throw new WalletError("insufficient_balance", `Your wallet holds ${formatUnitsGrouped(balance, quote.decimals)} ${symbol}, less than the ` +
83
+ `${formatTokenAmount(quote)} ${symbol} to pay. Nothing was sent.`);
84
+ }
74
85
  return await client.writeContract({
75
86
  account,
76
87
  chain: knownChain(transfer.chainId) ?? null,
@@ -90,6 +101,19 @@ export async function payWithWallet(wallet, quote) {
90
101
  throw new WalletError("failed", "The wallet could not send the payment", { cause: error });
91
102
  }
92
103
  }
104
+ /**
105
+ * The account's balance of `token`, read through the wallet on its current chain; `undefined` when
106
+ * the wallet cannot read it. The check only spares the payer a reverting transfer, so a wallet that
107
+ * does not serve `eth_call` still pays.
108
+ */
109
+ async function tokenBalance(wallet, token, owner) {
110
+ try {
111
+ return await readContract(wallet, { address: token, abi: erc20Abi, functionName: "balanceOf", args: [owner] });
112
+ }
113
+ catch {
114
+ return undefined;
115
+ }
116
+ }
93
117
  function isWalletClient(wallet) {
94
118
  return "writeContract" in wallet;
95
119
  }
@@ -1 +1 @@
1
- {"version":3,"file":"wallet.js","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wallet.js","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phala/pay",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Phala Pay checkout: a framework-agnostic client and React bindings",
5
5
  "keywords": [
6
6
  "crypto",
package/src/checkout.ts CHANGED
@@ -7,8 +7,8 @@ import { parseClientQuote, quoteIdFromClientSecret, type ClientQuote } from "./q
7
7
  * - `waiting` for a payment, until `expires_at`;
8
8
  * - `seen` once a transfer is in a block, `confirming` once it reaches the route's confirmation
9
9
  * (two blocks on Ethereum) and is being valued;
10
- * - `credited` (about 30 seconds after paying), or `rejected` for a payment that will not be
11
- * credited;
10
+ * - `credited` (typically the quote's `typical_credit_seconds` after paying), or `rejected` for a
11
+ * payment that will not be credited;
12
12
  * - `reversed` when a credited payment's transaction left the chain before finality;
13
13
  * - `expired` or `canceled` without a payment;
14
14
  * - `error` when the client secret is not valid, or the quote's address is not the one your
package/src/format.ts CHANGED
@@ -6,7 +6,12 @@ import type { ClientQuote } from "./quote.js";
6
6
  * `1,273.9185`. Every digit is kept: the service rounds a quote to a few decimals.
7
7
  */
8
8
  export function formatTokenAmount(quote: ClientQuote, locale?: string): string {
9
- const [whole = "0", fraction] = tokenAmount(quote).split(".");
9
+ return formatUnitsGrouped(BigInt(quote.amount_atomic), quote.decimals, locale);
10
+ }
11
+
12
+ /** An atomic token amount, grouped for `locale` and without trailing zeros, as `formatTokenAmount`. */
13
+ export function formatUnitsGrouped(atomic: bigint, decimals: number, locale?: string): string {
14
+ const [whole = "0", fraction] = formatUnits(atomic, decimals).split(".");
10
15
  const format = new Intl.NumberFormat(locale);
11
16
  const grouped = format.format(BigInt(whole));
12
17
  if (fraction === undefined) {
@@ -23,10 +28,23 @@ export function tokenAmount(quote: ClientQuote): string {
23
28
 
24
29
  /** The credit in the quote's currency, for example `$25.00`. */
25
30
  export function formatAmount(quote: ClientQuote, locale?: string): string {
31
+ return formatMinorAmount(quote, quote.amount, locale);
32
+ }
33
+
34
+ /** `minor` units of the quote's currency, for example `$10.00` for 1000. */
35
+ export function formatMinorAmount(quote: ClientQuote, minor: number, locale?: string): string {
26
36
  return new Intl.NumberFormat(locale, {
27
37
  style: "currency",
28
38
  currency: quote.currency.toUpperCase(),
29
- }).format(quote.amount / 100);
39
+ }).format(minor / 100);
40
+ }
41
+
42
+ /** A typical wait, for example `about 30 seconds` or `about 15 minutes`. */
43
+ export function formatWait(seconds: number): string {
44
+ if (seconds < 90) {
45
+ return `about ${seconds} second${seconds === 1 ? "" : "s"}`;
46
+ }
47
+ return `about ${Math.round(seconds / 60)} minutes`;
30
48
  }
31
49
 
32
50
  /** `mm:ss` (or `h:mm:ss`) until `expiresAt` Unix seconds, never negative. */
package/src/quote.ts CHANGED
@@ -8,7 +8,7 @@ export interface ClientQuote {
8
8
  livemode: boolean;
9
9
  /** `open` until a matching payment completes it, it expires by chain time, or it is canceled. */
10
10
  status: "open" | "complete" | "expired" | "canceled";
11
- /** Credit in the currency's minor unit (US cents). */
11
+ /** The quoted credit in the currency's minor unit (US cents). */
12
12
  amount: number;
13
13
  currency: string;
14
14
  /** The token's code, for example `pha`. */
@@ -25,13 +25,24 @@ export interface ClientQuote {
25
25
  expires_at: number;
26
26
  /**
27
27
  * `seen` once in a block (a reorg can remove it), `confirming` while a payment at the route's
28
- * confirmation is valued and screened, `credited` once it is credited (about 30 seconds after
29
- * paying), `rejected` when it will not be, `reversed` when a credited payment's transaction
30
- * left the chain before finality (the payment did not happen).
28
+ * confirmation is valued and screened, `credited` once it is credited (typically
29
+ * `typical_credit_seconds` after paying), `rejected` when it will not be, `reversed` when a
30
+ * credited payment's transaction left the chain before finality (the payment did not happen).
31
31
  */
32
32
  payment_status: "none" | "seen" | "confirming" | "credited" | "rejected" | "reversed";
33
33
  /** Block confirmations while `payment_status` is `seen`, otherwise `null`. */
34
34
  confirmations: number | null;
35
+ /**
36
+ * While `payment_status` is `credited`: what was credited, in the currency's minor unit. It
37
+ * differs from `amount` for a payment valued at the market price (another amount, or paid late);
38
+ * otherwise `null`.
39
+ */
40
+ amount_credited: number | null;
41
+ /**
42
+ * Typical seconds from paying to the credit at the confirmation this quote's payments need:
43
+ * 30 on Ethereum (two blocks), about 300 at an OP-stack chain's `safe` block, 900 at finality.
44
+ */
45
+ typical_credit_seconds: number;
35
46
  }
36
47
 
37
48
  const QUOTE_STATUSES = ["open", "complete", "expired", "canceled"] as const;
@@ -53,6 +64,7 @@ export function parseClientQuote(value: unknown): ClientQuote {
53
64
  }
54
65
  const v = value as Record<string, unknown>;
55
66
  const confirmations = v["confirmations"];
67
+ const amountCredited = v["amount_credited"];
56
68
  if (
57
69
  typeof v["id"] !== "string" ||
58
70
  v["object"] !== "quote" ||
@@ -70,7 +82,9 @@ export function parseClientQuote(value: unknown): ClientQuote {
70
82
  typeof v["payment_uri"] !== "string" ||
71
83
  !isSafeInteger(v["expires_at"]) ||
72
84
  !oneOf(v["payment_status"], PAYMENT_STATUSES) ||
73
- !(confirmations === null || isSafeInteger(confirmations))
85
+ !(confirmations === null || isSafeInteger(confirmations)) ||
86
+ !(amountCredited === null || isSafeInteger(amountCredited)) ||
87
+ !isSafeInteger(v["typical_credit_seconds"])
74
88
  ) {
75
89
  throw new TypeError("quote response does not match the public quote view");
76
90
  }
@@ -90,6 +104,8 @@ export function parseClientQuote(value: unknown): ClientQuote {
90
104
  expires_at: v["expires_at"],
91
105
  payment_status: v["payment_status"],
92
106
  confirmations,
107
+ amount_credited: amountCredited,
108
+ typical_credit_seconds: v["typical_credit_seconds"],
93
109
  };
94
110
  }
95
111
 
@@ -4,7 +4,14 @@ import { useEffect, useId, useRef, useState, type KeyboardEvent } from "react";
4
4
  import type { Hash, WalletClient } from "viem";
5
5
  import type { CheckoutErrorCode, CheckoutState, CheckoutStatus } from "../checkout.js";
6
6
  import { networkName, transactionUrl } from "../chains.js";
7
- import { formatAmount, formatCountdown, formatTokenAmount, tokenAmount } from "../format.js";
7
+ import {
8
+ formatAmount,
9
+ formatCountdown,
10
+ formatMinorAmount,
11
+ formatTokenAmount,
12
+ formatWait,
13
+ tokenAmount,
14
+ } from "../format.js";
8
15
  import { quoteTransfer } from "../payment.js";
9
16
  import type { ClientQuote } from "../quote.js";
10
17
  import {
@@ -30,13 +37,20 @@ export interface CheckoutProps {
30
37
  expectedAddress: string;
31
38
  /** The service origin, for example `https://topup.example.com`. */
32
39
  apiBase: string;
33
- /** Called once when the payment is credited. Fulfil from the `deposit.credited` webhook, not here. */
40
+ /** Called once when the payment is credited, with the quote: its `amount_credited` is what was
41
+ * credited, which differs from `amount` for a payment of another amount or a late one. Fulfil
42
+ * from the `deposit.credited` webhook, not here. */
34
43
  onSuccess?: (quote: ClientQuote) => void;
35
44
  /** Called once when the quote expires or is canceled without a payment. */
36
45
  onExpire?: (quote: ClientQuote) => void;
37
46
  /** Called whenever the checkout's status changes, like Stripe Elements' `onChange`: for example,
38
47
  * to hide your own "new payment" control while a payment is `seen` or `confirming`. */
39
48
  onChange?: (state: CheckoutState) => void;
49
+ /** Called when the wallet tab could not send the payment, with the `WalletError` and the wallet
50
+ * it tried (the chosen browser wallet's provider, or `walletClient`): for example on
51
+ * `insufficient_balance` (nothing was sent), to offer your own way to fund that wallet. The
52
+ * checkout shows the error's message itself. */
53
+ onWalletError?: (error: WalletError, wallet: WalletClient | EthereumProvider) => void;
40
54
  appearance?: Appearance;
41
55
  /** Milliseconds between status reads; default 3000. */
42
56
  pollInterval?: number;
@@ -64,6 +78,7 @@ export function Checkout({
64
78
  onSuccess,
65
79
  onExpire,
66
80
  onChange,
81
+ onWalletError,
67
82
  appearance,
68
83
  pollInterval,
69
84
  className,
@@ -133,6 +148,7 @@ export function Checkout({
133
148
  setTxHash(hash);
134
149
  refresh();
135
150
  }}
151
+ onWalletError={onWalletError}
136
152
  />
137
153
  )}
138
154
  </div>
@@ -182,13 +198,11 @@ function statusMessage(
182
198
  case "waiting":
183
199
  return "Waiting for your payment";
184
200
  case "seen":
185
- return quote?.confirmations == null
186
- ? "Payment received, crediting in about 30 seconds"
187
- : `Payment received, ${quote.confirmations} confirmation${quote.confirmations === 1 ? "" : "s"}. Crediting in about 30 seconds`;
201
+ return seenMessage(quote);
188
202
  case "confirming":
189
203
  return "Payment confirmed on chain, crediting…";
190
204
  case "credited":
191
- return quote === null ? "Payment credited" : `Payment credited: ${formatAmount(quote)}`;
205
+ return creditedMessage(quote);
192
206
  case "rejected":
193
207
  return "This payment cannot be credited. Contact support with your transaction.";
194
208
  case "reversed":
@@ -204,6 +218,31 @@ function statusMessage(
204
218
  }
205
219
  }
206
220
 
221
+ function seenMessage(quote: ClientQuote | null): string {
222
+ if (quote === null) {
223
+ return "Payment received, crediting once it is confirmed";
224
+ }
225
+ const wait = formatWait(quote.typical_credit_seconds);
226
+ return quote.confirmations === null
227
+ ? `Payment received, crediting in ${wait}`
228
+ : `Payment received, ${quote.confirmations} confirmation${quote.confirmations === 1 ? "" : "s"}. Crediting in ${wait}`;
229
+ }
230
+
231
+ /** What was credited and, when the payment was valued at the market price, the quote it missed. */
232
+ function creditedMessage(quote: ClientQuote | null): string {
233
+ if (quote?.amount_credited == null) {
234
+ return "Payment credited";
235
+ }
236
+ const credited = formatMinorAmount(quote, quote.amount_credited);
237
+ if (quote.amount_credited < quote.amount) {
238
+ return `Payment credited: ${credited} of ${formatAmount(quote)}`;
239
+ }
240
+ if (quote.amount_credited > quote.amount) {
241
+ return `Payment credited: ${credited}, more than the ${formatAmount(quote)} quoted`;
242
+ }
243
+ return `Payment credited: ${credited}`;
244
+ }
245
+
207
246
  function Transaction({ hash, chainId }: { hash: Hash; chainId: number }) {
208
247
  const url = transactionUrl(chainId, hash);
209
248
  return (
@@ -226,12 +265,14 @@ function PaymentOptions({
226
265
  buttonText,
227
266
  walletClient,
228
267
  onSent,
268
+ onWalletError,
229
269
  }: {
230
270
  quote: ClientQuote;
231
271
  now: number;
232
272
  buttonText: string;
233
273
  walletClient: WalletClient | undefined;
234
274
  onSent: (hash: Hash) => void;
275
+ onWalletError: CheckoutProps["onWalletError"];
235
276
  }) {
236
277
  const [method, setMethod] = useState<Method>("wallet");
237
278
  const id = useId();
@@ -298,6 +339,7 @@ function PaymentOptions({
298
339
  buttonText={buttonText}
299
340
  walletClient={walletClient}
300
341
  onSent={onSent}
342
+ onWalletError={onWalletError}
301
343
  />
302
344
  )}
303
345
  {method === "qr" && (
@@ -325,11 +367,13 @@ function WalletPanel({
325
367
  buttonText,
326
368
  walletClient,
327
369
  onSent,
370
+ onWalletError,
328
371
  }: {
329
372
  quote: ClientQuote;
330
373
  buttonText: string;
331
374
  walletClient: WalletClient | undefined;
332
375
  onSent: (hash: Hash) => void;
376
+ onWalletError: CheckoutProps["onWalletError"];
333
377
  }) {
334
378
  const [discovered, setDiscovered] = useState<Wallet[]>([]);
335
379
  const [step, setStep] = useState<WalletStep>({ kind: "idle" });
@@ -352,6 +396,9 @@ function WalletPanel({
352
396
  kind: "failed",
353
397
  message: error instanceof WalletError ? error.message : "The payment could not be sent",
354
398
  });
399
+ if (error instanceof WalletError) {
400
+ onWalletError?.(error, wallet);
401
+ }
355
402
  }
356
403
  };
357
404
 
package/src/wallet.ts CHANGED
@@ -6,10 +6,13 @@ import {
6
6
  erc20Abi,
7
7
  SwitchChainError,
8
8
  UserRejectedRequestError,
9
+ type Address,
9
10
  type Hash,
10
11
  type WalletClient,
11
12
  } from "viem";
13
+ import { readContract } from "viem/actions";
12
14
  import { knownChain, networkName } from "./chains.js";
15
+ import { formatTokenAmount, formatUnitsGrouped } from "./format.js";
13
16
  import { quoteTransfer } from "./payment.js";
14
17
  import type { ClientQuote } from "./quote.js";
15
18
 
@@ -83,7 +86,12 @@ function isProvider(value: unknown): value is EthereumProvider {
83
86
  return typeof (value as Partial<EthereumProvider> | null | undefined)?.request === "function";
84
87
  }
85
88
 
86
- export type WalletErrorCode = "rejected" | "no_account" | "wrong_chain" | "failed";
89
+ export type WalletErrorCode =
90
+ | "rejected"
91
+ | "no_account"
92
+ | "wrong_chain"
93
+ | "insufficient_balance"
94
+ | "failed";
87
95
 
88
96
  export class WalletError extends Error {
89
97
  override readonly name = "WalletError";
@@ -101,8 +109,10 @@ export class WalletError extends Error {
101
109
  * Pays a quote from a wallet: a viem `WalletClient` (for example wagmi's `useWalletClient()`), or an
102
110
  * EIP-1193 provider such as a discovered `Wallet`'s. Connects (unless the client already has an
103
111
  * account), switches to (or adds) the quote's chain, and sends the ERC-20 `transfer` that the quote's
104
- * `payment_uri` states. Resolves with the transaction hash once the wallet has broadcast it; the
105
- * checkout's status follows the payment from there.
112
+ * `payment_uri` states. Before sending, it reads the account's token balance and, when it is below
113
+ * the quote's amount, sends nothing and throws `WalletError` `insufficient_balance`: the transfer
114
+ * would revert and still cost gas. Resolves with the transaction hash once the wallet has broadcast
115
+ * it; the checkout's status follows the payment from there.
106
116
  */
107
117
  export async function payWithWallet(
108
118
  wallet: WalletClient | EthereumProvider,
@@ -116,6 +126,16 @@ export async function payWithWallet(
116
126
  throw new WalletError("no_account", "The wallet shared no account");
117
127
  }
118
128
  await ensureChain(client, transfer.chainId);
129
+ const address = typeof account === "string" ? account : account.address;
130
+ const balance = await tokenBalance(client, transfer.token, address);
131
+ if (balance !== undefined && balance < transfer.amount) {
132
+ const symbol = quote.asset.toUpperCase();
133
+ throw new WalletError(
134
+ "insufficient_balance",
135
+ `Your wallet holds ${formatUnitsGrouped(balance, quote.decimals)} ${symbol}, less than the ` +
136
+ `${formatTokenAmount(quote)} ${symbol} to pay. Nothing was sent.`,
137
+ );
138
+ }
119
139
  return await client.writeContract({
120
140
  account,
121
141
  chain: knownChain(transfer.chainId) ?? null,
@@ -135,6 +155,19 @@ export async function payWithWallet(
135
155
  }
136
156
  }
137
157
 
158
+ /**
159
+ * The account's balance of `token`, read through the wallet on its current chain; `undefined` when
160
+ * the wallet cannot read it. The check only spares the payer a reverting transfer, so a wallet that
161
+ * does not serve `eth_call` still pays.
162
+ */
163
+ async function tokenBalance(wallet: WalletClient, token: Address, owner: Address): Promise<bigint | undefined> {
164
+ try {
165
+ return await readContract(wallet, { address: token, abi: erc20Abi, functionName: "balanceOf", args: [owner] });
166
+ } catch {
167
+ return undefined;
168
+ }
169
+ }
170
+
138
171
  function isWalletClient(wallet: WalletClient | EthereumProvider): wallet is WalletClient {
139
172
  return "writeContract" in wallet;
140
173
  }