@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
@@ -34,11 +34,16 @@ const SelectToken = () => {
34
34
  ],
35
35
  onClick: () => {
36
36
  setSelectedTokenOption(option);
37
+ const meta = {
38
+ event: "click-token",
39
+ tokenSymbol: option.balance.token.symbol,
40
+ chainId: option.balance.token.chainId,
41
+ };
37
42
  if (isDepositFlow) {
38
- setRoute(ROUTES.SELECT_AMOUNT);
43
+ setRoute(ROUTES.SELECT_AMOUNT, meta);
39
44
  }
40
45
  else {
41
- setRoute(ROUTES.PAY_WITH_TOKEN);
46
+ setRoute(ROUTES.PAY_WITH_TOKEN, meta);
42
47
  }
43
48
  },
44
49
  disabled,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -20,7 +20,10 @@ const ConnectSolana = () => {
20
20
  if (solanaWallets.connected) {
21
21
  await solanaWallets.disconnect();
22
22
  }
23
- setRoute(ROUTES.SOLANA_CONNECTOR);
23
+ setRoute(ROUTES.SOLANA_CONNECTOR, {
24
+ event: "click-solana-wallet",
25
+ walletName: wallet.adapter.name,
26
+ });
24
27
  },
25
28
  }));
26
29
  return (jsxs(PageContent, { children: [jsx(OrderHeader, { minified: true }), solanaWallets.wallets.length === 0 && (jsxs(ModalContent, { style: {
@@ -29,7 +32,7 @@ const ConnectSolana = () => {
29
32
  justifyContent: "center",
30
33
  paddingTop: 16,
31
34
  paddingBottom: 16,
32
- }, children: [jsx(ModalH1, { children: "No Solana wallets detected." }), jsx(Button, { onClick: () => setRoute(ROUTES.SELECT_METHOD), children: "Select Another Method" })] })), jsx(OptionsList, { options: options })] }));
35
+ }, children: [jsx(ModalH1, { children: "No Solana wallets detected." }), jsx(Button, { onClick: () => setRoute(ROUTES.SELECT_METHOD, { event: "click-select-another" }), children: "Select Another Method" })] })), jsx(OptionsList, { options: options })] }));
33
36
  };
34
37
  const SquircleIcon = ({ icon, alt }) => (jsx("div", { style: { borderRadius: "22.5%", overflow: "hidden" }, children: jsx("img", { src: icon, alt: alt }) }));
