@phala/pay 0.11.3 → 0.12.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 CHANGED
@@ -204,6 +204,36 @@ import { PaymentElement } from "@phala/pay-react";
204
204
  exchange? Use a deposit address", for payers sending from an exchange or any wallet: it resolves
205
205
  with the deposit address's `address` and `networks` and, to follow its payments, `clientSecret`;
206
206
  the element shows `<DepositAddress>` at the chosen option, which states the per-transfer limits.
207
+ - **Deposit-address mode.** Without `createQuote`, submit calls `createDepositAddress(option)` once
208
+ and shows that address as the way to pay, with no secondary line: the customer's one fixed address
209
+ instead of a new quote per payment. `depositAmountAtomic(option, token)` names the token amount to
210
+ ask for in the token's smallest unit (`undefined` for any amount); it is called once the address
211
+ is created, with its token for the chosen option, whose `decimals` give the unit. The address view
212
+ then states the amount and network once, pays it with `Pay with <wallet name>`
213
+ (`payDepositAddressWithWallet`: exactly that amount, then a transaction-hash hint), and keeps a QR
214
+ code that requests the amount (EIP-681 `uint256`) and the address to copy behind "Pay from an
215
+ exchange or another wallet". It follows the payment the wallet sent, by its hash, or else the
216
+ newest one that arrives after the address was first read, on one status line; `onChange` reports
217
+ it as `payment`, and `onDepositSuccess(payment)` is called once when it is credited. An address
218
+ that does not take the chosen token on the chosen network is a `createDepositAddress` failure. To
219
+ resume after a reload, keep `onDepositSent(txHash, chainId)`'s values and pass them back as
220
+ `depositTxHash`, with that option as `value` or `defaultValue`: the element calls
221
+ `createDepositAddress` at once and shows that payment's status (no way to pay again) until it is
222
+ credited.
223
+
224
+ ```tsx
225
+ <PaymentElement
226
+ options={paymentOptions(config.assets)}
227
+ amount={2500}
228
+ // POST /v1/deposit_addresses on your backend: { address, networks, clientSecret }
229
+ createDepositAddress={() => api.depositAddress()}
230
+ // 25 of a $1 stablecoin: cents × 10^(decimals − 2)
231
+ depositAmountAtomic={(option, token) => (2500n * 10n ** BigInt(token.decimals)) / 100n}
232
+ apiBase="https://pay.example.com"
233
+ onDepositSuccess={() => router.refresh()}
234
+ />
235
+ ```
236
+
207
237
  - Your own content: `children` go inside the form, under the token and network and above the
208
238
  element's button, while the payer chooses. With `hideSubmit`, put your summary and your
209
239
  `type="submit"` button there, and the deposit-address line follows your button:
@@ -219,8 +249,9 @@ import { PaymentElement } from "@phala/pay-react";
219
249
  button `type="submit" form={id}` (or call `requestSubmit()` on the form with that id). The
220
250
  element is a `<form>`: do not nest it in another one.
221
251
  - `value` and `onOptionChange` control the choice (`defaultValue` sets the first one otherwise);
222
- `onChange({ step, checkout })` reports each step (`options`, `creating`, `checkout`,
223
- `deposit_address`) and, while paying, each checkout status change; `onSuccess`, `onExpire`,
252
+ `onChange({ step, checkout, payment })` reports each step (`options`, `creating`, `checkout`,
253
+ `deposit_address`) and, while paying, each checkout status change or, with
254
+ `depositAmountAtomic`, each change of the deposit address's payment; `onSuccess`, `onExpire`,
224
255
  `onWalletError`, `walletClient`, `pollInterval`, and `appearance` are `<Checkout>`'s.
225
256
 
226
257
  ### Payment options
@@ -299,8 +330,22 @@ not report loading. Unchanged polls, callback replacements,
299
330
  and reconnecting alone do not trigger it. Use it to update your page without additional polling;
300
331
  fulfil from the `deposit.credited` webhook.
301
332
 
