@daimo/pay 1.2.0 → 1.3.1

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.
Files changed (49) hide show
  1. package/build/index.d.ts +21 -19
  2. package/build/package.json.js +3 -3
  3. package/build/src/components/Common/AmountInput/index.js +5 -1
  4. package/build/src/components/Common/AmountInput/index.js.map +1 -1
  5. package/build/src/components/DaimoPay.js +42 -12
  6. package/build/src/components/DaimoPay.js.map +1 -1
  7. package/build/src/components/DaimoPayButton/index.js +31 -24
  8. package/build/src/components/DaimoPayButton/index.js.map +1 -1
  9. package/build/src/components/DaimoPayModal/index.js +31 -25
  10. package/build/src/components/DaimoPayModal/index.js.map +1 -1
  11. package/build/src/components/Pages/Confirmation/index.js +1 -1
  12. package/build/src/components/Pages/PayWithToken/index.js +1 -1
  13. package/build/src/components/Pages/SelectDepositAddressAmount/index.js +3 -2
  14. package/build/src/components/Pages/SelectDepositAddressAmount/index.js.map +1 -1
  15. package/build/src/components/Pages/SelectDepositAddressChain/index.js +3 -2
  16. package/build/src/components/Pages/SelectDepositAddressChain/index.js.map +1 -1
  17. package/build/src/components/Pages/SelectExternalAmount/index.js +3 -2
  18. package/build/src/components/Pages/SelectExternalAmount/index.js.map +1 -1
  19. package/build/src/components/Pages/SelectMethod/index.js +10 -4
  20. package/build/src/components/Pages/SelectMethod/index.js.map +1 -1
  21. package/build/src/components/Pages/SelectToken/index.js +7 -2
  22. package/build/src/components/Pages/SelectToken/index.js.map +1 -1
  23. package/build/src/components/Pages/Solana/ConnectSolana/index.js +5 -2
  24. package/build/src/components/Pages/Solana/ConnectSolana/index.js.map +1 -1
  25. package/build/src/components/Pages/Solana/ConnectorSolana/index.js +5 -1
  26. package/build/src/components/Pages/Solana/ConnectorSolana/index.js.map +1 -1
  27. package/build/src/components/Pages/Solana/PayWithSolanaToken/index.js +4 -33
  28. package/build/src/components/Pages/Solana/PayWithSolanaToken/index.js.map +1 -1
  29. package/build/src/components/Pages/Solana/SelectSolanaToken/index.js +7 -2
  30. package/build/src/components/Pages/Solana/SelectSolanaToken/index.js.map +1 -1
  31. package/build/src/components/Pages/WaitingDepositAddress/index.js +1 -1
  32. package/build/src/components/Pages/WaitingExternal/index.js +1 -1
  33. package/build/src/hooks/useDaimoPayStatus.js +3 -16
  34. package/build/src/hooks/useDaimoPayStatus.js.map +1 -1
  35. package/build/src/hooks/usePayWithSolanaToken.js +4 -3
  36. package/build/src/hooks/usePayWithSolanaToken.js.map +1 -1
  37. package/build/src/hooks/usePayWithToken.js +7 -8
  38. package/build/src/hooks/usePayWithToken.js.map +1 -1
  39. package/build/src/hooks/usePaymentState.js +27 -20
  40. package/build/src/hooks/usePaymentState.js.map +1 -1
  41. package/build/src/index.js +1 -2
  42. package/build/src/index.js.map +1 -1
  43. package/build/src/utils/exports.js +1 -8
  44. package/build/src/utils/exports.js.map +1 -1
  45. package/build/src/utils/trpc.js +2 -1
  46. package/build/src/utils/trpc.js.map +1 -1
  47. package/package.json +4 -4
  48. package/build/src/hooks/useModal.js +0 -35
  49. package/build/src/hooks/useModal.js.map +0 -1
package/build/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import React$1, { ReactNode } from 'react';
2
2
  export { version } from '../package.json';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
- import { DaimoPayOrderMode, DepositAddressPaymentOptionMetadata, PlatformType, ExternalPaymentOptionMetadata, WalletPaymentOption, DaimoPayOrder, DaimoPayTokenAmount, ExternalPaymentOptions, DepositAddressPaymentOptions, DepositAddressPaymentOptionData, SolanaPublicKey, PaymentStartedEvent, PaymentCompletedEvent, PaymentBouncedEvent } from '@daimo/common';
4
+ import { DaimoPayOrderMode, DepositAddressPaymentOptionMetadata, PlatformType, ExternalPaymentOptionMetadata, WalletPaymentOption, DaimoPayOrder, DaimoPayTokenAmount, ExternalPaymentOptions, DepositAddressPaymentOptions, DepositAddressPaymentOptionData, SolanaPublicKey, DaimoPayUserMetadata, PaymentStartedEvent, PaymentCompletedEvent, PaymentBouncedEvent, DaimoPayIntentStatus } from '@daimo/common';
5
5
  import { Address, Hex } from 'viem';
6
6
  import { AppRouter } from '@daimo/pay-api';
7
7
  import { CreateTRPCClient } from '@trpc/client';