35
38
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -20,7 +20,11 @@ const ConnectSolana = () => {
20
20
  useEffect(() => {
21
21
  if (isConnected) {
22
22
  // Wait so user can see it's connected
23
- setTimeout(() => setRoute(ROUTES.SOLANA_SELECT_TOKEN), 500);
23
+ const meta = {
24
+ event: "wait-solana-connected",
25
+ walletName: solanaWallets.wallet?.adapter.name,
26
+ };
27
+ setTimeout(() => setRoute(ROUTES.SOLANA_SELECT_TOKEN, meta), 500);
24
28
  }
25
29
  }, [isConnected]);
26
30
  if (!solanaConnector)
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -4,9 +4,6 @@ import { usePayContext, ROUTES } from '../../../DaimoPay.js';
4
4
  import { WalletSignTransactionError, WalletSendTransactionError } from '@solana/wallet-adapter-base';
5
5
  import { PageContent, ModalContent, ModalH1 } from '../../../Common/Modal/styles.js';
6
6
  import { assert } from '@daimo/common';
7
- import { motion } from 'framer-motion';
8
- import { css } from 'styled-components';
9
- import styled from '../../../../styles/styled/index.js';
10
7
  import Button from '../../../Common/Button/index.js';
11
8
  import PaymentBreakdown from '../../../Common/PaymentBreakdown/index.js';
12
9
  import TokenLogoSpinner from '../../../Spinners/TokenLogoSpinner/index.js';
@@ -25,11 +22,11 @@ const PayWithSolanaToken = () => {
25
22
  const handleTransfer = async () => {
26
23
  try {
27
24
  setPayState(PayState.RequestingPayment);
28
- assert(!!selectedSolanaTokenOption, "No token option selected");
25
+ assert(!!selectedSolanaTokenOption, "[PAY SOLANA] No token option selected");
29
26
  await payWithSolanaToken(selectedSolanaTokenOption.required.token.token);
30
27
  setPayState(PayState.RequestSuccessful);
31
28
  setTimeout(() => {
32
- setRoute(ROUTES.CONFIRMATION);
29
+ setRoute(ROUTES.CONFIRMATION, { event: "wait-pay-with-solana" });
33
30
  }, 200);
34
31
  }
35
32
  catch (error) {
@@ -55,37 +52,11 @@ const PayWithSolanaToken = () => {
55
52
  triggerResize();
56
53
  }, [payState]);
57
54
  return (jsxs(PageContent, { children: [selectedSolanaTokenOption && (jsx(TokenLogoSpinner, { token: selectedSolanaTokenOption.required.token })), jsxs(ModalContent, { style: { paddingBottom: 0 }, children: [jsx(ModalH1, { children: payState }), selectedSolanaTokenOption && (jsx(PaymentBreakdown, { paymentOption: selectedSolanaTokenOption })), payState === PayState.RequestCancelled && (jsx(Button, { onClick: handleTransfer, children: "Retry Payment" })), payState === PayState.RequestFailed && (jsx(Button, { onClick: () => {
58
- assert(payParams != null, "payParams cannot be null in deposit flow");
55
+ assert(payParams != null, "[PAY SOLANA] payParams cannot be null in deposit flow");
59
56
  generatePreviewOrder(payParams);
60
- setRoute(ROUTES.SELECT_METHOD);
57
+ setRoute(ROUTES.SELECT_METHOD, { event: "click-select-another" });
61
58
  }, children: "Select Another Method" }))] })] }));
62
59
  };
63
- styled(motion.div) `
64
- display: flex;
65
- align-items: center;
66
- justify-content: center;
67
- margin: 10px auto 16px;
68
- height: 120px;
69
- `;
70
- styled(motion.div) `
71
- user-select: none;
72
- position: relative;
73
- --spinner-error-opacity: 0;
74
- &:before {
75
- content: "";
76
- position: absolute;
77
- inset: 1px;
78
- opacity: 0;
79
- background: var(--ck-body-color-danger);
80
- ${(props) => props.$circle &&
81
- css `
82
- inset: -5px;
83
- border-radius: 50%;
84
- background: none;
85
- box-shadow: inset 0 0 0 3.5px var(--ck-body-color-danger);
86
- `}
87
- }
88
- `;
89
60
 
90
61
  export { PayWithSolanaToken as default };
91
62
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -31,11 +31,16 @@ const SelectSolanaToken = () => {
31
31
  ],
32
32
  onClick: () => {
33
33
  setSelectedSolanaTokenOption(option);
34
+ const meta = {
35
+ event: "click-solana-token",
36
+ tokenSymbol: option.balance.token.symbol,
37
+ chainId: option.balance.token.chainId,
38
+ };
34
39
  if (isDepositFlow) {
35
- setRoute(ROUTES.SOLANA_SELECT_AMOUNT);
40
+ setRoute(ROUTES.SOLANA_SELECT_AMOUNT, meta);
36
41
  }
37
42
  else {
38
- setRoute(ROUTES.SOLANA_PAY_WITH_TOKEN);
43
+ setRoute(ROUTES.SOLANA_PAY_WITH_TOKEN, meta);
39
44
  }
40
45
  },
41
46
  disabled,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -44,7 +44,7 @@ const WaitingDepositAddress = () => {
44
44
  useEffect(() => {
45
45
  triggerResize();
46
46
  }, [details]);
47
- return (jsx(PageContent, { children: failed ? (jsxs(ModalContent, { style: { marginLeft: 24, marginRight: 24 }, children: [jsxs(ModalH1, { children: [selectedDepositAddressOption?.id, " unavailable"] }), jsxs(ModalBody, { children: ["We're unable to process ", selectedDepositAddressOption?.id, " payments at this time. Please select another payment method."] }), jsx(Button, { onClick: () => setRoute(ROUTES.SELECT_METHOD), children: "Select Another Method" })] })) : (jsxs(ModalContent, { children: [jsx(CustomQRCode, { value: details?.uri, image: jsx("img", { src: selectedDepositAddressOption?.logoURI, width: "100%", height: "100%" }), tooltipMessage: jsxs(Fragment, { children: [jsx(ScanIconWithLogos, { logo: jsx("img", { src: selectedDepositAddressOption?.logoURI }) }), jsxs("span", { children: ["Use a ", selectedDepositAddressOption?.id, " wallet to scan"] })] }) }), details && (jsxs(Fragment, { children: [jsx(OrDivider, {}), jsxs(ModalBody, { children: ["Send exactly ", details.amount, " ", details.suffix, " to", " ", getAddressContraction(details.address), " and return to this page. Confirmation should appear in a few minutes."] }), jsx(CopyToClipboard, { variant: "button", string: details.address, children: "Copy Address" }), jsx(CopyToClipboard, { variant: "left", string: details.amount, children: "Copy Amount" })] }))] })) }));
47
+ return (jsx(PageContent, { children: failed ? (jsxs(ModalContent, { style: { marginLeft: 24, marginRight: 24 }, children: [jsxs(ModalH1, { children: [selectedDepositAddressOption?.id, " unavailable"] }), jsxs(ModalBody, { children: ["We're unable to process ", selectedDepositAddressOption?.id, " payments at this time. Please select another payment method."] }), jsx(Button, { onClick: () => setRoute(ROUTES.SELECT_METHOD, { event: "click-select-another" }), children: "Select Another Method" })] })) : (jsxs(ModalContent, { children: [jsx(CustomQRCode, { value: details?.uri, image: jsx("img", { src: selectedDepositAddressOption?.logoURI, width: "100%", height: "100%" }), tooltipMessage: jsxs(Fragment, { children: [jsx(ScanIconWithLogos, { logo: jsx("img", { src: selectedDepositAddressOption?.logoURI }) }), jsxs("span", { children: ["Use a ", selectedDepositAddressOption?.id, " wallet to scan"] })] }) }), details && (jsxs(Fragment, { children: [jsx(OrDivider, {}), jsxs(ModalBody, { children: ["Send exactly ", details.amount, " ", details.suffix, " to", " ", getAddressContraction(details.address), " and return to this page. Confirmation should appear in a few minutes."] }), jsx(CopyToClipboard, { variant: "button", string: details.address, children: "Copy Address" }), jsx(CopyToClipboard, { variant: "left", string: details.amount, children: "Copy Amount" })] }))] })) }));
48
48
  };
49
49
 
50
50
  export { WaitingDepositAddress as default };
@@ -20,7 +20,7 @@ const WaitingExternal = () => {
20
20
  orderId: daimoPayOrder.id.toString(),
21
21
  });
22
22
  if (found) {
23
- setRoute(ROUTES.CONFIRMATION);
23
+ setRoute(ROUTES.CONFIRMATION, { event: "found-source-payment" });
24
24
  }
25
25
  };