333
+ With `amountAtomic` (an amount of the token at `chainId` and `asset`, which then stay fixed), it
334
+ asks for that amount instead: the amount and network stated once, a `Pay with <wallet name>` button
335
+ (`walletClient`, `buttonText`, and `onWalletError` as `<Checkout>`'s), and "Pay from an exchange or
336
+ another wallet" revealing a QR code that requests exactly the amount and the address to copy (shown
337
+ at once when the browser has no wallet). With `clientSecret` and `apiBase` it follows that payment
338
+ (the wallet's transaction by its hash, else the newest payment that arrives after the address was
339
+ first read) on one status line, calls `onPaymentChange(payment)` as it changes and `onSuccess(payment)`
340
+ once it is credited, and replaces the ways to pay with that status once it is on its way.
341
+ `onSent(txHash, chainId)` reports the wallet's transaction; pass it back as `txHash` after a
342
+ reload to follow that payment again.
343
+
302
344
  `depositAddressTransfer(network, asset)` reads and checks one token's amount-less EIP-681
303
- `payment_uri` without React.
345
+ `payment_uri` without React; `payDepositAddressWithWallet(wallet, { network, asset, amountAtomic,
346
+ clientSecret?, apiBase? })` pays an amount of it from a wallet as `payWithWallet` pays a quote
347
+ (connect, switch chain, balance check, `transfer`), then, with `clientSecret` and `apiBase`, hints
348
+ the transaction with its `chain_id` without waiting on the hint, and resolves with the hash.
304
349
 
305
350
  ## Appearance
306
351
 
@@ -334,6 +379,7 @@ the theme (or map the colors) that suits its background.
334
379
  | `--pp-color-success` | `#15803d` | `#4ade80` | Credited icon |
335
380
  | `--pp-color-warning` | `#b45309` | `#fbbf24` | "Test mode" |
336
381
  | `--pp-color-danger` | `#dc2626` | `#f87171` | Failure icon, wallet errors |
382
+ | `--pp-color-icon-ring` | text color at 12% | same | Faint ring over a token or network logo's edge |
337
383
  | `--pp-font-family` | inherited | inherited | Font |
338
384
  | `--pp-font-family-mono` | `ui-monospace, …` | same | Addresses, amounts to copy, hashes |
339
385
  | `--pp-font-size` | `14px` | `14px` | Root text size; other text sizes are relative to it |
@@ -356,7 +402,10 @@ follow your page's text size. Keep `--pp-color-focus` distinct from `--pp-color-
356
402
  least 3:1 contrast to the background: it is how a keyboard user tells the focused choice from the
357
403
  selected one. Keep `--pp-color-input` at 3:1 or more against the background too, as WCAG 1.4.11
358
404
  asks of the edge that shows where a control is; `--pp-color-border` draws only dividers and may be
359
- fainter.
405
+ fainter. `--pp-color-icon-ring` is a 1px outline drawn inside each logo's edge, so that a logo
406
+ whose disc is the color of its background (PHA's black on a dark card, Ethereum's white on a light
407
+ one) stays round; it defaults to the surrounding text color at 12% opacity, so it follows the theme
408
+ and also applies to `AssetIcon` and `NetworkIcon` outside the components.
360
409
 