@@ -69,8 +69,6 @@ type DaimoPayContextOptions = {
69
69
  type DaimoPayModalOptions = {
70
70
  closeOnSuccess?: boolean;
71
71
  };
72
- /** Payment status. See webhooks and React useDaimoPayStatus() hook. */
73
- type PaymentStatus = "payment_pending" | "payment_started" | "payment_completed" | "payment_bounced";
74
72
  /** Additional payment options. Onchain payments are always enabled. */
75
73
  type PaymentOption = "Daimo" | "Coinbase" | "Binance" | "RampNetwork";
76
74
 
@@ -82,10 +80,9 @@ type types_d_DaimoPayModalOptions = DaimoPayModalOptions;
82
80
  type types_d_Languages = Languages;
83
81
  type types_d_Mode = Mode;
84
82
  type types_d_PaymentOption = PaymentOption;
85
- type types_d_PaymentStatus = PaymentStatus;
86
83
  type types_d_Theme = Theme;
87
84
  declare namespace types_d {
88
- export type { types_d_All as All, types_d_CustomAvatarProps as CustomAvatarProps, types_d_CustomTheme as CustomTheme, types_d_DaimoPayContextOptions as DaimoPayContextOptions, types_d_DaimoPayModalOptions as DaimoPayModalOptions, types_d_Languages as Languages, types_d_Mode as Mode, types_d_PaymentOption as PaymentOption, types_d_PaymentStatus as PaymentStatus, types_d_Theme as Theme };
85
+ export type { types_d_All as All, types_d_CustomAvatarProps as CustomAvatarProps, types_d_CustomTheme as CustomTheme, types_d_DaimoPayContextOptions as DaimoPayContextOptions, types_d_DaimoPayModalOptions as DaimoPayModalOptions, types_d_Languages as Languages, types_d_Mode as Mode, types_d_PaymentOption as PaymentOption, types_d_Theme as Theme };
89
86
  }
90
87
 
91
88
  type useConnectCallbackProps = {
@@ -175,6 +172,10 @@ interface PayParams {
175
172
  chain: number;
176
173
  address: Address;
177
174
  }[];
175
+ /** External ID. E.g. a correlation ID. */
176
+ externalId?: string;
177
+ /** Developer metadata. E.g. correlation ID. */
178
+ metadata?: DaimoPayUserMetadata;
178
179
  }
179
180
  /** Creates (or loads) a payment and manages the corresponding modal. */
180
181
  interface PaymentState {
@@ -256,9 +257,9 @@ type ContextValue = {
256
257
  lang: Languages;
257
258
  setLang: React$1.Dispatch<React$1.SetStateAction<Languages>>;
258
259
  open: boolean;
259
- setOpen: React$1.Dispatch<React$1.SetStateAction<boolean>>;
260
+ setOpen: (open: boolean, meta?: Record<string, any>) => void;
260
261
  route: string;
261
- setRoute: React$1.Dispatch<React$1.SetStateAction<ROUTES>>;
262
+ setRoute: (route: ROUTES, data?: Record<string, any>) => void;
262
263
  connector: Connector;
263
264
  setConnector: React$1.Dispatch<React$1.SetStateAction<Connector>>;
264
265
  errorMessage: Error;
@@ -267,6 +268,8 @@ type ContextValue = {
267
268
  displayError: (message: string | React$1.ReactNode | null, code?: any) => void;
268
269
  resize: number;
269
270
  triggerResize: () => void;
271
+ /** Session ID. */
272
+ sessionId: string;
270
273
  /** Chosen Solana wallet, eg Phantom.*/
271
274
  solanaConnector: SolanaWalletName | undefined;
272
275
  setSolanaConnector: React$1.Dispatch<React$1.SetStateAction<SolanaWalletName | undefined>>;
@@ -369,6 +372,14 @@ type PayButtonPaymentProps = {
369
372
  chain: number;
370
373
  address: Address;
371
374
  }[];
375
+ /**
376
+ * External ID. E.g. a correlation ID.
377
+ */
378
+ externalId?: string;
379
+ /**
380
+ * Developer metadata. E.g. correlation ID.
381
+ * */
382
+ metadata?: DaimoPayUserMetadata;
372
383
  } | {
373
384
  /** The payment ID, generated via the Daimo Pay API. Replaces params above. */
374
385
  payId: string;
@@ -421,7 +432,7 @@ declare namespace DaimoPayButtonCustom {
421
432
  /** Returns the current payment, or undefined if there is none.
422
433
  *
423
434
  * Status values:
424
- * - `payment_pending` - the user has not paid yet
435
+ * - `payment_unpaid` - the user has not paid yet
425
436
  * - `payment_started` - the user has paid & payment is in progress. This status
426
437
  * typically lasts a few seconds.
427
438
  * - `payment_completed` - the final call or transfer succeeded
@@ -430,16 +441,9 @@ declare namespace DaimoPayButtonCustom {
430
441
  */
431
442
  declare function useDaimoPayStatus(): {
432
443
  paymentId: string;
433
- status: PaymentStatus;
444
+ status: DaimoPayIntentStatus;
434
445
  } | undefined;
435
446
 
436
- type UseModalProps = {} & useConnectCallbackProps;
437
- /** Opens and closes the payment modal. */
438
- declare const useModal: ({ onConnect, onDisconnect }?: UseModalProps) => {
439
- open: boolean;
440
- setOpen: (show: boolean) => void;
441
- };
442
-
443
447
  /** Icon for an EVM chain, given chain ID. No ID shows a loading spinner. */
444
448
  declare const Chain: React$1.FC<{
445
449
  id?: number;
@@ -454,9 +458,7 @@ declare const wallets: {
454
458
  };
455
459
 
456
460
  declare const daimoPayVersion: string;
457
- /** Generates a globally-unique payId. */
458
- declare function generatePayId(): string;
459
461
  /** Chain ids supported by Daimo Pay. */
460
462
  declare const supportedChainIds: Set<number>;
461
463
 
462
- export { Avatar, Chain as ChainIcon, DaimoPayButton, Context as DaimoPayContext, DaimoPayProvider, types_d as Types, daimoPayVersion, generatePayId, defaultConfig as getDefaultConfig, supportedChainIds, useModal as useDaimoPayModal, useDaimoPayStatus, usePayContext, wallets };
464
+ export { Avatar, Chain as ChainIcon, DaimoPayButton, Context as DaimoPayContext, DaimoPayProvider, types_d as Types, daimoPayVersion, defaultConfig as getDefaultConfig, supportedChainIds, useDaimoPayStatus, usePayContext, wallets };
@@ -1,5 +1,5 @@
1
1
  var name = "@daimo/pay";
2
- var version = "1.2.0";
2
+ var version = "1.3.1";
3
3
  var author = "Daimo";
4
4
  var homepage = "https://pay.daimo.com";
5
5
  var license = "BSD-2-Clause license";
@@ -38,8 +38,8 @@ var keywords = [
38
38
  "crypto"
39
39
  ];
40
40
  var dependencies = {
41
- "@daimo/common": "1.1.1",
42
- "@daimo/contract": "1.1.1",
41
+ "@daimo/common": "1.3.1",
42
+ "@daimo/contract": "1.3.1",
43
43
  "@solana/wallet-adapter-base": "^0.9.23",
44
44
  "@solana/wallet-adapter-react": "^0.15.35",
45
45
  "@solana/web3.js": "^1.95.4",
@@ -98,7 +98,11 @@ const MultiCurrencySelectAmount = ({ selectedTokenOption, setSelectedTokenOption
98
98
  },
99
99
  });
100
100
  paymentState.setChosenUsd(usd);
101
- setRoute(nextPage);
101
+ setRoute(nextPage, {
102
+ amountUsd: usd,
103
+ amountUnits,
104
+ tokenSymbol: balanceToken.symbol,
105
+ });
102
106
  };
103
107
  return (jsxs(PageContent, { children: [jsx(TokenLogoSpinner, { token: balanceToken, showSpinner: false }), jsxs(ModalContent, { "$preserveDisplay": true, children: [jsxs(AmountInputContainer, { children: [jsx(MaxButton, { style: { visibility: "hidden" }, children: "Max" }), jsx(AmountInputField, { value: isEditingUsd ? usdValue : tokenValue, onChange: handleAmountChange, currency: isEditingUsd ? "$" : balanceToken.symbol, onKeyDown: handleKeyDown }), jsx(MaxButton, { onClick: handleMax, children: "Max" })] }), !isUsdStablecoin && (jsx(SwitchContainer, { children: jsx(SwitchButton, { onClick: handleSwitchCurrency, children: jsx(SecondaryAmount, { children: isEditingUsd
104
108
  ? `${tokenValue} ${balanceToken.symbol}`
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
- import { DaimoPayOrderMode, DaimoPayOrderStatusSource, DaimoPayIntentStatus, retryBackoff, debugJson } from '@daimo/common';
2
+ import { DaimoPayOrderMode, DaimoPayIntentStatus, retryBackoff, debugJson, DaimoPayOrderStatusSource } from '@daimo/common';
3
3
  import { Buffer } from 'buffer';
4
- import React, { createContext, useState, useEffect, useMemo, createElement } from 'react';
4
+ import React, { createContext, useState, useEffect, useMemo, useCallback, createElement } from 'react';
5
5
  import { ThemeProvider } from 'styled-components';
6
6
  import { WagmiContext, useAccount } from 'wagmi';
7
7
  import { REQUIRED_CHAINS } from '../defaultConfig.js';
@@ -103,12 +103,30 @@ const DaimoPayProviderWithoutSolana = ({ children, theme = "auto", mode = "auto"
103
103
  const [ckMode, setMode] = useState(mode);
104
104
  const [ckCustomTheme, setCustomTheme] = useState(customTheme ?? {});
105
105
  const [ckLang, setLang] = useState("en-US");
106
- const [open, setOpen] = useState(false);
106
+ const [open, setOpenState] = useState(false);
107
+ const setOpen = (open, meta) => {
108
+ setOpenState(open);
109
+ trpc.nav.mutate({
110
+ action: open ? "navOpenPay" : "navClosePay",
111
+ orderId: daimoPayOrder?.id?.toString(),
112
+ data: meta ?? {},
113
+ });
114
+ };
107
115
  const [connector, setConnector] = useState({
108
116
  id: "",
109
117
  });
110
118
  const [solanaConnector, setSolanaConnector] = useState();
111
- const [route, setRoute] = useState(ROUTES.SELECT_METHOD);
119
+ const [route, setRouteState] = useState(ROUTES.SELECT_METHOD);
120
+ const setRoute = (route, data) => {
121
+ const action = route.replace("daimoPay", "");
122
+ log(`[SET ROUTE] ${action} ${daimoPayOrder?.id} ${debugJson(data ?? {})}`);
123
+ trpc.nav.mutate({
124
+ action,
125
+ orderId: daimoPayOrder?.id?.toString(),
126
+ data: data ?? {},
127
+ });
128
+ setRouteState(route);
129
+ };
112
130
  const [errorMessage, setErrorMessage] = useState("");
113
131
  const [confirmationMessage, setConfirmationMessage] = useState(undefined);
114
132
  const [resize, onResize] = useState(0);
@@ -129,13 +147,23 @@ const DaimoPayProviderWithoutSolana = ({ children, theme = "auto", mode = "auto"
129
147
  }
130
148
  }, [isConnected, isChainSupported, chain, route, open]);
131
149
  const log = debugMode ? console.log : () => { };
150
+ // Track sessions. Each generates separate intent IDs unless using externalId.
151
+ const [sessionId] = useState(() => crypto.randomUUID().replaceAll("-", ""));
132
152
  // Connect to the Daimo Pay TRPC API
133
- const trpc = useMemo(() => createTrpcClient(payApiUrl), [payApiUrl]);
153
+ const trpc = useMemo(() => createTrpcClient(payApiUrl, sessionId), [payApiUrl]);
134
154
  // PaymentInfo is a second, inner context object containing a DaimoPayOrder
135
155
  // plus all associated status and callbacks. In order for useContext() and
136
156
  // downstream hooks like useDaimoPayStatus() to work correctly, we must set
137
157
  // set refresh context when payment status changes; done via setDaimoPayOrder.
138
- const [daimoPayOrder, setDaimoPayOrder] = useState();
158
+ const [daimoPayOrder, setDaimoPayOrderInner] = useState();
159
+ const setDaimoPayOrder = useCallback((order) => {
160
+ setDaimoPayOrderInner(order);
161
+ let extra = `> $${order.destFinalCallTokenAmount.usd.toFixed(2)} to ${order.destFinalCallTokenAmount.token.chainId} ${order.destFinalCall.to}`;
162
+ if (order.mode === DaimoPayOrderMode.HYDRATED) {
163
+ extra += ` via ${order.intentAddr} ${order.sourceStatus} ${order.intentStatus}`;
164
+ }
165
+ log(`[PAY] setDaimoPayOrder: ${order.id} ${extra}`);
166
+ }, [setDaimoPayOrderInner]);
139
167
  const paymentState = usePaymentState({
140
168
  trpc,
141
169
  daimoPayOrder,
@@ -149,13 +177,13 @@ const DaimoPayProviderWithoutSolana = ({ children, theme = "auto", mode = "auto"
149
177
  // Order just updated...
150
178
  if (daimoPayOrder?.mode !== DaimoPayOrderMode.HYDRATED)
151
179
  return;
152
- const { sourceStatus, intentStatus } = daimoPayOrder;
180
+ const { intentStatus } = daimoPayOrder;
153
181
  let intervalMs = 0;
154
- if (sourceStatus === DaimoPayOrderStatusSource.WAITING_PAYMENT) {
155
- intervalMs = 2500; // additional, faster polling in WaitingOther
182
+ if (intentStatus === DaimoPayIntentStatus.UNPAID) {
183
+ intervalMs = 2000; // additional, faster polling in WaitingOther
156
184
  }
157
- else if (intentStatus === DaimoPayIntentStatus.PENDING) {
158
- intervalMs = 300; // poll fast from (payment initiated) to (finished)
185
+ else if (intentStatus === DaimoPayIntentStatus.STARTED) {
186
+ intervalMs = 300; // poll fast from payment started to payment completed
159
187
  }
160
188
  else {
161
189
  return;
@@ -169,6 +197,7 @@ const DaimoPayProviderWithoutSolana = ({ children, theme = "auto", mode = "auto"
169
197
  const id = daimoPayOrder?.id;
170
198
  log(`[PAY] showing payment ${debugJson({ id, modalOptions })}`);
171
199
  paymentState.setModalOptions(modalOptions);
200
+ setOpen(true);
172
201
  if (daimoPayOrder &&
173
202
  daimoPayOrder.mode === DaimoPayOrderMode.HYDRATED &&
174
203
  (daimoPayOrder.sourceStatus !==
@@ -180,7 +209,6 @@ const DaimoPayProviderWithoutSolana = ({ children, theme = "auto", mode = "auto"
180
209
  else {
181
210
  setRoute(ROUTES.SELECT_METHOD);
182
211
  }
183
- setOpen(true);
184
212
  };
185
213
  const value = {
186
214
  theme: ckTheme,
@@ -196,6 +224,8 @@ const DaimoPayProviderWithoutSolana = ({ children, theme = "auto", mode = "auto"
196
224
  route,
197
225
  setRoute,
198
226
  connector,
227
+ // Daimo Pay context
228
+ sessionId,
199
229
  setConnector,
200
230
  solanaConnector,
201
231
  setSolanaConnector,
@@ -1 +1 @@
1
- {"version":3,"file":"DaimoPay.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"DaimoPay.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -2,7 +2,7 @@ import { jsx } from 'react/jsx-runtime';
2
2
  import { useEffect } from 'react';
3
3
  import { usePayContext } from '../DaimoPay.js';
4
4
  import { TextContainer } from './styles.js';
5
- import { DaimoPayOrderMode, DaimoPayOrderStatusSource, writeDaimoPayOrderID, assertNotNull, DaimoPayIntentStatus } from '@daimo/common';
5
+ import { DaimoPayOrderMode, DaimoPayIntentStatus, writeDaimoPayOrderID, assertNotNull, getDaimoPayOrderView } from '@daimo/common';
6
6
  import { AnimatePresence } from 'framer-motion';
7
7
  import { ResetContainer } from '../../styles/index.js';
8
8
  import ThemedButton from '../Common/ThemedButton/index.js';
@@ -34,6 +34,8 @@ function DaimoPayButtonCustom(props) {
34
34
  paymentOptions: props.paymentOptions,
35
35
  preferredChains: props.preferredChains,
36
36
  preferredTokens: props.preferredTokens,
37
+ externalId: props.externalId,
38
+ metadata: props.metadata,
37
39
  }
38
40
  : null;
39
41
  let payId = "payId" in props ? props.payId : null;
@@ -45,7 +47,7 @@ function DaimoPayButtonCustom(props) {
45
47
  else if (payParams != null) {
46
48
  paymentState.setPayParams(payParams);
47
49
  }
48
- }, [payId, ...Object.values(payParams || {})]);
50
+ }, [payId, ...JSON.stringify(payParams || {})]);
49
51
  const { setConfirmationMessage } = context;
50
52
  useEffect(() => {
51
53
  if (props.confirmationMessage) {
@@ -55,8 +57,8 @@ function DaimoPayButtonCustom(props) {
55
57
  // Payment events: call these three event handlers.
56
58
  const { onPaymentStarted, onPaymentCompleted, onPaymentBounced } = props;
57
59
  const order = paymentState.daimoPayOrder;
60
+ const intentStatus = order?.intentStatus;
58
61
  const hydOrder = order?.mode === DaimoPayOrderMode.HYDRATED ? order : null;
59
- const isStarted = hydOrder?.sourceStatus !== DaimoPayOrderStatusSource.WAITING_PAYMENT;
60
62
  // Functions to show and hide the modal
61
63
  const { children, closeOnSuccess } = props;
62
64
  const modalOptions = { closeOnSuccess };
@@ -66,33 +68,38 @@ function DaimoPayButtonCustom(props) {
66
68
  context.showPayment(modalOptions);
67
69
  };
68
70
  const hide = () => context.setOpen(false);
69
- useEffect(() => {
70
- if (hydOrder == null || !isStarted)
71
- return;
72
- onPaymentStarted?.({
73
- paymentId: writeDaimoPayOrderID(hydOrder.id),
74
- type: "payment_started",
75
- chainId: assertNotNull(hydOrder.sourceTokenAmount).token.chainId,
76
- txHash: assertNotNull(hydOrder.sourceInitiateTxHash),
77
- });
78
- }, [isStarted]);
71
+ // Emit event handlers when payment status changes
79
72
  useEffect(() => {
80
73
  if (hydOrder == null)
81
74
  return;
82
- if (hydOrder.intentStatus === DaimoPayIntentStatus.PENDING)
75
+ if (intentStatus === DaimoPayIntentStatus.UNPAID)
83
76
  return;
84
- const commonFields = {
85
- paymentId: writeDaimoPayOrderID(hydOrder.id),
86
- chainId: assertNotNull(hydOrder.destFinalCallTokenAmount).token.chainId,
87
- txHash: assertNotNull(hydOrder.destFastFinishTxHash ?? hydOrder.destClaimTxHash),
88
- };
89
- if (hydOrder.intentStatus === DaimoPayIntentStatus.SUCCESSFUL) {
90
- onPaymentCompleted?.({ type: "payment_completed", ...commonFields });
77
+ if (intentStatus === DaimoPayIntentStatus.STARTED) {
78
+ onPaymentStarted?.({
79
+ type: DaimoPayIntentStatus.STARTED,
80
+ paymentId: writeDaimoPayOrderID(hydOrder.id),
81
+ chainId: hydOrder.destFinalCallTokenAmount.token.chainId,
82
+ txHash: assertNotNull(hydOrder.sourceInitiateTxHash, `[PAY BUTTON] source initiate tx hash null on order ${hydOrder.id} when intent status is ${intentStatus}`),
83
+ payment: getDaimoPayOrderView(hydOrder),
84
+ });
91
85
  }
92
- else if (hydOrder.intentStatus === DaimoPayIntentStatus.REFUNDED) {
93
- onPaymentBounced?.({ type: "payment_bounced", ...commonFields });
86
+ else if (intentStatus === DaimoPayIntentStatus.COMPLETED ||
87
+ intentStatus === DaimoPayIntentStatus.BOUNCED) {
88
+ const event = {
89
+ type: intentStatus,
90
+ paymentId: writeDaimoPayOrderID(hydOrder.id),
91
+ chainId: hydOrder.destFinalCallTokenAmount.token.chainId,
92
+ txHash: assertNotNull(hydOrder.destFastFinishTxHash ?? hydOrder.destClaimTxHash, `[PAY BUTTON] dest tx hash null on order ${hydOrder.id} when intent status is ${intentStatus}`),
93
+ payment: getDaimoPayOrderView(hydOrder),
94
+ };
95
+ if (intentStatus === DaimoPayIntentStatus.COMPLETED) {
96
+ onPaymentCompleted?.(event);
97
+ }
98
+ else if (intentStatus === DaimoPayIntentStatus.BOUNCED) {
99
+ onPaymentBounced?.(event);
100
+ }
94
101
  }
95
- }, [hydOrder?.intentStatus]);
102
+ }, [hydOrder?.id, intentStatus]);
96
103
  useEffect(() => {
97
104
  if (props.defaultOpen) {
98
105
  show();
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -35,7 +35,7 @@ const DaimoPayModal = ({ mode = "auto", theme = "auto", customTheme = customThem
35
35
  const context = usePayContext();
36
36
  const paymentState = context.paymentState;
37
37
  const { payParams, generatePreviewOrder, isDepositFlow, setPaymentWaitingMessage, setSelectedExternalOption, setSelectedTokenOption, setSelectedSolanaTokenOption, setSelectedDepositAddressOption, } = paymentState;
38
- const { isConnected, chain } = useAccount();
38
+ const { isConnected, connector, chain, address } = useAccount();
39
39
  const chainIsSupported = useChainIsSupported(chain?.id);
40
40
  //if chain is unsupported we enforce a "switch chain" prompt
41
41
  const closeable = !(context.options?.enforceSupportedChains &&
@@ -45,81 +45,82 @@ const DaimoPayModal = ({ mode = "auto", theme = "auto", customTheme = customThem
45
45
  context.route !== ROUTES.SELECT_METHOD &&
46
46
  context.route !== ROUTES.CONFIRMATION;
47
47
  const onBack = () => {
48
+ const meta = { event: "click-back" };
48
49
  if (context.route === ROUTES.DOWNLOAD) {
49
- context.setRoute(ROUTES.CONNECT);
50
+ context.setRoute(ROUTES.CONNECT, meta);
50
51
  }
51
52
  else if (context.route === ROUTES.CONNECTORS) {
52
- context.setRoute(ROUTES.SELECT_METHOD);
53
+ context.setRoute(ROUTES.SELECT_METHOD, meta);
53
54
  }
54
55
  else if (context.route === ROUTES.SELECT_TOKEN) {
55
- context.setRoute(ROUTES.SELECT_METHOD);
56
+ context.setRoute(ROUTES.SELECT_METHOD, meta);
56
57
  }
57
58
  else if (context.route === ROUTES.SELECT_AMOUNT) {
58
59
  setSelectedTokenOption(undefined);
59
- context.setRoute(ROUTES.SELECT_TOKEN);
60
+ context.setRoute(ROUTES.SELECT_TOKEN, meta);
60
61
  }
61
62
  else if (context.route === ROUTES.SELECT_EXTERNAL_AMOUNT) {
62
63
  setSelectedExternalOption(undefined);
63
- context.setRoute(ROUTES.SELECT_METHOD);
64
+ context.setRoute(ROUTES.SELECT_METHOD, meta);
64
65
  }
65
66
  else if (context.route === ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT) {
66
67
  setSelectedDepositAddressOption(undefined);
67
- context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN);
68
+ context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN, meta);
68
69
  }
69
70
  else if (context.route === ROUTES.WAITING_EXTERNAL) {
70
71
  setPaymentWaitingMessage(undefined);
71
72
  if (isDepositFlow) {
72
- assert(payParams != null, "payParams cannot be null in deposit flow");
73
+ assert(payParams != null, "[PAY MODAL] payParams cannot be null in deposit flow");
73
74
  generatePreviewOrder(payParams);
74
- context.setRoute(ROUTES.SELECT_EXTERNAL_AMOUNT);
75
+ context.setRoute(ROUTES.SELECT_EXTERNAL_AMOUNT, meta);
75
76
  }
76
77
  else {
77
78
  setSelectedExternalOption(undefined);
78
- context.setRoute(ROUTES.SELECT_METHOD);
79
+ context.setRoute(ROUTES.SELECT_METHOD, meta);
79
80
  }
80
81
  }
81
82
  else if (context.route === ROUTES.PAY_WITH_TOKEN) {
82
83
  if (isDepositFlow) {
83
- assert(payParams != null, "payParams cannot be null in deposit flow");
84
+ assert(payParams != null, "[PAY MODAL] payParams cannot be null in deposit flow");
84
85
  generatePreviewOrder(payParams);
85
- context.setRoute(ROUTES.SELECT_AMOUNT);
86
+ context.setRoute(ROUTES.SELECT_AMOUNT, meta);
86
87
  }
87
88
  else {
88
89
  setSelectedTokenOption(undefined);
89
- context.setRoute(ROUTES.SELECT_TOKEN);
90
+ context.setRoute(ROUTES.SELECT_TOKEN, meta);
90
91
  }
91
92
  }
92
93
  else if (context.route === ROUTES.ONBOARDING) {
93
- context.setRoute(ROUTES.CONNECTORS);
94
+ context.setRoute(ROUTES.CONNECTORS, meta);
94
95
  }
95
96
  else if (context.route === ROUTES.WAITING_DEPOSIT_ADDRESS) {
96
97
  if (isDepositFlow) {
97
- assert(payParams != null, "payParams cannot be null in deposit flow");
98
+ assert(payParams != null, "[PAY MODAL] payParams cannot be null in deposit flow");
98
99
  generatePreviewOrder(payParams);
99
- context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT);
100
+ context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT, meta);
100
101
  }
101
102
  else {
102
103
  setSelectedDepositAddressOption(undefined);
103
- context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN);
104
+ context.setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_CHAIN, meta);
104
105
  }
105
106
  }
106
107
  else if (context.route === ROUTES.SOLANA_SELECT_AMOUNT) {
107
108
  setSelectedSolanaTokenOption(undefined);
108
- context.setRoute(ROUTES.SOLANA_SELECT_TOKEN);
109
+ context.setRoute(ROUTES.SOLANA_SELECT_TOKEN, meta);
109
110
  }
110
111
  else if (context.route === ROUTES.SOLANA_PAY_WITH_TOKEN) {
111
112
  if (isDepositFlow) {
112
- assert(payParams != null, "payParams cannot be null in deposit flow");
113
+ assert(payParams != null, "[PAY MODAL] payParams cannot be null in deposit flow");
113
114
  generatePreviewOrder(payParams);
114
- context.setRoute(ROUTES.SOLANA_SELECT_AMOUNT);
115
+ context.setRoute(ROUTES.SOLANA_SELECT_AMOUNT, meta);
115
116
  }
116
117
  else {
117
118
  setSelectedSolanaTokenOption(undefined);
118
- context.setRoute(ROUTES.SOLANA_SELECT_TOKEN);
119
+ context.setRoute(ROUTES.SOLANA_SELECT_TOKEN, meta);
119
120
  }
120
121
  }
121
122
  else {
122
- context.setRoute(ROUTES.SELECT_METHOD);
123
+ context.setRoute(ROUTES.SELECT_METHOD, meta);
123
124
  }
124
125
  };
125
126
  const pages = {
@@ -149,17 +150,22 @@ const DaimoPayModal = ({ mode = "auto", theme = "auto", customTheme = customThem
149
150
  };
150
151
  function hide() {
151
152
  if (isDepositFlow) {
152
- assert(payParams != null, "payParams cannot be null in deposit flow");
153
+ assert(payParams != null, "[PAY MODAL] payParams cannot be null in deposit flow");
153
154
  generatePreviewOrder(payParams);
154
155
  }
155
- context.setOpen(false);
156
+ context.setOpen(false, { event: "click-close" });
156
157
  }
157
158
  useEffect(() => {
158
159
  if (context.route === ROUTES.CONNECT ||
159
160
  context.route === ROUTES.CONNECTORS ||
160
161
  context.route === ROUTES.MOBILECONNECTORS) {
161
162
  if (isConnected) {
162
- context.setRoute(ROUTES.SELECT_TOKEN);
163
+ context.setRoute(ROUTES.SELECT_TOKEN, {
164
+ event: "connected",
165
+ walletId: connector?.id,
166
+ chainId: chain?.id,
167
+ address,
168
+ });
163
169
  }
164
170
  }
165
171
  }, [isConnected, context.route]);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -21,7 +21,7 @@ const Confirmation = () => {
21
21
  destStatus === DaimoPayOrderStatusDest.CLAIM_SUCCESSFUL) {
22
22
  const txHash = daimoPayOrder.destFastFinishTxHash ?? daimoPayOrder.destClaimTxHash;
23
23
  const chainId = daimoPayOrder.destFinalCallTokenAmount.token.chainId;
24
- assert(txHash != null, `Dest ${destStatus}, but missing txHash`);
24
+ assert(txHash != null, `[CONFIRMATION] dest status: ${destStatus}, but missing txHash`);
25
25
  const txURL = getChainExplorerTxUrl(chainId, txHash);
26
26
  paymentState.onSuccess({ txHash, txURL });
27
27
  return {
@@ -53,7 +53,7 @@ const PayWithToken = () => {
53
53
  await payWithToken(option.required);
54
54
  setPayState(PayState.RequestSuccessful);
55
55
  setTimeout(() => {
56
- setRoute(ROUTES.CONFIRMATION);
56
+ setRoute(ROUTES.CONFIRMATION, { event: "wait-pay-with-token" });
57
57
  }, 200);
58
58
  }
59
59
  catch (e) {
@@ -45,8 +45,9 @@ const SelectDepositAddressAmount = () => {
45
45
  }
46
46
  };
47
47
  const handleContinue = () => {
48
- paymentState.setChosenUsd(Number(sanitizeNumber(usdInput)));
49
- setRoute(ROUTES.WAITING_DEPOSIT_ADDRESS);
48
+ const amountUsd = Number(sanitizeNumber(usdInput));
49
+ paymentState.setChosenUsd(amountUsd);
50
+ setRoute(ROUTES.WAITING_DEPOSIT_ADDRESS, { amountUsd });
50
51
  };
51
52
  return (jsxs(PageContent, { children: [jsx(ExternalPaymentSpinner, { logoURI: selectedDepositAddressOption.logoURI, logoShape: "circle", showSpinner: false }), jsxs(ModalContent, { "$preserveDisplay": true, children: [jsx(AmountInputContainer, { children: jsx(AmountInputField, { value: usdInput, onChange: handleAmountChange, onKeyDown: handleKeyDown }) }), message && jsx(ModalBody, { children: message }), jsx(Button, { onClick: handleContinue, disabled: continueDisabled, children: "Continue" })] })] }));
52
53
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -22,11 +22,12 @@ const SelectDepositAddressChain = () => {
22
22
  icons: [option.logoURI],
23
23
  onClick: () => {
24
24
  setSelectedDepositAddressOption(option);
25
+ const meta = { event: "click-option", option: option.id };
25
26
  if (isDepositFlow) {
26
- setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT);
27
+ setRoute(ROUTES.SELECT_DEPOSIT_ADDRESS_AMOUNT, meta);
27
28
  }
28
29
  else {
29
- setRoute(ROUTES.WAITING_DEPOSIT_ADDRESS);
30
+ setRoute(ROUTES.WAITING_DEPOSIT_ADDRESS, meta);
30
31
  }
31
32
  },
32
33
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -47,8 +47,9 @@ const SelectExternalAmount = () => {
47
47
  }
48
48
  };
49
49
  const handleContinue = () => {
50
- paymentState.setChosenUsd(Number(sanitizeNumber(usdInput)));
51
- setRoute(ROUTES.WAITING_EXTERNAL);
50
+ const amountUsd = Number(sanitizeNumber(usdInput));
51
+ paymentState.setChosenUsd(amountUsd);
52
+ setRoute(ROUTES.WAITING_EXTERNAL, { amountUsd });
52
53
  };
53
54
  return (jsxs(PageContent, { children: [jsx(ExternalPaymentSpinner, { logoURI: selectedExternalOption.logoURI, logoShape: selectedExternalOption.logoShape, showSpinner: false }), jsxs(ModalContent, { "$preserveDisplay": true, children: [jsx(AmountInputContainer, { children: jsx(AmountInputField, { value: usdInput, onChange: handleAmountChange, onKeyDown: handleKeyDown }) }), message && jsx(ModalBody, { children: message }), jsx(Button, { onClick: handleContinue, disabled: continueDisabled, children: "Continue" })] })] }));
54
55
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -64,7 +64,7 @@ function getDepositAddressOption(depositAddressOptions) {
64
64
  }
65
65
  const SelectMethod = () => {
66
66
  const isMobile = useIsMobile();
67
- const { address, isConnected, connector } = useAccount();
67
+ const { address, chain, isConnected, connector } = useAccount();
68
68
  const { disconnectAsync } = useDisconnect();
69
69
  const { setRoute, paymentState, log } = usePayContext();
70
70
  const { setSelectedExternalOption, externalPaymentOptions, depositAddressOptions, senderEnsName, } = paymentState;
@@ -75,7 +75,12 @@ const SelectMethod = () => {
75
75
  title: `Pay with ${displayName}`,
76
76
  icons: connector && connector.icon ? [connector.icon] : [jsx(MetaMask, {})],
77
77
  onClick: () => {
78
- setRoute(ROUTES.SELECT_TOKEN);
78
+ setRoute(ROUTES.SELECT_TOKEN, {
79
+ event: "click-wallet",
80
+ walletId: connector?.id,
81
+ chainId: chain?.id,
82
+ address: address,
83
+ });
79
84
  },
80
85
  }
81
86
  : null;
@@ -103,11 +108,12 @@ const SelectMethod = () => {
103
108
  icons: [option.logoURI],
104
109
  onClick: () => {
105
110
  setSelectedExternalOption(option);
111
+ const meta = { event: "click-option", option: option.id };
106
112
  if (paymentState.isDepositFlow) {
107
- setRoute(ROUTES.SELECT_EXTERNAL_AMOUNT);
113
+ setRoute(ROUTES.SELECT_EXTERNAL_AMOUNT, meta);
108
114
  }
109
115
  else {
110
- setRoute(ROUTES.WAITING_EXTERNAL);
116
+ setRoute(ROUTES.WAITING_EXTERNAL, meta);
111
117
  }
112
118
  },
113
119
  disabled: option.disabled,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}