@daimo/pay 1.6.5 → 1.7.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.
package/build/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { ExternalPaymentOptions, assert, assertNotNull, debugJson, supportedChains, ethereum, readDaimoPayOrderID, getChainName, arbitrum as arbitrum$1, base as base$2, blast as blast$1, bsc as bsc$1, linea as linea$1, mantle as mantle$1, optimism as optimism$1, polygon as polygon$1, worldchain as worldchain$1, writeDaimoPayOrderID, DaimoPayOrderMode, DaimoPayOrderStatusDest, getChainExplorerTxUrl, getAddressContraction, DaimoPayIntentStatus, retryBackoff, DaimoPayOrderStatusSource, getDaimoPayOrderView } from '@daimo/pay-common';
2
+ import { ExternalPaymentOptions, assert, assertNotNull, debugJson, supportedChains, ethereum, readDaimoPayOrderID, getChainName, arbitrum as arbitrum$1, base as base$2, blast as blast$1, bsc as bsc$1, linea as linea$1, mantle as mantle$1, optimism as optimism$1, polygon as polygon$1, worldchain as worldchain$1, getAddressContraction, writeDaimoPayOrderID, DaimoPayOrderMode, DaimoPayOrderStatusDest, getChainExplorerTxUrl, DaimoPayIntentStatus, retryBackoff, DaimoPayOrderStatusSource, getDaimoPayOrderView } from '@daimo/pay-common';
3
3
  import { Buffer } from 'buffer';
4
4
  import React, { useState, useEffect, createContext, useCallback, useRef, useLayoutEffect, useMemo, createElement } from 'react';
5
5
  import styled$1, { css, keyframes, ThemeProvider } from 'styled-components';
@@ -22,7 +22,7 @@ import { WalletSignTransactionError, WalletSendTransactionError } from '@solana/
22
22
  import { normalize } from 'viem/ens';
23
23
 
24
24
  var name = "@daimo/pay";
25
- var version = "1.6.5";
25
+ var version = "1.7.1";
26
26
  var author = "Daimo";
27
27
  var homepage = "https://pay.daimo.com";
28
28
  var license = "BSD-2-Clause license";
@@ -61,7 +61,7 @@ var keywords = [
61
61
  "crypto"
62
62
  ];
63
63
  var dependencies = {
64
- "@daimo/pay-common": "1.6.5",
64
+ "@daimo/pay-common": "1.7.1",
65
65
  "@rollup/plugin-typescript": "^12.1.2",
66
66
  "@solana/wallet-adapter-base": "^0.9.23",
67
67
  "@solana/wallet-adapter-react": "^0.15.35",
@@ -273,18 +273,6 @@ const useConnectCallback = ({ onConnect, onDisconnect, }) => {
273
273
  });
274
274
  };
275
275
 