361
410
  ```css
362
411
  .pp-root[data-theme] {
@@ -386,8 +435,8 @@ group by group with what their wallet shows; selecting and copying it gives the
386
435
  spaces. The QR code keeps the standard quiet zone of four modules inside 8px of white, so it scans
387
436
  on a dark page too. The status row's text stays the body color on a neutral surface; its icon
388
437
  carries the tone. Transitions and the loading placeholder's pulse stop under
389
- `prefers-reduced-motion: reduce`, and the selected tab and a listbox's active option keep a system
390
- color in forced-colors mode.
438
+ `prefers-reduced-motion: reduce`, and the selected tab, a listbox's active option, and a logo's ring keep
439
+ a system color in forced-colors mode.
391
440
 
392
441
  ### Content Security Policy
393
442
 
package/dist/index.d.ts CHANGED
@@ -7,7 +7,7 @@ export { depositAddressTransfer, parseTransferUri, quoteTransfer, type DepositAd
7
7
  export { parseClientQuote, quoteIdFromClientSecret, type ClientQuote } from "./quote.js";
8
8
  export { assetIconName, assetName, assetSymbol, iconMonogram, type IconName } from "./icon-names.js";
9
9
  export { paymentOptionLabel, paymentOptions, samePaymentOption, type NetworkPaymentOption, type PaymentNetwork, type PaymentOption, } from "./options.js";
10
- export { INJECTED_WALLET_UUID, WalletError, payWithWallet, watchWallets, type EthereumProvider, type Wallet, type WalletErrorCode, type WalletInfo, } from "./wallet.js";
10
+ export { INJECTED_WALLET_UUID, WalletError, payDepositAddressWithWallet, payWithWallet, watchWallets, type EthereumProvider, type PayDepositAddressOptions, type Wallet, type WalletErrorCode, type WalletInfo, } from "./wallet.js";
11
11
  export { networkIcon, assetIcon } from "./icons.js";
12
12
  export type { CheckoutParams } from "./shared/checkout-params.js";
13
13
  export { submitTransaction, type SubmitTransactionOptions } from "./transactions.js";
@@ -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,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"}
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,2BAA2B,EAC3B,aAAa,EACb,YAAY,EACZ,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAC7B,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
@@ -7,7 +7,7 @@ export { depositAddressTransfer, parseTransferUri, quoteTransfer, } from "./paym
7
7
  export { parseClientQuote, quoteIdFromClientSecret } from "./quote.js";
8
8
  export { assetIconName, assetName, assetSymbol, iconMonogram } from "./icon-names.js";
9
9
  export { paymentOptionLabel, paymentOptions, samePaymentOption, } from "./options.js";
10
- export { INJECTED_WALLET_UUID, WalletError, payWithWallet, watchWallets, } from "./wallet.js";
10
+ export { INJECTED_WALLET_UUID, WalletError, payDepositAddressWithWallet, payWithWallet, watchWallets, } from "./wallet.js";
11
11
  export { networkIcon, assetIcon } from "./icons.js";
12
12
  export { submitTransaction } from "./transactions.js";
13
13
  //# sourceMappingURL=index.js.map
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,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"}
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,2BAA2B,EAC3B,aAAa,EACb,YAAY,GAMb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGpD,OAAO,EAAE,iBAAiB,EAAiC,MAAM,mBAAmB,CAAC"}
package/dist/wallet.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { type Hash, type WalletClient } from "viem";
2
+ import { type DepositAddressAsset, type DepositAddressNetwork } from "./payment.js";
2
3
  import type { ClientQuote } from "./quote.js";
3
4
  /** EIP-6963 provider info. */
4
5
  export interface WalletInfo {
@@ -43,4 +44,28 @@ export declare class WalletError extends Error {
43
44
  * it; the checkout's status follows the payment from there.
44
45
  */
45
46
  export declare function payWithWallet(wallet: WalletClient | EthereumProvider, quote: ClientQuote): Promise<Hash>;
47
+ export interface PayDepositAddressOptions {
48
+ /** The network to pay on, from the deposit address's `networks`. */
49
+ network: DepositAddressNetwork;
50
+ /** The token to pay in, from that network's `assets`. */
51
+ asset: DepositAddressAsset;
52
+ /** The token amount to send, in the smallest unit; positive. */
53
+ amountAtomic: bigint;
54
+ /**
55
+ * The address's `client_secret`. With `apiBase`, the transaction hash is sent to the service as
56
+ * a best-effort hint once the wallet broadcasts it, so the payment is found within about a block.
57
+ */
58
+ clientSecret?: string | undefined;
59
+ /** The service origin; needed with `clientSecret`. */
60
+ apiBase?: string | undefined;
61
+ }
62
+ /**
63
+ * Pays `amountAtomic` of a token to a customer's deposit address from a wallet, as `payWithWallet`
64
+ * pays a quote: connects, switches to (or adds) the network's chain, checks the token balance, and
65
+ * sends the ERC-20 `transfer` that the token's `payment_uri` states, for exactly that amount. Then,
66
+ * with `clientSecret` and `apiBase`, it hints the transaction to the service without waiting for
67
+ * or failing on it. Resolves with the transaction hash once the wallet has broadcast it; follow the
68
+ * payment in the address's `payments` by that hash.
69
+ */
70
+ export declare function payDepositAddressWithWallet(wallet: WalletClient | EthereumProvider, { network, asset, amountAtomic, clientSecret, apiBase }: PayDepositAddressOptions): Promise<Hash>;
46
71
  //# sourceMappingURL=wallet.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wallet.d.ts","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"AAEA,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,CAsCf"}
1
+ {"version":3,"file":"wallet.d.ts","sourceRoot":"","sources":["../src/wallet.ts"],"names":[],"mappings":"AAEA,OAAO,EAQL,KAAK,IAAI,EACT,KAAK,YAAY,EAClB,MAAM,MAAM,CAAC;AAId,OAAO,EAGL,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAE3B,MAAM,cAAc,CAAC;AACtB,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,CAIf;AAED,MAAM,WAAW,wBAAwB;IACvC,oEAAoE;IACpE,OAAO,EAAE,qBAAqB,CAAC;IAC/B,yDAAyD;IACzD,KAAK,EAAE,mBAAmB,CAAC;IAC3B,gEAAgE;IAChE,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,sDAAsD;IACtD,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,YAAY,GAAG,gBAAgB,EACvC,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,EAAE,wBAAwB,GAChF,OAAO,CAAC,IAAI,CAAC,CAYf"}
package/dist/wallet.js CHANGED
@@ -1,10 +1,10 @@
1
- import { submitWalletTransaction } from "./transactions.js";
1
+ import { submitTransaction, submitWalletTransaction } from "./transactions.js";
2
2
  import { createStore } from "mipd";
3
3
  import { BaseError, createWalletClient, custom, erc20Abi, SwitchChainError, UserRejectedRequestError, } from "viem";
4
4
  import { readContract } from "viem/actions";
5
5
  import { knownChain, networkName } from "./chains.js";
6
- import { formatTokenAmount, formatUnitsGrouped } from "./format.js";
7
- import { quoteTransfer } from "./payment.js";
6
+ import { formatUnitsGrouped } from "./format.js";
7
+ import { depositAddressTransfer, quoteTransfer, } from "./payment.js";
8
8
  /** The legacy `window.ethereum` provider, offered when no wallet announces itself (EIP-6963). */
9
9
  export const INJECTED_WALLET_UUID = "injected";
10
10
  /**
@@ -68,7 +68,30 @@ export class WalletError extends Error {
68
68
  * it; the checkout's status follows the payment from there.
69
69
  */
70
70
  export async function payWithWallet(wallet, quote) {
71
- const transfer = quoteTransfer(quote);
71
+ const hash = await sendTransfer(wallet, quoteTransfer(quote), quote.asset, quote.decimals);
72
+ submitWalletTransaction(quote, hash);
73
+ return hash;
74
+ }
75
+ /**
76
+ * Pays `amountAtomic` of a token to a customer's deposit address from a wallet, as `payWithWallet`
77
+ * pays a quote: connects, switches to (or adds) the network's chain, checks the token balance, and
78
+ * sends the ERC-20 `transfer` that the token's `payment_uri` states, for exactly that amount. Then,
79
+ * with `clientSecret` and `apiBase`, it hints the transaction to the service without waiting for
80
+ * or failing on it. Resolves with the transaction hash once the wallet has broadcast it; follow the
81
+ * payment in the address's `payments` by that hash.
82
+ */
83
+ export async function payDepositAddressWithWallet(wallet, { network, asset, amountAtomic, clientSecret, apiBase }) {
84
+ if (amountAtomic <= 0n) {
85
+ throw new TypeError("amountAtomic must be positive");
86
+ }
87
+ const transfer = { ...depositAddressTransfer(network, asset), amount: amountAtomic };
88
+ const hash = await sendTransfer(wallet, transfer, asset.asset, asset.decimals);
89
+ if (clientSecret !== undefined && apiBase !== undefined) {
90
+ void submitTransaction({ apiBase, clientSecret, transactionHash: hash, chainId: transfer.chainId }).catch(() => undefined);
91
+ }
92
+ return hash;
93
+ }
94
+ async function sendTransfer(wallet, transfer, asset, decimals) {
72
95
  const client = isWalletClient(wallet) ? wallet : createWalletClient({ transport: custom(wallet) });
73
96
  try {
74
97
  const account = client.account ?? (await client.requestAddresses())[0];
@@ -79,11 +102,11 @@ export async function payWithWallet(wallet, quote) {
79
102
  const address = typeof account === "string" ? account : account.address;
80
103
  const balance = await tokenBalance(client, transfer.token, address);
81
104
  if (balance !== undefined && balance < transfer.amount) {
82
- const symbol = quote.asset.toUpperCase();
83
- throw new WalletError("insufficient_balance", `Your wallet holds ${formatUnitsGrouped(balance, quote.decimals)} ${symbol}, less than the ` +
84
- `${formatTokenAmount(quote)} ${symbol} to pay. Nothing was sent.`);
105
+ const symbol = asset.toUpperCase();
106
+ throw new WalletError("insufficient_balance", `Your wallet holds ${formatUnitsGrouped(balance, decimals)} ${symbol}, less than the ` +
107
+ `${formatUnitsGrouped(transfer.amount, decimals)} ${symbol} to pay. Nothing was sent.`);
85
108
  }
86
- const hash = await client.writeContract({
109
+ return await client.writeContract({
87
110
  account,
88
111
  chain: knownChain(transfer.chainId) ?? null,
89
112
  address: transfer.token,
@@ -91,8 +114,6 @@ export async function payWithWallet(wallet, quote) {
91
114
  functionName: "transfer",
92
115
  args: [transfer.to, transfer.amount],
93
116
  });
94
- submitWalletTransaction(quote, hash);
95
- return hash;
96
117
  }
97
118
  catch (error) {
98
119
  if (error instanceof WalletError) {
@@ -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.11.3",
3
+ "version": "0.12.0",
4
4
  "description": "Phala Pay framework-free browser client",
5
5
  "keywords": [
6
6
  "crypto",
package/src/index.ts CHANGED
@@ -47,9 +47,11 @@ export {
47
47
  export {
48
48
  INJECTED_WALLET_UUID,
49
49
  WalletError,
50
+ payDepositAddressWithWallet,
50
51
  payWithWallet,
51
52
  watchWallets,
52
53
  type EthereumProvider,
54
+ type PayDepositAddressOptions,
53
55
  type Wallet,
54
56
  type WalletErrorCode,
55
57
  type WalletInfo,
package/src/wallet.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { submitWalletTransaction } from "./transactions.js";
1
+ import { submitTransaction, submitWalletTransaction } from "./transactions.js";
2
2
  import { createStore } from "mipd";
3
3
  import {
4
4
  BaseError,
@@ -13,8 +13,14 @@ import {
13
13
  } from "viem";
14
14
  import { readContract } from "viem/actions";
15
15
  import { knownChain, networkName } from "./chains.js";
16
- import { formatTokenAmount, formatUnitsGrouped } from "./format.js";
17
- import { quoteTransfer } from "./payment.js";
16
+ import { formatUnitsGrouped } from "./format.js";
17
+ import {
18
+ depositAddressTransfer,
19
+ quoteTransfer,
20
+ type DepositAddressAsset,
21
+ type DepositAddressNetwork,
22
+ type TokenTransfer,
23
+ } from "./payment.js";
18
24
  import type { ClientQuote } from "./quote.js";
19
25
 
20
26
  /** EIP-6963 provider info. */
@@ -119,7 +125,58 @@ export async function payWithWallet(
119
125
  wallet: WalletClient | EthereumProvider,
120
126
  quote: ClientQuote,
121
127
  ): Promise<Hash> {
122
- const transfer = quoteTransfer(quote);
128
+ const hash = await sendTransfer(wallet, quoteTransfer(quote), quote.asset, quote.decimals);
129
+ submitWalletTransaction(quote, hash);
130
+ return hash;
131
+ }
132
+
133
+ export interface PayDepositAddressOptions {
134
+ /** The network to pay on, from the deposit address's `networks`. */
135
+ network: DepositAddressNetwork;
136
+ /** The token to pay in, from that network's `assets`. */
137
+ asset: DepositAddressAsset;
138
+ /** The token amount to send, in the smallest unit; positive. */
139
+ amountAtomic: bigint;
140
+ /**
141
+ * The address's `client_secret`. With `apiBase`, the transaction hash is sent to the service as
142
+ * a best-effort hint once the wallet broadcasts it, so the payment is found within about a block.
143
+ */
144
+ clientSecret?: string | undefined;
145
+ /** The service origin; needed with `clientSecret`. */
146
+ apiBase?: string | undefined;
147
+ }
148
+
149
+ /**
150
+ * Pays `amountAtomic` of a token to a customer's deposit address from a wallet, as `payWithWallet`
151
+ * pays a quote: connects, switches to (or adds) the network's chain, checks the token balance, and
152
+ * sends the ERC-20 `transfer` that the token's `payment_uri` states, for exactly that amount. Then,
153
+ * with `clientSecret` and `apiBase`, it hints the transaction to the service without waiting for
154
+ * or failing on it. Resolves with the transaction hash once the wallet has broadcast it; follow the
155
+ * payment in the address's `payments` by that hash.
156
+ */
157
+ export async function payDepositAddressWithWallet(
158
+ wallet: WalletClient | EthereumProvider,
159
+ { network, asset, amountAtomic, clientSecret, apiBase }: PayDepositAddressOptions,
160
+ ): Promise<Hash> {
161
+ if (amountAtomic <= 0n) {
162
+ throw new TypeError("amountAtomic must be positive");
163
+ }
164
+ const transfer = { ...depositAddressTransfer(network, asset), amount: amountAtomic };
165
+ const hash = await sendTransfer(wallet, transfer, asset.asset, asset.decimals);
166
+ if (clientSecret !== undefined && apiBase !== undefined) {
167
+ void submitTransaction({ apiBase, clientSecret, transactionHash: hash, chainId: transfer.chainId }).catch(
168
+ () => undefined,
169
+ );
170
+ }
171
+ return hash;
172
+ }
173
+
174
+ async function sendTransfer(
175
+ wallet: WalletClient | EthereumProvider,
176
+ transfer: TokenTransfer,
177
+ asset: string,
178
+ decimals: number,
179
+ ): Promise<Hash> {
123
180
  const client = isWalletClient(wallet) ? wallet : createWalletClient({ transport: custom(wallet) });
124
181
  try {
125
182
  const account = client.account ?? (await client.requestAddresses())[0];
@@ -130,14 +187,14 @@ export async function payWithWallet(
130
187
  const address = typeof account === "string" ? account : account.address;
131
188
  const balance = await tokenBalance(client, transfer.token, address);
132
189
  if (balance !== undefined && balance < transfer.amount) {
133
- const symbol = quote.asset.toUpperCase();
190
+ const symbol = asset.toUpperCase();
134
191
  throw new WalletError(
135
192
  "insufficient_balance",
136
- `Your wallet holds ${formatUnitsGrouped(balance, quote.decimals)} ${symbol}, less than the ` +
137
- `${formatTokenAmount(quote)} ${symbol} to pay. Nothing was sent.`,
193
+ `Your wallet holds ${formatUnitsGrouped(balance, decimals)} ${symbol}, less than the ` +
194
+ `${formatUnitsGrouped(transfer.amount, decimals)} ${symbol} to pay. Nothing was sent.`,
138
195
  );
139
196
  }
140
- const hash = await client.writeContract({
197
+ return await client.writeContract({
141
198
  account,
142
199
  chain: knownChain(transfer.chainId) ?? null,
143
200
  address: transfer.token,
@@ -145,8 +202,6 @@ export async function payWithWallet(
145
202
  functionName: "transfer",
146
203
  args: [transfer.to, transfer.amount],
147
204
  });
148
- submitWalletTransaction(quote, hash);
149
- return hash;
150
205
  } catch (error) {
151
206
  if (error instanceof WalletError) {
152
207
  throw error;