26
26
  const interval = setInterval(checkForSourcePayment, 1000);
@@ -1,10 +1,10 @@
1
- import { writeDaimoPayOrderID, DaimoPayOrderMode, DaimoPayIntentStatus, DaimoPayOrderStatusSource } from '@daimo/common';
1
+ import { writeDaimoPayOrderID } from '@daimo/common';
2
2
  import { usePayContext } from '../components/DaimoPay.js';
3
3
 
4
4
  /** Returns the current payment, or undefined if there is none.
5
5
  *
6
6
  * Status values:
7
- * - `payment_pending` - the user has not paid yet
7
+ * - `payment_unpaid` - the user has not paid yet
8
8
  * - `payment_started` - the user has paid & payment is in progress. This status
9
9
  * typically lasts a few seconds.
10
10
  * - `payment_completed` - the final call or transfer succeeded
@@ -17,20 +17,7 @@ function useDaimoPayStatus() {
17
17
  return undefined;
18
18
  const order = paymentState.daimoPayOrder;
19
19
  const paymentId = writeDaimoPayOrderID(order.id);
20
- if (order.mode === DaimoPayOrderMode.HYDRATED) {
21
- if (order.intentStatus !== DaimoPayIntentStatus.PENDING) {
22
- if (order.intentStatus === DaimoPayIntentStatus.SUCCESSFUL) {
23
- return { paymentId, status: "payment_completed" };
24
- }
25
- else {
26
- return { paymentId, status: "payment_bounced" };
27
- }
28
- }
29
- else if (order.sourceStatus !== DaimoPayOrderStatusSource.WAITING_PAYMENT) {
30
- return { paymentId, status: "payment_started" };
31
- }
32
- }
33
- return { paymentId, status: "payment_pending" };
20
+ return { paymentId, status: order.intentStatus };
34
21
  }
35
22
 
36
23
  export { useDaimoPayStatus };
@@ -1 +1 @@
1
- {"version":3,"file":"useDaimoPayStatus.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"useDaimoPayStatus.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -7,8 +7,9 @@ function usePayWithSolanaToken({ trpc, daimoPayOrder, setDaimoPayOrder, createOr
7
7
  const { connection } = useConnection();
8
8
  const wallet = useWallet();
9
9
  const payWithSolanaToken = async (inputToken) => {
10
- assert(!!wallet.publicKey, "No wallet connected");
11
- assert(!!platform && !!daimoPayOrder);
10
+ assert(!!wallet.publicKey, "[PAY SOLANA] No wallet connected");
11
+ assert(!!daimoPayOrder, "[PAY SOLANA] daimoPayOrder cannot be null");
12
+ assert(!!platform, "[PAY SOLANA] platform cannot be null");
12
13
  const orderId = daimoPayOrder.id;
13
14
  const { hydratedOrder } = await createOrHydrate({
14
15
  order: daimoPayOrder,
@@ -18,7 +19,7 @@ function usePayWithSolanaToken({ trpc, daimoPayOrder, setDaimoPayOrder, createOr
18
19
  try {
19
20
  const serializedTx = await trpc.getSolanaSwapAndBurnTx.query({
20
21
  orderId: orderId.toString(),
21
- userPublicKey: assertNotNull(wallet.publicKey).toString(),
22
+ userPublicKey: assertNotNull(wallet.publicKey, "[PAY SOLANA] wallet.publicKey cannot be null").toString(),
22
23
  inputTokenMint: inputToken,
23
24
  });
24
25
  const tx = VersionedTransaction.deserialize(hexToBytes(serializedTx));
@@ -1 +1 @@
1
- {"version":3,"file":"usePayWithSolanaToken.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"usePayWithSolanaToken.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -7,12 +7,14 @@ function usePayWithToken({ trpc, senderAddr, daimoPayOrder, setDaimoPayOrder, cr
7
7
  const { sendTransactionAsync } = useSendTransaction();
8
8
  /** Commit to a token + amount = initiate payment. */