276
- const isWalletInstalled = (name) => {
277
- if (typeof window === "undefined")
278
- return false;
279
- const { ethereum } = window;
280
- return !!(ethereum?.[`is${name}`] ||
281
- (ethereum?.providers &&
282
- ethereum?.providers.find((provider) => provider?.[`is${name}`])));
283
- };
284
- const isFamily = () => isWalletInstalled("Family");
285
- const isRainbow = () => isWalletInstalled("Rainbow");
286
- const isZerion = () => isWalletInstalled("Zerion");
287
-
288
276
  const Mock = ({ ...props }) => (jsxs("svg", { ...props, "aria-hidden": "true", width: "44", height: "44", viewBox: "0 0 44 44", fill: "none", xmlns: "http://www.w3.org/2000/svg", style: {
289
277
  background: "linear-gradient(180deg, #8995A9 0%, #424D5F 99.48%)",
290
278
  }, children: [jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M20.5611 8.12948C21.0082 7.90729 21.5007 7.79167 22 7.79167C22.4993 7.79167 22.9919 7.90729 23.439 8.12948L23.4408 8.1304L33.0387 12.9293C33.577 13.197 34.031 13.61 34.3478 14.121C34.6649 14.6323 34.833 15.2218 34.8333 15.8234V27.2595C34.833 27.8611 34.6649 28.4511 34.3478 28.9624C34.031 29.4733 33.578 29.8858 33.0398 30.1535L23.4411 34.9528C22.9919 35.1775 22.4963 35.2947 21.994 35.2947C21.4918 35.2947 20.9964 35.1777 20.5472 34.9529L10.9475 30.1531L10.9452 30.1519C10.4071 29.8808 9.95535 29.4646 9.6411 28.9504C9.32739 28.437 9.16312 27.8464 9.16673 27.2448L9.16675 27.2417L10.0004 27.2475H9.16673V27.2448V15.8239C9.16705 15.2223 9.33518 14.6322 9.65222 14.121C9.96906 13.61 10.4221 13.1976 10.9604 12.9298L20.5592 8.1304L20.5611 8.12948ZM21.3031 9.62267L11.8706 14.3389L22 19.4036L32.1294 14.3389L22.697 9.62267C22.4806 9.51531 22.2416 9.45905 22 9.45905C21.7585 9.45905 21.5194 9.51534 21.3031 9.62267ZM10.8341 15.8241C10.8341 15.7785 10.8362 15.733 10.8401 15.6878L21.1663 20.8509V33.3983L11.6955 28.6629C11.4352 28.5315 11.2159 28.3297 11.0638 28.0809C10.9116 27.8318 10.8321 27.5452 10.8341 27.2533L10.8341 27.2475V15.8241ZM22.8337 33.3923L32.2967 28.6608C32.5576 28.5312 32.7772 28.3313 32.9308 28.0836C33.0844 27.836 33.1658 27.5504 33.166 27.259V15.8243C33.1659 15.7786 33.1639 15.7331 33.1599 15.6878L22.8337 20.8509V33.3923Z", fill: "url(#paint0_linear_3546_7073)" }), jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M10.8341 15.8241C10.8341 15.7785 10.8362 15.733 10.8401 15.6878L21.1663 20.8509V33.3983L11.6955 28.6629C11.4352 28.5315 11.2159 28.3297 11.0638 28.0809C10.9116 27.8318 10.8321 27.5452 10.8341 27.2533L10.8341 27.2475V15.8241Z", fill: "url(#paint1_linear_3546_7073)", fillOpacity: "0.3" }), jsxs("defs", { children: [jsxs("linearGradient", { id: "paint0_linear_3546_7073", x1: "22", y1: "7.79167", x2: "22", y2: "35.2947", gradientUnits: "userSpaceOnUse", children: [jsx("stop", { stopColor: "white" }), jsx("stop", { offset: "1", stopColor: "white", stopOpacity: "0.7" })] }), jsxs("linearGradient", { id: "paint1_linear_3546_7073", x1: "22", y1: "7.79167", x2: "22", y2: "35.2947", gradientUnits: "userSpaceOnUse", children: [jsx("stop", { stopColor: "white" }), jsx("stop", { offset: "1", stopColor: "white", stopOpacity: "0.7" })] })] })] }));
@@ -389,7 +377,7 @@ const OtherWallets = ({ ...props }) => {
389
377
  overflow: "hidden",
390
378
  borderRadius: "27.5%",
391
379
  };
392
- return (jsxs("div", { style: column, ...props, children: [jsxs("div", { style: row, children: [jsx("div", { style: cell, children: jsx(WalletConnect, { background: true }) }), jsx("div", { style: cell, children: !isZerion() ? jsx(Zerion, {}) : jsx(Phantom, {}) })] }), jsxs("div", { style: row, children: [jsx("div", { style: cell, children: !isFamily() ? jsx(Family, {}) : jsx(ImToken, {}) }), jsx("div", { style: cell, children: !isRainbow() ? jsx(Rainbow, {}) : jsx(Trust, {}) })] })] }));
380
+ return (jsxs("div", { style: column, ...props, children: [jsxs("div", { style: row, children: [jsx("div", { style: cell, children: jsx(Rainbow, {}) }), jsx("div", { style: cell, children: jsx(WalletConnect, { background: true }) })] }), jsxs("div", { style: row, children: [jsx("div", { style: cell, children: jsx(Family, {}) }), jsx("div", { style: cell, children: jsx(Ledger, {}) })] })] }));
393
381
  };
394
382
  const Fordefi = ({ ...props }) => (jsxs("svg", { ...props, width: "88", height: "88", viewBox: "0 0 96 96", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [jsxs("g", { clipPath: "url(#clip0_14298_75627)", children: [jsx("path", { d: "M43.5075 62.5508H6V73.5954C6 79.2046 10.5379 83.7515 16.1357 83.7515H32.9997L43.5075 62.5508Z", fill: "#7994FF" }), jsx("path", { d: "M6.00098 39.1016H76.2075L68.0567 55.4841H6.00098V39.1016Z", fill: "#486DFF" }), jsx("path", { d: "M30.6398 12H6.09766V32.0282H89.8447V12H65.3025V26.9577H60.2423V12H35.7001V26.9577H30.6398V12Z", fill: "#5CD1FA" })] }), jsx("defs", { children: jsx("clipPath", { id: "clip0_14298_75627", children: jsx("rect", { width: "84", height: "72", fill: "white", transform: "translate(6 12)" }) }) })] }));
395
383
  const SquircleIcon = ({ icon, alt, }) => {
@@ -807,10 +795,19 @@ function useExtractWcWallet({ log, connector, }) {
807
795
  localStorage.removeItem("WALLETCONNECT_DEEPLINK_CHOICE");
808
796
  }
809
797
  else {
810
- connector
811
- .getProvider()
812
- .then((p) => setWcWallet(extractWcWalletFromProvider(p, log)))
813
- .catch((e) => console.error(`[WCWALLET] err getting provider`, e));
798
+ // Check if getProvider exists and is a function before calling
799
+ if (typeof connector.getProvider === "function") {
800
+ connector
801
+ .getProvider()
802
+ .then((p) => setWcWallet(extractWcWalletFromProvider(p, log)))
803
+ .catch((e) => console.error(`[WCWALLET] err getting provider`, e));
804
+ }
805
+ else {
806
+ // Log a warning if getProvider is not available
807
+ console.warn(`[WCWALLET] connector does not have getProvider method`, connector);
808
+ // Potentially reset wcWallet state if the connector is invalid/unexpected
809
+ setWcWallet(undefined);
810
+ }
814
811
  }
815
812
  }, [connector]);
816
813
  return wcWallet;
@@ -5190,7 +5187,7 @@ const Modal = ({ open, pages, pageId, positionInside, inline, demo, onClose, onB
5190
5187
  CONNECTORNAME: walletInfo?.name,
5191
5188
  });
5192
5189
  const [state, setOpen] = useTransition({
5193
- timeout: mobile ? 160 : 160, // different animations, 10ms extra to avoid final-frame drops
5190
+ timeout: 160,
5194
5191
  preEnter: true,
5195
5192
  mountOnEnter: true,
5196
5193
  unmountOnExit: true,
@@ -6591,11 +6588,12 @@ const MoreIndicator = styled.div `
6591
6588
  `;
6592
6589
  const ScrollAreaContainer = styled.div `
6593
6590
  --bg: ${({ $backgroundColor }) => $backgroundColor || "var(--ck-body-background)"};
6594
- --fade-height: 1px;
6591
+ --fade-height-top: 1px;
6592
+ --fade-height-bottom: ${(props) => props.$hideBottomLine && props.$totalItems > 2 ? "32px" : "1px"};
6595
6593
  position: relative;
6596
6594
  z-index: 1;
6597
6595
 
6598
- ${({ $mobile, $height, $mobileDirection }) => $mobile && $mobileDirection === "horizontal"
6596
+ ${({ $mobile, $height, $mobileDirection, $hideBottomLine }) => $mobile && $mobileDirection === "horizontal"
6599
6597
  ? css `
6600
6598
  overflow-x: scroll;
6601
6599
  margin: 0 -24px;
@@ -6610,7 +6608,7 @@ const ScrollAreaContainer = styled.div `
6610
6608
  position: sticky;
6611
6609
  top: 0;
6612
6610
  bottom: 0;
6613
- width: var(--fade-height);
6611
+ width: var(--fade-height-bottom);
6614
6612
  background: var(
6615
6613
  --ck-body-divider-secondary,
6616
6614
  var(--ck-body-divider)
@@ -6641,7 +6639,7 @@ const ScrollAreaContainer = styled.div `
6641
6639
  max-height: ${$height ? `${$height}px` : "310px"};
6642
6640
  overflow-y: scroll;
6643
6641
  padding: 0 10px;
6644
- margin: calc(var(--fade-height) * -1) -16px 0 -10px;
6642
+ margin: calc(var(--fade-height-top) * -1) -16px 0 -10px;
6645
6643
 
6646
6644
  &:before,
6647
6645
  &:after {
@@ -6652,19 +6650,23 @@ const ScrollAreaContainer = styled.div `
6652
6650
  position: sticky;
6653
6651
  left: 0;
6654
6652
  right: 0;
6655
- height: var(--fade-height);
6653
+ }
6654
+ &:before {
6655
+ top: 0;
6656
+ height: var(--fade-height-top);
6656
6657
  background: var(
6657
6658
  --ck-body-divider-secondary,
6658
6659
  var(--ck-body-divider)
6659
6660
  );
6660
6661
  box-shadow: var(--ck-body-divider-box-shadow);
6661
- transition: opacity 300ms ease;
6662
- }
6663
- &:before {
6664
- top: 0;
6665
6662
  }
6666
6663
  &:after {
6667
6664
  bottom: 0;
6665
+ height: var(--fade-height-bottom);
6666
+ background: ${$hideBottomLine
6667
+ ? "linear-gradient(to bottom, transparent, var(--bg))"
6668
+ : "var(--ck-body-divider-secondary, var(--ck-body-divider))"};
6669
+ box-shadow: none;
6668
6670
  }
6669
6671
 
6670
6672
  &.scroll-start {
@@ -6700,7 +6702,7 @@ const ScrollAreaContainer = styled.div `
6700
6702
  `;
6701
6703
 
6702
6704
  const ArrowDown = () => (jsx("svg", { width: "11", height: "12", viewBox: "0 0 11 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M5.49438 1L5.49438 11M5.49438 11L9.5 7M5.49438 11L1.5 7", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }) }));
6703
- const ScrollArea = ({ children, height, backgroundColor, mobileDirection, }) => {
6705
+ const ScrollArea = ({ children, height, backgroundColor, mobileDirection, hideBottomLine = false, totalItems, }) => {
6704
6706
  const { log } = usePayContext();
6705
6707
  const ref = useRef(null);
6706
6708
  const moreRef = useRef(null);
@@ -6743,7 +6745,7 @@ const ScrollArea = ({ children, height, backgroundColor, mobileDirection, }) =>
6743
6745
  el.removeEventListener("scroll", handleScroll);
6744
6746
  };
6745
6747
  }, [ref.current]);
6746
- return (jsxs(ScrollContainer, { children: [jsx(ScrollAreaContainer, { ref: ref, "$mobile": isMobile, "$height": height, "$backgroundColor": backgroundColor, "$mobileDirection": mobileDirection, children: children }), jsx(MoreIndicator, { ref: moreRef, className: "hide", onClick: () => {
6748
+ return (jsxs(ScrollContainer, { children: [jsx(ScrollAreaContainer, { ref: ref, "$mobile": isMobile, "$height": height, "$backgroundColor": backgroundColor, "$mobileDirection": mobileDirection, "$hideBottomLine": hideBottomLine, "$totalItems": totalItems, children: children }), jsx(MoreIndicator, { ref: moreRef, className: "hide", onClick: () => {
6747
6749
  if (ref.current) {
6748
6750
  ref.current.scrollTo({
6749
6751
  top: ref.current.scrollHeight,
@@ -7430,8 +7432,13 @@ function tokenAmountToRoundedUsd(amount, token, round = "nearest") {
7430
7432
  }
7431
7433
 
7432
7434
  /** Shows payment amount. */
7433
- const OrderHeader = ({ minified = false }) => {
7434
- const { paymentState, route } = usePayContext();
7435
+ const OrderHeader = ({ minified = false, showEth = false, showSolana = false, }) => {
7436
+ const { paymentState, route, wcWallet } = usePayContext();
7437
+ const { isConnected: isEthConnected, address, connector } = useAccount();
7438
+ const { connected: isSolanaConnected, publicKey, wallet: solanaWallet, } = useWallet$1();
7439
+ const { senderEnsName } = paymentState;
7440
+ const ethWalletDisplayName = senderEnsName ?? (address ? getAddressContraction(address) : "wallet");
7441
+ const solWalletDisplayName = getAddressContraction(publicKey?.toBase58() ?? "");
7435
7442
  const orderUsd = paymentState.daimoPayOrder?.destFinalCallTokenAmount.usd;
7436
7443
  const titleAmountContent = (() => {
7437
7444
  if (paymentState.isDepositFlow) {
@@ -7444,9 +7451,16 @@ const OrderHeader = ({ minified = false }) => {
7444
7451
  return orderUsd != null ? (jsx("span", { children: formatUsd(orderUsd, "nearest") })) : null;
7445
7452
  }
7446
7453
  })();
7454
+ const renderIcon = (icon, name, size = 32) => {
7455
+ if (!icon)
7456
+ return jsx(MetaMask, {});
7457
+ return (jsx(LogoContainer$4, { "$size": size, "$zIndex": 1, style: { borderRadius: "22.5%" }, children: typeof icon === "string" ? (jsx("img", { src: icon, alt: name || "wallet", style: { maxWidth: "100%", maxHeight: "100%" } })) : (icon) }));
7458
+ };
7459
+ let walletIcon = renderIcon(connector?.icon || wcWallet?.icon, wcWallet?.name);
7460
+ let solanaIcon = renderIcon(solanaWallet?.adapter.icon || jsx(Solana, {}), solanaWallet?.adapter.name);
7447
7461
  if (minified) {
7448
7462
  if (titleAmountContent != null) {
7449
- return (jsxs(MinifiedContainer, { children: [jsx(MinifiedTitleAmount, { children: titleAmountContent }), jsx(CoinLogos, { "$size": 32 })] }));
7463
+ return (jsxs(MinifiedContainer, { children: [jsx(MinifiedTitleAmount, { children: titleAmountContent }), showEth && isEthConnected && (jsx(Fragment, { children: jsxs(SubtitleContainer, { children: [jsx(Subtitle, { children: ethWalletDisplayName }), walletIcon] }) })), showSolana && isSolanaConnected && (jsx(Fragment, { children: jsxs(SubtitleContainer, { children: [jsx(Subtitle, { children: solWalletDisplayName }), solanaIcon] }) })), !showEth && !showSolana && (jsx(Fragment, { children: jsx(CoinLogos, { "$size": 32 }) }))] }));
7450
7464
  }
7451
7465
  else {
7452
7466
  return (jsxs(MinifiedContainer, { children: [jsx(CoinLogos, {}), jsx(Subtitle, { children: "1000+ tokens accepted" })] }));
@@ -7545,6 +7559,12 @@ const Logos = styled(motion.div) `
7545
7559
  align-items: center;
7546
7560
  justify-content: center;
7547
7561
  `;
7562
+ const SubtitleContainer = styled.div `
7563
+ display: flex;
7564
+ align-items: center;
7565
+ justify-content: flex-end;
7566
+ gap: 8px;
7567
+ `;
7548
7568
 
7549
7569
  const Wallets = () => {
7550
7570
  const context = usePayContext();
@@ -10316,7 +10336,7 @@ const OptionIcon = styled(motion.div) `
10316
10336
  border-radius: 0;
10317
10337
  }
10318
10338
  `;
10319
- const OptionsContainer = styled.div `
10339
+ const OptionsContainer$1 = styled.div `
10320
10340
  transition: opacity 300ms ease;
10321
10341
  display: flex;
10322
10342
  flex-direction: column;
@@ -10329,7 +10349,7 @@ const OptionsContainer = styled.div `
10329
10349
  `}
10330
10350
  `;
10331
10351
 
10332
- const OptionsList = ({ options, isLoading, requiredSkeletons, }) => {
10352
+ const OptionsList = ({ options, isLoading, requiredSkeletons, scrollHeight = 300, orDivider = false, }) => {
10333
10353
  const { triggerResize, log } = usePayContext();
10334
10354
  const optionsLength = options.length;
10335
10355
  useEffect(() => {
@@ -10342,10 +10362,10 @@ const OptionsList = ({ options, isLoading, requiredSkeletons, }) => {
10342
10362
  const skeletonCount = requiredSkeletons
10343
10363
  ? Math.max(requiredSkeletons - optionsLength, 0)
10344
10364
  : 0;
10345
- return (jsxs(OptionsContainer, { "$totalResults": options.length, children: [options.map((option) => (jsx(OptionItem, { option: option }, option.id))), isLoading &&
10365
+ return (jsxs(OptionsContainer$1, { "$totalResults": options.length, children: [options.map((option) => (jsx(OptionItem, { option: option }, option.id))), isLoading &&
10346
10366
  Array.from({ length: skeletonCount }).map((_, index) => (jsx(SkeletonOptionItem, {}, index)))] }));
10347
10367
  }
10348
- return (jsx(ScrollArea, { mobileDirection: "vertical", height: 300, children: jsx(OptionsContainer, { "$totalResults": options.length, children: options.map((option) => (jsx(OptionItem, { option: option }, option.id))) }) }));
10368
+ return (jsxs(Fragment, { children: [jsx(ScrollArea, { mobileDirection: "vertical", height: scrollHeight, hideBottomLine: orDivider, totalItems: options.length, children: jsx(OptionsContainer$1, { "$totalResults": options.length, children: options.map((option) => (jsx(OptionItem, { option: option }, option.id))) }) }), orDivider && jsx(OrDivider, {})] }));
10349
10369
  };
10350
10370
  const SkeletonOptionItem = () => {
10351
10371
  return (jsxs(OptionButton, { type: "button", children: [jsx(SkeletonIcon, {}), jsx(SkeletonLabel, {})] }));
@@ -10424,6 +10444,84 @@ const IconStackItem = styled(motion.div) `
10424
10444
  border-radius: 22.5%;
10425
10445
  `;
10426
10446
 
10447
+ const OptionsContainer = styled$1.div `
10448
+ width: 100%;
10449
+ margin-top: 1rem;
10450
+ `;
10451
+ function SelectAnotherMethodButton() {
10452
+ const { paymentState, setRoute } = usePayContext();
10453
+ const { externalPaymentOptions, daimoPayOrder } = paymentState;
10454
+ const { connector } = useAccount();
10455
+ const { disconnectAsync } = useDisconnect();
10456
+ const paymentOptions = daimoPayOrder?.metadata.payer?.paymentOptions;
10457
+ const allPaymentOptions = [
10458
+ ...externalPaymentOptions.options.map((option) => option.id),
10459
+ ...(paymentOptions ?? []),
10460
+ ].flat();
10461
+ const includeSolana = paymentOptions == null ||
10462
+ paymentOptions.includes(ExternalPaymentOptions.Solana);
10463
+ // Deposit address options, e.g. Bitcoin, Tron, Zcash, etc.
10464
+ // Include by default if paymentOptions not provided
10465
+ const includeDepositAddressOption = paymentOptions == null ||
10466
+ paymentOptions.includes(ExternalPaymentOptions.ExternalChains);
10467
+ const selectMethodOption = {
10468
+ id: "select-method",
10469
+ title: `Pay with another method`,
10470
+ icons: getBestPaymentMethodIcons(),
10471
+ onClick: () => {
10472
+ setRoute(ROUTES.SELECT_METHOD);
10473
+ },
10474
+ };
10475
+ const selectWalletOption = {
10476
+ id: "select-wallet",
10477
+ title: "Pay with another wallet",
10478
+ icons: getBestUnconnectedWalletIcons(connector),
10479
+ onClick: async () => {
10480
+ await disconnectAsync();
10481
+ setRoute(ROUTES.CONNECTORS);
10482
+ },
10483
+ };
10484
+ function getBestUnconnectedWalletIcons(connector) {
10485
+ const icons = [];
10486
+ const strippedId = connector?.id.toLowerCase(); // some connector ids can have weird casing and or suffixes and prefixes
10487
+ const [isMetaMask, isRainbow, isCoinbase] = [
10488
+ strippedId?.includes("metamask"),
10489
+ strippedId?.includes("rainbow"),
10490
+ strippedId?.includes("coinbase"),
10491
+ ];
10492
+ if (!isRainbow)
10493
+ icons.push(jsx(Rainbow, {}));
10494
+ if (!isMetaMask)
10495
+ icons.push(jsx(MetaMask, {}));
10496
+ if (!isCoinbase)
10497
+ icons.push(jsx(Coinbase, {}));
10498
+ if (icons.length < 3)
10499
+ icons.push(jsx(Rabby, {}));
10500
+ return icons;
10501
+ }
10502
+ function getBestPaymentMethodIcons() {
10503
+ let icons = externalPaymentOptions.options
10504
+ .filter((option) => option.id !== ExternalPaymentOptions.Daimo)
10505
+ .map((option) => (jsx("div", { style: { borderRadius: "22.5%", overflow: "hidden" }, children: jsx("img", { src: option.logoURI, alt: "" }) }, option.id)));
10506
+ if (icons.length < 3) {
10507
+ const additionalIcons = [];
10508
+ if (includeSolana)
10509
+ additionalIcons.push(jsx(Solana, {}));
10510
+ if (includeDepositAddressOption && additionalIcons.length < 3)
10511
+ additionalIcons.push(jsx(Bitcoin, {}));
10512
+ if (includeDepositAddressOption && additionalIcons.length < 3)
10513
+ additionalIcons.push(jsx(Tron, {}));
10514
+ if (additionalIcons.length < 3)
10515
+ additionalIcons.push(...getBestUnconnectedWalletIcons(connector));
10516
+ icons = [...icons, ...additionalIcons.slice(0, 3 - icons.length)];
10517
+ }
10518
+ return icons;
10519
+ }
10520
+ return (jsx(OptionsContainer, { children: jsx(OptionsList, { options: allPaymentOptions.length > 0
10521
+ ? [selectMethodOption]
10522
+ : [selectWalletOption] }) }));
10523
+ }
10524
+
10427
10525
  const SelectDepositAddressChain = () => {
10428
10526
  const { setRoute, paymentState } = usePayContext();
10429
10527
  const { isDepositFlow, setSelectedDepositAddressOption, depositAddressOptions, } = paymentState;
@@ -10434,7 +10532,7 @@ const SelectDepositAddressChain = () => {
10434
10532
  justifyContent: "center",
10435
10533
  paddingTop: 16,
10436
10534
  paddingBottom: 16,
10437
- }, children: [jsx(ModalH1, { children: "Chains unavailable." }), jsx(Button, { onClick: () => setRoute(ROUTES.SELECT_METHOD), children: "Select Another Method" })] })), jsx(OptionsList, { requiredSkeletons: 4, isLoading: depositAddressOptions.loading, options: depositAddressOptions.options?.map((option) => {
10535
+ }, children: [jsx(ModalH1, { children: "Chains unavailable." }), jsx(SelectAnotherMethodButton, {})] })), jsx(OptionsList, { requiredSkeletons: 4, isLoading: depositAddressOptions.loading, options: depositAddressOptions.options?.map((option) => {
10438
10536
  return {
10439
10537
  id: option.id,
10440
10538
  title: option.id,
@@ -10536,15 +10634,13 @@ function SelectMethod() {
10536
10634
  const ethWalletDisplayName = senderEnsName ?? (address ? getAddressContraction(address) : "wallet");
10537
10635
  let walletIcon;
10538
10636
  if (connector?.icon) {
10539
- log("[SELECT_METHOD] connector?.icon", connector?.icon);
10540
10637
  walletIcon = (jsx("div", { style: { borderRadius: "22.5%", overflow: "hidden" }, children: jsx("img", { src: connector.icon, alt: connector.name }) }));
10541
10638
  }
10542
10639
  else if (wcWallet?.icon) {
10543
- log("[SELECT_METHOD] wcWallet.icon", wcWallet.icon);
10544
10640
  walletIcon = (jsx("div", { style: { borderRadius: "22.5%", overflow: "hidden" }, children: typeof wcWallet.icon === "string" ? (jsx("img", { src: wcWallet.icon, alt: wcWallet.name })) : (wcWallet.icon) }));
10545
10641
  }
10546
10642
  else {
10547
- log("[SELECT_METHOD] else");
10643
+ // TODO: remove this once we have a default icon for wagmi wallets
10548
10644
  walletIcon = jsx(MetaMask, {});
10549
10645
  }
10550
10646
  const connectedEthWalletOption = {
@@ -10564,7 +10660,7 @@ function SelectMethod() {
10564
10660
  };
10565
10661
  connectedOptions.push(connectedEthWalletOption);
10566
10662
  }
10567
- if (isSolanaConnected) {
10663
+ if (isSolanaConnected && includeSolana) {
10568
10664
  const solWalletDisplayName = getAddressContraction(publicKey?.toBase58() ?? "");
10569
10665
  const connectedSolWalletOption = {
10570
10666
  id: "connectedSolanaWallet",
@@ -10652,10 +10748,10 @@ function getBestUnconnectedWalletIcons(connector) {
10652
10748
  strippedId?.includes("rainbow"),
10653
10749
  strippedId?.includes("coinbase"),
10654
10750
  ];
10655
- if (!isMetaMask)
10656
- icons.push(jsx(MetaMask, {}));
10657
10751
  if (!isRainbow)
10658
10752
  icons.push(jsx(Rainbow, {}));
10753
+ if (!isMetaMask)
10754
+ icons.push(jsx(MetaMask, {}));
10659
10755
  if (!isCoinbase)
10660
10756
  icons.push(jsx(Coinbase, {}));
10661
10757
  if (icons.length < 3)
@@ -10663,7 +10759,7 @@ function getBestUnconnectedWalletIcons(connector) {
10663
10759
  return icons;
10664
10760
  }
10665
10761
  function getSolanaOption(isOnIOS) {
10666
- const { wallets } = useWallet$1();
10762
+ const { wallets, disconnect: disconnectSolana } = useWallet$1();
10667
10763
  const { setRoute } = usePayContext();
10668
10764
  if (wallets.length === 0 && !isOnIOS)
10669
10765
  return null;
@@ -10671,7 +10767,8 @@ function getSolanaOption(isOnIOS) {
10671
10767
  id: "solana",
10672
10768
  title: "Pay on Solana",
10673
10769
  icons: [jsx(Solana, {})],
10674
- onClick: () => {
10770
+ onClick: async () => {
10771
+ await disconnectSolana();
10675
10772
  setRoute(ROUTES.SOLANA_CONNECT);
10676
10773
  },
10677
10774
  };
@@ -10761,13 +10858,13 @@ function SelectToken() {
10761
10858
  disabled,
10762
10859
  };
10763
10860
  }) ?? [];
10764
- return (jsxs(PageContent, { children: [jsx(OrderHeader, { minified: true }), !walletPaymentOptions.isLoading && optionsList.length === 0 && (jsxs(ModalContent, { style: {
10861
+ return (jsxs(PageContent, { children: [jsx(OrderHeader, { minified: true, showEth: true }), !walletPaymentOptions.isLoading && optionsList.length === 0 && (jsxs(ModalContent, { style: {
10765
10862
  display: "flex",
10766
10863
  alignItems: "center",
10767
10864
  justifyContent: "center",
10768
10865
  paddingTop: 16,
10769
10866
  paddingBottom: 16,
10770
- }, children: [jsx(ModalH1, { children: "Insufficient balance." }), jsx(Button, { onClick: () => setRoute(ROUTES.SELECT_METHOD), children: "Select Another Method" })] })), jsx(OptionsList, { requiredSkeletons: 4, isLoading: walletPaymentOptions.isLoading, options: optionsList })] }));
10867
+ }, children: [jsx(ModalH1, { children: "Insufficient balance." }), jsx(SelectAnotherMethodButton, {})] })), jsx(OptionsList, { requiredSkeletons: 4, isLoading: walletPaymentOptions.isLoading, options: optionsList, scrollHeight: isMobile ? 225 : 300, orDivider: optionsList.length != 0 }), optionsList.length != 0 && jsx(SelectAnotherMethodButton, {})] }));
10771
10868
  }
10772
10869
  function getDaimoTokenKey(token) {
10773
10870
  return `${token.chainId}-${token.token}`;
@@ -10874,7 +10971,7 @@ const ConnectSolana = () => {
10874
10971
  paddingTop: 16,
10875
10972
  paddingBottom: 16,
10876
10973
  gap: 16,
10877
- }, children: [jsx(ModalH1, { children: "No Solana wallets detected." }), jsx(Button, { onClick: () => setRoute(ROUTES.SELECT_METHOD, { event: "click-select-another" }), children: "Select Another Method" })] })), isMobile() &&
10974
+ }, children: [jsx(ModalH1, { children: "No Solana wallets detected." }), jsx(SelectAnotherMethodButton, {})] })), isMobile() &&
10878
10975
  (solanaWallets.wallets.length === 0 ||
10879
10976
  (solanaWallets.wallets.length > 0 &&
10880
10977
  solanaWallets.wallets[0].adapter.name ===
@@ -10929,11 +11026,7 @@ const PayWithSolanaToken = () => {
10929
11026
  useEffect(() => {
10930
11027
  triggerResize();
10931
11028
  }, [payState]);
10932
- 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: () => {
10933
- assert(payParams != null, "[PAY SOLANA] payParams cannot be null in deposit flow");
10934
- generatePreviewOrder(payParams);
10935
- setRoute(ROUTES.SELECT_METHOD, { event: "click-select-another" });
10936
- }, children: "Select Another Method" }))] })] }));
11029
+ 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(SelectAnotherMethodButton, {})] })] }));
10937
11030
  };