9
9
  const payWithToken = async (tokenAmount) => {
10
- assert(!!daimoPayOrder && !!platform);
10
+ assert(!!daimoPayOrder, "[PAY TOKEN] daimoPayOrder cannot be null");
11
+ assert(!!platform, "[PAY TOKEN] platform cannot be null");
11
12
  const { hydratedOrder } = await createOrHydrate({
12
13
  order: daimoPayOrder,
13
14
  refundAddress: senderAddr,
14
15
  });
15
- log(`[CHECKOUT] Hydrated order: ${JSON.stringify(hydratedOrder)}, checking out with ${tokenAmount.token.token}`);
16
+ log(`[CHECKOUT] hydrated order: ${JSON.stringify(hydratedOrder)}, checking out with ${tokenAmount.token.token}`);
17
+ setDaimoPayOrder(hydratedOrder);
16
18
  const txHash = await (async () => {
17
19
  try {
18
20
  if (tokenAmount.token.token === zeroAddress) {
@@ -31,23 +33,20 @@ function usePayWithToken({ trpc, senderAddr, daimoPayOrder, setDaimoPayOrder, cr
31
33
  }
32
34
  }
33
35
  catch (e) {
34
- console.error(`[CHECKOUT] Error sending token: ${e}`);
35
- setDaimoPayOrder(hydratedOrder);
36
+ console.error(`[CHECKOUT] error sending token: ${e}`);
36
37
  throw e;
37
38
  }
38
- finally {
39
- setDaimoPayOrder(hydratedOrder);
40
- }
41
39
  })();
42
40
  if (txHash) {
43
41
  await trpc.processSourcePayment.mutate({
44
42
  orderId: daimoPayOrder.id.toString(),
45
43
  sourceInitiateTxHash: txHash,
46
44
  sourceChainId: tokenAmount.token.chainId,
47
- sourceFulfillerAddr: assertNotNull(senderAddr),
45
+ sourceFulfillerAddr: assertNotNull(senderAddr, `[PAY TOKEN] senderAddr cannot be null on order ${daimoPayOrder.id}`),
48
46
  sourceToken: tokenAmount.token.token,
49
47
  sourceAmount: tokenAmount.amount,
50
48
  });
49
+ // TODO: update order immediately, do not wait for polling.
51
50
  }
52
51
  };
53
52
  return { payWithToken };
@@ -1 +1 @@
1
- {"version":3,"file":"usePayWithToken.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"usePayWithToken.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -4,7 +4,6 @@ import { useWallet } from '@solana/wallet-adapter-react';
4
4
  import { useState, useEffect, useCallback } from 'react';
5
5
  import { parseUnits, formatUnits } from 'viem';
6
6
  import { useAccount, useEnsName } from 'wagmi';
7
- import { generatePayId } from '../utils/exports.js';
8
7
  import { detectPlatform } from '../utils/platform.js';
9
8
  import { useDepositAddressOptions } from './useDepositAddressOptions.js';
10
9
  import { useExternalPaymentOptions } from './useExternalPaymentOptions.js';
@@ -67,9 +66,9 @@ function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log,
67
66
  const chainOrderUsdLimits = useOrderUsdLimits({ trpc });
68
67
  /** Create a new order or hydrate an existing one. */
69
68
  const createOrHydrate = async ({ order, refundAddress, externalPaymentOption, }) => {
70
- assert(!!platform, "missing platform");
69
+ assert(!!platform, "[CREATE/HYDRATE] missing platform");
71
70
  if (payParams == null) {
72
- log(`[CHECKOUT] hydrating existing order ${order.id}`);
71
+ log(`[CREATE/HYDRATE] hydrating existing order ${order.id}`);
73
72
  return await trpc.hydrateOrder.query({
74
73
  id: order.id.toString(),
75
74
  chosenFinalTokenAmount: order.destFinalCallTokenAmount.amount,
@@ -78,7 +77,7 @@ function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log,
78
77
  externalPaymentOption,
79
78
  });
80
79
  }
81
- log(`[CHECKOUT] creating+hydrating new order ${order.id}`);
80
+ log(`[CREATE/HYDRATE] creating+hydrating new order ${order.id}`);
82
81
  // Update units, if isDepositFlow then the user may have changed the amount.
83
82
  const toUnits = formatUnits(BigInt(order.destFinalCallTokenAmount.amount), order.destFinalCallTokenAmount.token.decimals);
84
83
  return await trpc.createOrder.mutate({
@@ -88,6 +87,7 @@ function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log,
88
87
  id: order.id.toString(),
89
88
  toUnits,
90
89
  metadata: order.metadata,
90
+ userMetadata: payParams.metadata,
91
91
  isAmountEditable: isDepositFlow,
92
92
  },
93
93
  platform,
@@ -127,28 +127,29 @@ function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log,
127
127
  : DEFAULT_USD_LIMIT;
128
128
  };
129
129
  const payWithExternal = async (option) => {
130
- assert(!!daimoPayOrder && !!platform);
130
+ assert(!!daimoPayOrder, "[PAY EXTERNAL] daimoPayOrder cannot be null");
131
+ assert(!!platform, "[PAY EXTERNAL] platform cannot be null");
131
132
  const { hydratedOrder, externalPaymentOptionData } = await createOrHydrate({
132
133
  order: daimoPayOrder,
133
134
  externalPaymentOption: option,
134
135
  });
135
- assert(!!externalPaymentOptionData, "missing externalPaymentOptionData");
136
- log(`[CHECKOUT] Hydrated order: ${JSON.stringify(hydratedOrder)}, checking out with external payment: ${option}`);
136
+ assert(!!externalPaymentOptionData, "[PAY EXTERNAL] missing externalPaymentOptionData");
137
+ log(`[PAY EXTERNAL] hydrated order: ${JSON.stringify(hydratedOrder)}, checking out with external payment: ${option}`);
137
138
  setPaymentWaitingMessage(externalPaymentOptionData.waitingMessage);
138
139
  setDaimoPayOrder(hydratedOrder);
139
140
  return externalPaymentOptionData.url;
140
141
  };
141
142
  const payWithDepositAddress = async (option) => {
142
- assert(!!daimoPayOrder);
143
+ assert(!!daimoPayOrder, "[PAY DEPOSIT ADDRESS] missing daimoPayOrder");
143
144
  const { hydratedOrder } = await createOrHydrate({
144
145
  order: daimoPayOrder,
145
146
  });
146
147
  setDaimoPayOrder(hydratedOrder);
147
- log(`[CHECKOUT] Hydrated order: ${JSON.stringify(hydratedOrder)}, checking out with deposit address: ${option}`);
148
+ log(`[PAY DEPOSIT ADDRESS] hydrated order: ${JSON.stringify(hydratedOrder)}, checking out with deposit address: ${option}`);
148
149
  const depositAddressOption = await trpc.getDepositAddressOptionData.query({
149
150
  input: option,
150
151
  usdRequired: daimoPayOrder.destFinalCallTokenAmount.usd,
151
- toAddress: assertNotNull(hydratedOrder.intentAddr),
152
+ toAddress: assertNotNull(hydratedOrder.intentAddr, `[PAY DEPOSIT ADDRESS] missing intentAddr on order ${hydratedOrder.id}`),
152
153
  });
153
154
  return depositAddressOption;
154
155
  };
@@ -161,17 +162,22 @@ function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log,
161
162
  });
162
163
  // Don't overwrite the order if a new order was generated.
163
164
  if (daimoPayOrder == null || order.id === daimoPayOrder.id) {
165
+ log(`[CHECKOUT] refreshed order: ${order.id}`);
164
166
  setDaimoPayOrder(order);
165
167
  }
168
+ else {
169
+ log(`[CHECKOUT] IGNORING refreshOrder, wrong ID: ${order.id} vs ${daimoPayOrder.id}`);
170
+ }
166
171
  }, [daimoPayOrder?.id]);