10938
11031
 
10939
11032
  const SelectSolanaAmount = () => {
@@ -10984,13 +11077,13 @@ const SelectSolanaToken = () => {
10984
11077
  disabled,
10985
11078
  };
10986
11079
  }) ?? [];
10987
- return (jsxs(PageContent, { children: [jsx(OrderHeader, { minified: true }), !solanaPaymentOptions.isLoading && optionsList.length === 0 && (jsxs(ModalContent, { style: {
11080
+ return (jsxs(PageContent, { children: [jsx(OrderHeader, { minified: true, showSolana: true }), !solanaPaymentOptions.isLoading && optionsList.length === 0 && (jsxs(ModalContent, { style: {
10988
11081
  display: "flex",
10989
11082
  alignItems: "center",
10990
11083
  justifyContent: "center",
10991
11084
  paddingTop: 16,
10992
11085
  paddingBottom: 16,
10993
- }, children: [jsx(ModalH1, { children: "Insufficient balance." }), jsx(Button, { onClick: () => setRoute(ROUTES.SELECT_METHOD), children: "Select Another Method" })] })), jsx(OptionsList, { requiredSkeletons: 4, isLoading: solanaPaymentOptions.isLoading, options: optionsList })] }));
11086
+ }, children: [jsx(ModalH1, { children: "Insufficient balance." }), jsx(SelectAnotherMethodButton, {})] })), jsx(OptionsList, { requiredSkeletons: 4, isLoading: solanaPaymentOptions.isLoading, options: optionsList, orDivider: optionsList.length != 0 }), optionsList.length != 0 && jsx(SelectAnotherMethodButton, {})] }));
10994
11087
  };