167
172
  /** User picked a different deposit amount. */
168
173
  const setChosenUsd = (usd) => {
169
- log(`[CHECKOUT] Setting chosen USD amount to ${usd}`);
170
- assert(!!daimoPayOrder);
174
+ assert(!!daimoPayOrder, "[SET CHOSEN USD] daimoPayOrder cannot be null");
171
175
  const token = daimoPayOrder.destFinalCallTokenAmount.token;
172
- const tokenAmount = parseUnits((usd / token.usd).toString(), token.decimals);
176
+ const tokenUnits = (usd / token.usd).toString();
177
+ const tokenAmount = parseUnits(tokenUnits, token.decimals);
173
178
  // TODO: remove amount from destFinalCall, it is redundant with
174
179
  // destFinalCallTokenAmount. Here, we only modify one and not the other.
180
+ log(`[CHECKOUT] setting chosen USD amount to $${usd} = ${tokenUnits} ${token.symbol}`);
175
181
  setDaimoPayOrder({
176
182
  ...daimoPayOrder,
177
183
  destFinalCallTokenAmount: {
@@ -191,27 +197,25 @@ function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log,
191
197
  }
192
198
  const { order } = await trpc.getOrder.query({ id });
193
199
  if (!order) {
194
- console.error(`[CHECKOUT] No order found for ${payId}`);
200
+ console.error(`[CHECKOUT] setPayId: no order found for ${payId}`);
195
201
  return;
196
202
  }
197
- log(`[CHECKOUT] fetched order: ${JSON.stringify(order)}`);
203
+ log(`[CHECKOUT] setPayId: fetched order: ${JSON.stringify(order)}`);
198
204
  setDaimoPayOrder(order);
199
205
  }, [daimoPayOrder]);
200
206
  /** Called whenever params change. */
201
207
  const setPayParams = async (payParams) => {
202
- assert(payParams != null);
208
+ assert(payParams != null, "[SET PAY PARAMS] payParams cannot be null");
203
209
  setPayParamsState(payParams);
204
210
  setIsDepositFlow(payParams.toUnits == null);
205
211
  generatePreviewOrder(payParams);
206
212
  };
207
213
  const generatePreviewOrder = async (payParams) => {
208
- const newPayId = generatePayId();
209
- const newId = readDaimoPayOrderID(newPayId).toString();
210
214
  // toUnits is undefined if and only if we're in deposit flow.
211
215
  // Set dummy value for deposit flow, since user can edit the amount.
212
216
  const toUnits = payParams.toUnits == null ? "0" : payParams.toUnits;
213
217
  const orderPreview = await trpc.previewOrder.query({
214
- id: newId,
218
+ appId: payParams.appId,
215
219
  toChain: payParams.toChain,
216
220
  toToken: payParams.toToken,
217
221
  toUnits,
@@ -227,13 +231,16 @@ function usePaymentState({ trpc, daimoPayOrder, setDaimoPayOrder, setOpen, log,
227
231
  preferredTokens: payParams.preferredTokens,
228
232
  },
229
233
  },
234
+ externalId: payParams.externalId,
235
+ userMetadata: payParams.metadata,
230
236
  });
237
+ log(`[CHECKOUT] generated preview: ${JSON.stringify(orderPreview)}`);
231
238
  setDaimoPayOrder(orderPreview);
232
239
  };
233
240
  const onSuccess = ({ txHash, txURL }) => {
234
241
  if (modalOptions?.closeOnSuccess) {
235
242
  log(`[CHECKOUT] transaction succeeded, closing: ${txHash} ${txURL}`);
236
- setTimeout(() => setOpen(false), 1000);
243
+ setTimeout(() => setOpen(false, { event: "wait-success" }), 1000);
237
244
  }
238
245
  };
239
246
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"usePaymentState.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"usePaymentState.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -3,9 +3,8 @@ export { Context as DaimoPayContext, DaimoPayProvider, usePayContext } from './c
3
3
  export { default as getDefaultConfig } from './defaultConfig.js';
4
4
  export { DaimoPayButton } from './components/DaimoPayButton/index.js';
5
5
  export { useDaimoPayStatus } from './hooks/useDaimoPayStatus.js';
6
- export { useModal as useDaimoPayModal } from './hooks/useModal.js';
7
6
  export { default as Avatar } from './components/Common/Avatar/index.js';
8
7
  export { default as ChainIcon } from './components/Common/Chain/index.js';
9
8
  export { wallets } from './wallets/index.js';
10
- export { daimoPayVersion, generatePayId, supportedChainIds } from './utils/exports.js';
9
+ export { daimoPayVersion, supportedChainIds } from './utils/exports.js';
11
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
@@ -1,17 +1,10 @@
1
- import { writeDaimoPayOrderID } from '@daimo/common';
2
1
  import { getDAv2Chains } from '@daimo/contract';
3
- import { bytesToBigInt } from 'viem';
4
2
  import packageJson from '../../package.json.js';
5
3
 
6
4
  // Exported utilities, useful for @daimo/pay users.
7
5
  const daimoPayVersion = packageJson.version;
8
- /** Generates a globally-unique payId. */
9
- function generatePayId() {
10
- const id = bytesToBigInt(crypto.getRandomValues(new Uint8Array(32)));
11
- return writeDaimoPayOrderID(id);
12
- }
13
6
  /** Chain ids supported by Daimo Pay. */
14
7
  const supportedChainIds = new Set([...getDAv2Chains(false), ...getDAv2Chains(true)].map((c) => c.chainId));
15
8
 
16
- export { daimoPayVersion, generatePayId, supportedChainIds };
9
+ export { daimoPayVersion, supportedChainIds };
17
10
  //# sourceMappingURL=exports.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"exports.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"exports.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
@@ -1,13 +1,14 @@
1
1
  import { createTRPCClient, httpBatchLink } from '@trpc/client';
2
2
  import { daimoPayVersion } from './exports.js';
3
3
 
4
- function createTrpcClient(apiUrl) {
4
+ function createTrpcClient(apiUrl, sessionId) {
5
5
  return createTRPCClient({
6
6
  links: [
7
7
  httpBatchLink({
8
8
  url: apiUrl,
9
9
  headers: {
10
10
  "x-pay-version": daimoPayVersion,
11
+ "x-session-id": sessionId,
11
12
  },
12
13
  }),
13
14
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"trpc.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"trpc.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@daimo/pay",
3
3
  "private": false,
4
- "version": "1.2.0",
4
+ "version": "1.3.1",
5
5
  "author": "Daimo",
6
6
  "homepage": "https://pay.daimo.com",
7
7
  "license": "BSD-2-Clause license",
@@ -40,8 +40,8 @@
40
40
  "crypto"
41
41
  ],
42
42
  "dependencies": {
43
- "@daimo/common": "1.1.1",
44
- "@daimo/contract": "1.1.1",
43
+ "@daimo/common": "1.3.1",
44
+ "@daimo/contract": "1.3.1",
45
45
  "@solana/wallet-adapter-base": "^0.9.23",
46
46
  "@solana/wallet-adapter-react": "^0.15.35",
47
47
  "@solana/web3.js": "^1.95.4",
@@ -79,4 +79,4 @@
79
79
  "rollup-plugin-visualizer": "^5.5.4",
80
80
  "typescript-plugin-styled-components": "^3.0.0"
81
81
  }
82
- }
82
+ }
@@ -1,35 +0,0 @@
1
- import { usePayContext, ROUTES } from '../components/DaimoPay.js';
2
- import { useConnectCallback } from './useConnectCallback.js';
3
-
4
- /** Opens and closes the payment modal. */
5
- const useModal = ({ onConnect, onDisconnect } = {}) => {
6
- const context = usePayContext();
7
- useConnectCallback({
8
- onConnect,
9
- onDisconnect,
10
- });
11
- const close = () => {
12
- context.setOpen(false);
13
- };
14
- const open = () => {
15
- context.setOpen(true);
16
- };
17
- const gotoAndOpen = (route) => {
18
- context.setRoute(route);
19
- open();
20
- };
21
- return {
22
- open: context.open,
23
- setOpen: (show) => {
24
- if (show) {
25
- gotoAndOpen(ROUTES.SELECT_METHOD);
26
- }
27
- else {
28
- close();
29
- }
30
- },
31
- };
32
- };
33
-
34
- export { useModal };
35
- //# sourceMappingURL=useModal.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useModal.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}