10995
11088
 
10996
11089
  const WaitingDepositAddress = () => {
@@ -11028,7 +11121,7 @@ const WaitingDepositAddress = () => {
11028
11121
  useEffect(() => {
11029
11122
  triggerResize();
11030
11123
  }, [details]);
11031
- 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" })] }))] })) }));
11124
+ 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(SelectAnotherMethodButton, {})] })) : (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" })] }))] })) }));
11032
11125
  };
11033
11126
 
11034
11127
  const WaitingExternal = () => {
@@ -11062,7 +11155,11 @@ const WaitingExternal = () => {
11062
11155
  const openExternalWindow = (url) => {
11063
11156
  if (selectedExternalOption?.id === "Coinbase") {
11064
11157
  //opening Coinbase onramp in a popup window in portrait mode in the center of the screen
11065
- window.open(url, "popupWindow", `width=500,height=700,left=${(window.screen.width - 500) / 2},top=${(window.screen.height - 700) / 2}`);
11158
+ const width = 500;
11159
+ const height = 700;
11160
+ const left = Math.max(0, Math.floor((window.innerWidth - width) / 2) + window.screenX);
11161
+ const top = Math.max(0, Math.floor((window.innerHeight - height) / 2) + window.screenY);
11162
+ window.open(url, "popupWindow", `width=${width},height=${height},left=${left},top=${top},scrollbars=yes`);
11066
11163
  }
11067
11164
  else {
11068
11165
  window.open(url, "_blank");
@@ -11087,15 +11184,24 @@ const DaimoPayModal = ({ mode = "auto", theme = "auto", customTheme = customThem
11087
11184
  const context = usePayContext();
11088
11185
  const paymentState = context.paymentState;
11089
11186
  const { payParams, generatePreviewOrder, isDepositFlow, setPaymentWaitingMessage, setSelectedExternalOption, setSelectedTokenOption, setSelectedSolanaTokenOption, setSelectedDepositAddressOption, } = paymentState;
11090
- const { isConnected, connector, chain, address } = useAccount();
11187
+ const { isConnected: isEthConnected, connector, chain, address, } = useAccount();
11188
+ const { connected: isSolanaConnected } = useWallet$1();
11189
+ const { daimoPayOrder } = paymentState;
11190
+ const paymentOptions = daimoPayOrder?.metadata.payer?.paymentOptions;
11191
+ // Solana payment option
11192
+ // Include by default if paymentOptions not provided
11193
+ const includeSolana = paymentOptions == null ||
11194
+ paymentOptions.includes(ExternalPaymentOptions.Solana);
11091
11195
  const chainIsSupported = useChainIsSupported(chain?.id);
11092
11196
  //if chain is unsupported we enforce a "switch chain" prompt
11093
11197
  const closeable = !(context.options?.enforceSupportedChains &&
11094
- isConnected &&
11198
+ isEthConnected &&
11095
11199
  !chainIsSupported);
11096
11200
  const showBackButton = closeable &&
11097
11201
  context.route !== ROUTES.SELECT_METHOD &&
11098
- context.route !== ROUTES.CONFIRMATION;
11202
+ context.route !== ROUTES.CONFIRMATION &&
11203
+ context.route !== ROUTES.SELECT_TOKEN &&
11204
+ context.route !== ROUTES.SOLANA_SELECT_TOKEN;
11099
11205
  const onBack = () => {
11100
11206
  const meta = { event: "click-back" };
11101
11207
  if (context.route === ROUTES.DOWNLOAD) {
@@ -11104,9 +11210,6 @@ const DaimoPayModal = ({ mode = "auto", theme = "auto", customTheme = customThem
11104
11210
  else if (context.route === ROUTES.CONNECTORS) {
11105
11211
  context.setRoute(ROUTES.SELECT_METHOD, meta);
11106
11212
  }
11107
- else if (context.route === ROUTES.SELECT_TOKEN) {
11108
- context.setRoute(ROUTES.SELECT_METHOD, meta);
11109
- }
11110
11213
  else if (context.route === ROUTES.SELECT_AMOUNT) {
11111
11214
  setSelectedTokenOption(undefined);
11112
11215
  context.setRoute(ROUTES.SELECT_TOKEN, meta);
@@ -11207,11 +11310,39 @@ const DaimoPayModal = ({ mode = "auto", theme = "auto", customTheme = customThem
11207
11310
  }
11208
11311
  context.setOpen(false, { event: "click-close" });
11209
11312
  }
11313
+ // Separate effect for initial route when modal opens
11314
+ useEffect(() => {
11315
+ if (context.open &&
11316
+ !isSolanaConnected &&
11317
+ (context.wcWallet || isEthConnected)) {
11318
+ // Only set initial route if we're at SELECT_METHOD when opening
11319
+ if (context.route === ROUTES.SELECT_METHOD) {
11320
+ context.setRoute(ROUTES.SELECT_TOKEN, {
11321
+ event: "eth_connected_on_open",
11322
+ walletId: connector?.id,
11323
+ chainId: chain?.id,
11324
+ address,
11325
+ });
11326
+ }
11327
+ }
11328
+ else if (context.open &&
11329
+ isSolanaConnected &&
11330
+ !isEthConnected &&
11331
+ context.wcWallet === undefined &&
11332
+ includeSolana) {
11333
+ if (context.route === ROUTES.SELECT_METHOD) {
11334
+ context.setRoute(ROUTES.SOLANA_SELECT_TOKEN, {
11335
+ event: "solana_connected_on_open",
11336
+ });
11337
+ }
11338
+ }
11339
+ // If both are connected, do nothing and stay on SELECT_METHOD
11340
+ }, [context.open]);
11210
11341
  useEffect(() => {
11211
11342
  if (context.route === ROUTES.CONNECT ||
11212
11343
  context.route === ROUTES.CONNECTORS ||
11213
11344
  context.route === ROUTES.MOBILECONNECTORS) {
11214
- if (isConnected) {
11345
+ if (isEthConnected) {
11215
11346
  context.setRoute(ROUTES.SELECT_TOKEN, {
11216
11347
  event: "connected",
11217
11348
  walletId: connector?.id,
@@ -11220,7 +11351,7 @@ const DaimoPayModal = ({ mode = "auto", theme = "auto", customTheme = customThem
11220
11351
  });
11221
11352
  }
11222
11353
  }
11223
- }, [isConnected, context.route]);
11354
+ }, [isEthConnected, context.route]);
11224
11355
  useEffect(() => context.setMode(mode), [mode]);
11225
11356
  useEffect(() => context.setTheme(theme), [theme]);
11226
11357
  useEffect(() => context.setCustomTheme(customTheme), [customTheme]);