@openfort/react 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/build/assets/logos.d.ts +3 -0
  2. package/build/assets/logos.js +2 -0
  3. package/build/assets/logos.js.map +1 -1
  4. package/build/components/Common/Modal/styles.js +3 -0
  5. package/build/components/Common/Modal/styles.js.map +1 -1
  6. package/build/components/Common/ScrollArea/index.d.ts +5 -1
  7. package/build/components/Common/ScrollArea/index.js +2 -2
  8. package/build/components/Common/ScrollArea/styles.d.ts +4 -1
  9. package/build/components/Common/ScrollArea/styles.js +19 -4
  10. package/build/components/Common/ScrollArea/styles.js.map +1 -1
  11. package/build/components/Common/SolanaChain/index.d.ts +8 -0
  12. package/build/components/Common/SolanaChain/index.js +40 -0
  13. package/build/components/Common/SolanaChain/index.js.map +1 -0
  14. package/build/components/ConnectModal/index.js +17 -5
  15. package/build/components/ConnectModal/index.js.map +1 -1
  16. package/build/components/Openfort/types.d.ts +17 -11
  17. package/build/components/Openfort/types.js +1 -0
  18. package/build/components/Openfort/types.js.map +1 -1
  19. package/build/components/PageContent/index.d.ts +2 -1
  20. package/build/components/PageContent/index.js +2 -2
  21. package/build/components/Pages/Buy/coinbaseApi.d.ts +1 -1
  22. package/build/components/Pages/Buy/coinbaseApi.js +2 -13
  23. package/build/components/Pages/Buy/coinbaseApi.js.map +1 -1
  24. package/build/components/Pages/Buy/evmCurrencies.d.ts +11 -0
  25. package/build/components/Pages/Buy/evmCurrencies.js +27 -0
  26. package/build/components/Pages/Buy/evmCurrencies.js.map +1 -0
  27. package/build/components/Pages/Buy/index.js +8 -1
  28. package/build/components/Pages/Buy/index.js.map +1 -1
  29. package/build/components/Pages/Buy/onrampApi.d.ts +8 -1
  30. package/build/components/Pages/Buy/onrampApi.js +24 -14
  31. package/build/components/Pages/Buy/onrampApi.js.map +1 -1
  32. package/build/components/Pages/Buy/solanaCurrencies.d.ts +9 -0
  33. package/build/components/Pages/Buy/solanaCurrencies.js +25 -0
  34. package/build/components/Pages/Buy/solanaCurrencies.js.map +1 -0
  35. package/build/components/Pages/Buy/stripeApi.d.ts +1 -1
  36. package/build/components/Pages/Buy/stripeApi.js +2 -13
  37. package/build/components/Pages/Buy/stripeApi.js.map +1 -1
  38. package/build/components/Pages/BuyComplete/index.js +7 -1
  39. package/build/components/Pages/BuyComplete/index.js.map +1 -1
  40. package/build/components/Pages/BuyProcessing/index.js +9 -5
  41. package/build/components/Pages/BuyProcessing/index.js.map +1 -1
  42. package/build/components/Pages/BuyProviderSelect/styles.d.ts +2 -1
  43. package/build/components/Pages/BuySelectProvider/index.js +10 -5
  44. package/build/components/Pages/BuySelectProvider/index.js.map +1 -1
  45. package/build/components/Pages/Connected/EthereumConnected.js +7 -3
  46. package/build/components/Pages/Connected/EthereumConnected.js.map +1 -1
  47. package/build/components/Pages/Connected/SolanaConnected.js +3 -2
  48. package/build/components/Pages/Connected/SolanaConnected.js.map +1 -1
  49. package/build/components/Pages/Deposit/AssetChainLogo.d.ts +5 -2
  50. package/build/components/Pages/Deposit/AssetChainLogo.js +21 -4
  51. package/build/components/Pages/Deposit/AssetChainLogo.js.map +1 -1
  52. package/build/components/Pages/Deposit/DepositAddressBlock.js +1 -1
  53. package/build/components/Pages/Deposit/DepositProgress.js +3 -2
  54. package/build/components/Pages/Deposit/DepositProgress.js.map +1 -1
  55. package/build/components/Pages/Deposit/DepositSuccess.js +2 -1
  56. package/build/components/Pages/Deposit/DepositSuccess.js.map +1 -1
  57. package/build/components/Pages/Deposit/RouteSelectors.js +11 -1
  58. package/build/components/Pages/Deposit/RouteSelectors.js.map +1 -1
  59. package/build/components/Pages/Deposit/SameChainDepositStatus.d.ts +7 -0
  60. package/build/components/Pages/Deposit/SameChainDepositStatus.js +34 -0
  61. package/build/components/Pages/Deposit/SameChainDepositStatus.js.map +1 -0
  62. package/build/components/Pages/Deposit/SameChainDepositSuccess.d.ts +11 -0
  63. package/build/components/Pages/Deposit/SameChainDepositSuccess.js +30 -0
  64. package/build/components/Pages/Deposit/SameChainDepositSuccess.js.map +1 -0
  65. package/build/components/Pages/Deposit/TestnetNotice.d.ts +10 -0
  66. package/build/components/Pages/Deposit/TestnetNotice.js +131 -0
  67. package/build/components/Pages/Deposit/TestnetNotice.js.map +1 -0
  68. package/build/components/Pages/Deposit/UnsupportedNetworkNotice.d.ts +12 -0
  69. package/build/components/Pages/Deposit/UnsupportedNetworkNotice.js +111 -0
  70. package/build/components/Pages/Deposit/UnsupportedNetworkNotice.js.map +1 -0
  71. package/build/components/Pages/Deposit/index.js +35 -5
  72. package/build/components/Pages/Deposit/index.js.map +1 -1
  73. package/build/components/Pages/Deposit/paymentOptions.d.ts +6 -0
  74. package/build/components/Pages/Deposit/paymentOptions.js +10 -4
  75. package/build/components/Pages/Deposit/paymentOptions.js.map +1 -1
  76. package/build/components/Pages/Deposit/useDepositRoute.d.ts +2 -1
  77. package/build/components/Pages/Deposit/useDepositRoute.js +36 -13
  78. package/build/components/Pages/Deposit/useDepositRoute.js.map +1 -1
  79. package/build/components/Pages/Deposit/useFundingTarget.d.ts +2 -4
  80. package/build/components/Pages/Deposit/useFundingTarget.js +3 -5
  81. package/build/components/Pages/Deposit/useFundingTarget.js.map +1 -1
  82. package/build/components/Pages/Deposit/useSameChainArrival.d.ts +19 -0
  83. package/build/components/Pages/Deposit/useSameChainArrival.js +86 -0
  84. package/build/components/Pages/Deposit/useSameChainArrival.js.map +1 -0
  85. package/build/components/Pages/DepositCex/index.js +7 -8
  86. package/build/components/Pages/DepositCex/index.js.map +1 -1
  87. package/build/components/Pages/DepositCrypto/index.js +26 -3
  88. package/build/components/Pages/DepositCrypto/index.js.map +1 -1
  89. package/build/components/Pages/DepositWallet/DepositWalletDesktop.d.ts +4 -1
  90. package/build/components/Pages/DepositWallet/DepositWalletDesktop.js +19 -27
  91. package/build/components/Pages/DepositWallet/DepositWalletDesktop.js.map +1 -1
  92. package/build/components/Pages/DepositWallet/index.d.ts +5 -5
  93. package/build/components/Pages/DepositWallet/index.js +82 -39
  94. package/build/components/Pages/DepositWallet/index.js.map +1 -1
  95. package/build/components/Pages/DepositWallet/walletDeeplinks.d.ts +6 -4
  96. package/build/components/Pages/DepositWallet/walletDeeplinks.js +3 -1
  97. package/build/components/Pages/DepositWallet/walletDeeplinks.js.map +1 -1
  98. package/build/components/Pages/SelectToken/SolanaSelectToken.d.ts +1 -0
  99. package/build/components/Pages/SelectToken/SolanaSelectToken.js +50 -0
  100. package/build/components/Pages/SelectToken/SolanaSelectToken.js.map +1 -0
  101. package/build/components/Pages/SelectToken/index.js +13 -2
  102. package/build/components/Pages/SelectToken/index.js.map +1 -1
  103. package/build/components/Pages/SelectToken/styles.d.ts +2 -1
  104. package/build/components/Pages/Send/SolanaSend.js +32 -31
  105. package/build/components/Pages/Send/SolanaSend.js.map +1 -1
  106. package/build/components/Pages/Send/utils.js +4 -1
  107. package/build/components/Pages/Send/utils.js.map +1 -1
  108. package/build/components/Pages/SendConfirmation/SolanaSendConfirmation.js +57 -13
  109. package/build/components/Pages/SendConfirmation/SolanaSendConfirmation.js.map +1 -1
  110. package/build/components/Pages/SendConfirmation/index.js +1 -1
  111. package/build/components/Pages/SendConfirmation/styles.d.ts +0 -5
  112. package/build/components/Pages/SendConfirmation/styles.js +1 -39
  113. package/build/components/Pages/SendConfirmation/styles.js.map +1 -1
  114. package/build/constants/chainConfigs.js +32 -32
  115. package/build/constants/logos.d.ts +4 -0
  116. package/build/constants/logos.js +25 -1
  117. package/build/constants/logos.js.map +1 -1
  118. package/build/ethereum/hooks/useEthereumWalletAssets.js +39 -3
  119. package/build/ethereum/hooks/useEthereumWalletAssets.js.map +1 -1
  120. package/build/hooks/openfort/useFunding.js +7 -7
  121. package/build/hooks/openfort/useFundingChains.d.ts +6 -0
  122. package/build/hooks/openfort/useFundingChains.js +22 -10
  123. package/build/hooks/openfort/useFundingChains.js.map +1 -1
  124. package/build/shared/hooks/useAsyncData.js +15 -2
  125. package/build/shared/hooks/useAsyncData.js.map +1 -1
  126. package/build/shared/utils/explorer.js +6 -4
  127. package/build/shared/utils/explorer.js.map +1 -1
  128. package/build/solana/transfer.d.ts +35 -6
  129. package/build/solana/transfer.js +112 -18
  130. package/build/solana/transfer.js.map +1 -1
  131. package/build/solana/types.d.ts +8 -0
  132. package/build/utils/validation.d.ts +9 -0
  133. package/build/utils/validation.js +14 -1
  134. package/build/utils/validation.js.map +1 -1
  135. package/build/version.d.ts +1 -1
  136. package/build/version.js +1 -1
  137. package/build/wagmi/components/ChainSelect/index.js +3 -2
  138. package/build/wagmi/components/ChainSelect/index.js.map +1 -1
  139. package/build/wagmi/components/ChainSelectList/index.js +3 -2
  140. package/build/wagmi/components/ChainSelectList/index.js.map +1 -1
  141. package/build/wagmi/components/SwitchNetworks/index.js +3 -2
  142. package/build/wagmi/components/SwitchNetworks/index.js.map +1 -1
  143. package/build/wagmi/useSwitchChainFiltered.d.ts +199 -0
  144. package/build/wagmi/useSwitchChainFiltered.js +53 -0
  145. package/build/wagmi/useSwitchChainFiltered.js.map +1 -0
  146. package/package.json +5 -1
@@ -0,0 +1,131 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState, useEffect } from 'react';
3
+ import styled from '../../../styles/styled/index.js';
4
+ import { getPublishableKeyEnvironment } from '../../../utils/validation.js';
5
+ import { useOpenfort } from '../../Openfort/useOpenfort.js';
6
+
7
+ /** Relay's own testnet guide — the authoritative explanation of the limitation. */
8
+ const RELAY_TESTNET_DOCS = 'https://docs.relay.link/references/api/api_guides/testnet#testnet-support';
9
+ const FlaskIcon = () => (jsxs("svg", { width: "15", height: "15", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [jsx("path", { d: "M6 1.5h4M6.5 1.5v4.2L3.3 11.4A1.5 1.5 0 0 0 4.6 13.7h6.8a1.5 1.5 0 0 0 1.3-2.3L9.5 5.7V1.5", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round" }), jsx("path", { d: "M5.1 9h5.8", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round" })] }));
10
+ const Card = styled.div `
11
+ text-align: left;
12
+ margin-bottom: 14px;
13
+ border-radius: 12px;
14
+ /* Amber "sandbox" tint that reads on both light and dark themes. */
15
+ background: rgba(245, 158, 11, 0.09);
16
+ border: 1px solid rgba(245, 158, 11, 0.28);
17
+ color: var(--ck-body-color);
18
+ `;
19
+ /** The always-visible summary row; the whole row toggles the details. */
20
+ const Header = styled.button `
21
+ appearance: none;
22
+ width: 100%;
23
+ display: flex;
24
+ align-items: center;
25
+ gap: 9px;
26
+ padding: 10px 12px;
27
+ background: none;
28
+ border: 0;
29
+ cursor: pointer;
30
+ color: inherit;
31
+ font: inherit;
32
+ text-align: left;
33
+ `;
34
+ const Badge = styled.span `
35
+ flex-shrink: 0;
36
+ width: 22px;
37
+ height: 22px;
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: center;
41
+ border-radius: 7px;
42
+ color: #b45309;
43
+ background: rgba(245, 158, 11, 0.18);
44
+ `;
45
+ const Summary = styled.span `
46
+ flex: 1;
47
+ min-width: 0;
48
+ font-size: 13px;
49
+ font-weight: 600;
50
+ line-height: 1.3;
51
+ `;
52
+ const Chevron = styled.span `
53
+ flex-shrink: 0;
54
+ color: var(--ck-body-color-muted, #6b7280);
55
+ font-size: 11px;
56
+ transition: transform 150ms ease;
57
+ transform: rotate(${({ $open }) => ($open ? '90deg' : '0deg')});
58
+ `;
59
+ const Body = styled.div `
60
+ display: flex;
61
+ flex-direction: column;
62
+ gap: 7px;
63
+ padding: 0 12px 12px 43px;
64
+ font-size: 12.5px;
65
+ line-height: 1.45;
66
+ `;
67
+ const Muted = styled.p `
68
+ margin: 0;
69
+ color: var(--ck-body-color-muted, #6b7280);
70
+ `;
71
+ const Rules = styled.ul `
72
+ margin: 0;
73
+ padding: 0;
74
+ list-style: none;
75
+ display: flex;
76
+ flex-direction: column;
77
+ gap: 3px;
78
+
79
+ li {
80
+ display: flex;
81
+ align-items: flex-start;
82
+ gap: 7px;
83
+ }
84
+ li[data-ok='true']::before {
85
+ content: '✓';
86
+ color: #16a34a;
87
+ font-weight: 700;
88
+ }
89
+ li[data-ok='false']::before {
90
+ content: '✕';
91
+ color: #dc2626;
92
+ font-weight: 700;
93
+ }
94
+ `;
95
+ const DocsLink = styled.a `
96
+ display: inline-flex;
97
+ align-items: center;
98
+ gap: 4px;
99
+ width: fit-content;
100
+ font-weight: 600;
101
+ color: var(--ck-body-color);
102
+ text-decoration: underline;
103
+ text-underline-offset: 2px;
104
+
105
+ &:hover {
106
+ opacity: 0.8;
107
+ }
108
+ `;
109
+ /**
110
+ * A dev-facing notice shown only for test keys (`pk_test_…`) in the Deposit flow.
111
+ *
112
+ * Collapsed by default to a single summary line; expands to explain that funding
113
+ * routes through Relay, whose testnet rail bridges the same asset but cannot swap
114
+ * to a different token (testnets lack DEX liquidity, so e.g. `ETH → USDC` fails),
115
+ * and that card/exchange rails are mainnet-only. Links to Relay's testnet guide.
116
+ * Renders nothing on live keys.
117
+ */
118
+ function TestnetNotice() {
119
+ const { publishableKey, triggerResize } = useOpenfort();
120
+ const [open, setOpen] = useState(false);
121
+ // Re-measure the modal when the details expand/collapse so it grows/shrinks to fit.
122
+ useEffect(() => {
123
+ triggerResize();
124
+ }, [open, triggerResize]);
125
+ if (getPublishableKeyEnvironment(publishableKey) !== 'test')
126
+ return null;
127
+ return (jsxs(Card, { children: [jsxs(Header, { type: "button", "aria-expanded": open, onClick: () => setOpen((v) => !v), children: [jsx(Badge, { children: jsx(FlaskIcon, {}) }), jsx(Summary, { children: "Testnet mode \u2014 funding is limited" }), jsx(Chevron, { "$open": open, children: "\u25B6" })] }), open && (jsxs(Body, { children: [jsx(Muted, { children: "Deposits route through Relay's testnet rail. It bridges the same asset but can't swap between tokens \u2014 testnets have no DEX liquidity. Card and exchange rails are mainnet-only." }), jsxs(Rules, { children: [jsx("li", { "data-ok": "true", children: "Bridging the same asset (e.g. ETH \u2192 ETH) and same-chain transfers" }), jsx("li", { "data-ok": "false", children: "Swapping to another token (e.g. \u2192 USDC) \u2014 fails with \"$0 liquidity\"" })] }), jsx(Muted, { children: "To test swaps, card or exchange deposits, use a live key on a low-cost chain like Base." }), jsx(DocsLink, { href: RELAY_TESTNET_DOCS, target: "_blank", rel: "noreferrer", children: "Why? Read Relay's testnet guide \u2197" })] }))] }));
128
+ }
129
+
130
+ export { TestnetNotice };
131
+ //# sourceMappingURL=TestnetNotice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestnetNotice.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,12 @@
1
+ import type { FundingChain } from '../../../hooks/openfort/useFundingChains';
2
+ /**
3
+ * Shown in the deposit flow when the active funding TARGET chain (the embedded
4
+ * wallet's chain) isn't one the rail can deliver to — e.g. Polygon Amoy or a
5
+ * Solana testnet, which Relay's testnet rail doesn't route. Explains why, and
6
+ * (on EVM) offers a one-tap switch to the supported chains. Solana-only contexts
7
+ * have no in-VM switch, so they get the explanation alone.
8
+ */
9
+ export declare function UnsupportedNetworkNotice({ targetChain, railChains, }: {
10
+ targetChain: string;
11
+ railChains: FundingChain[];
12
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,111 @@
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
+ import { chainConfigs } from '../../../constants/chainConfigs.js';
3
+ import { useEthereumBridge } from '../../../ethereum/OpenfortEthereumBridgeContext.js';
4
+ import styled from '../../../styles/styled/index.js';
5
+ import { useSwitchChainFiltered } from '../../../wagmi/useSwitchChainFiltered.js';
6
+ import Chain from '../../Common/Chain/index.js';
7
+ import { ScrollArea } from '../../Common/ScrollArea/index.js';
8
+ import { isSolana } from './sources.js';
9
+
10
+ /** Readable name for a CAIP-2 chain the rail can't deliver to. */
11
+ function chainName(caip) {
12
+ var _a, _b;
13
+ if (isSolana(caip))
14
+ return 'Solana';
15
+ const id = Number(caip.split(':')[1]);
16
+ return (_b = (_a = chainConfigs.find((c) => c.id === id)) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : 'this network';
17
+ }
18
+ const Card = styled.div `
19
+ text-align: left;
20
+ display: flex;
21
+ flex-direction: column;
22
+ gap: 10px;
23
+ padding: 14px;
24
+ margin-top: 4px;
25
+ border-radius: 12px;
26
+ background: var(--ck-body-background-secondary, #fafafa);
27
+ border: 1px solid var(--ck-body-divider, #e4e4e7);
28
+ color: var(--ck-body-color);
29
+ `;
30
+ const Title = styled.div `
31
+ font-size: 14px;
32
+ font-weight: 600;
33
+ `;
34
+ const Body = styled.p `
35
+ margin: 0;
36
+ font-size: 13px;
37
+ line-height: 1.45;
38
+ color: var(--ck-body-color-muted, #6b7280);
39
+ `;
40
+ const Label = styled.div `
41
+ font-size: 12px;
42
+ font-weight: 600;
43
+ color: var(--ck-body-color-muted, #6b7280);
44
+ `;
45
+ const SwitchButtons = styled.div `
46
+ display: flex;
47
+ flex-direction: column;
48
+ gap: 8px;
49
+ `;
50
+ const SwitchButton = styled.button `
51
+ appearance: none;
52
+ display: flex;
53
+ align-items: center;
54
+ gap: 10px;
55
+ width: 100%;
56
+ box-sizing: border-box;
57
+ padding: 10px 12px;
58
+ border-radius: 10px;
59
+ border: 1px solid var(--ck-body-divider, #e4e4e7);
60
+ background: var(--ck-body-background, #fff);
61
+ color: var(--ck-body-color);
62
+ font-size: 14px;
63
+ font-weight: 500;
64
+ cursor: pointer;
65
+
66
+ &:hover:not(:disabled) {
67
+ background: var(--ck-secondary-button-hover-background, #f3f3f5);
68
+ }
69
+ &:disabled {
70
+ opacity: 0.55;
71
+ cursor: default;
72
+ }
73
+
74
+ .name {
75
+ flex: 1;
76
+ text-align: left;
77
+ }
78
+ .chevron {
79
+ color: var(--ck-body-color-muted, #6b7280);
80
+ }
81
+ `;
82
+ /**
83
+ * Shown in the deposit flow when the active funding TARGET chain (the embedded
84
+ * wallet's chain) isn't one the rail can deliver to — e.g. Polygon Amoy or a
85
+ * Solana testnet, which Relay's testnet rail doesn't route. Explains why, and
86
+ * (on EVM) offers a one-tap switch to the supported chains. Solana-only contexts
87
+ * have no in-VM switch, so they get the explanation alone.
88
+ */
89
+ function UnsupportedNetworkNotice({ targetChain, railChains, }) {
90
+ const bridge = useEthereumBridge();
91
+ return (jsxs(Card, { children: [jsxs(Title, { children: ["Funding isn't available on ", chainName(targetChain)] }), jsx(Body, { children: isSolana(targetChain)
92
+ ? "Solana isn't supported by the funding rail in test mode. Switch to a supported EVM testnet to add funds."
93
+ : "The funding rail can't deliver to this network. Switch to a supported one to add funds." }), bridge && jsx(SupportedChainSwitcher, { railChains: railChains })] }));
94
+ }
95
+ /**
96
+ * EVM-only: the rail-supported chains the wallet can switch to. Rendered only when
97
+ * an Ethereum bridge is present (wagmi), so the wagmi hook below never runs in a
98
+ * Solana-only provider tree.
99
+ */
100
+ function SupportedChainSwitcher({ railChains }) {
101
+ const { chains, switchChain, isPending } = useSwitchChainFiltered();
102
+ const supported = chains.filter((c) => railChains.some((rc) => rc.id === `eip155:${c.id}`));
103
+ if (supported.length === 0)
104
+ return null;
105
+ return (jsxs(Fragment, { children: [jsx(Label, { children: "Switch to a supported network" }), jsx(ScrollArea, { height: 156, children: jsx(SwitchButtons, { children: supported.map((c) => {
106
+ return (jsxs(SwitchButton, { type: "button", disabled: isPending || !switchChain, onClick: () => switchChain === null || switchChain === void 0 ? void 0 : switchChain({ chainId: c.id }), children: [jsx(Chain, { id: c.id, size: 22 }), jsx("span", { className: "name", children: c.name }), jsx("span", { className: "chevron", "aria-hidden": true, children: "\u203A" })] }, c.id));
107
+ }) }) })] }));
108
+ }
109
+
110
+ export { UnsupportedNetworkNotice };
111
+ //# sourceMappingURL=UnsupportedNetworkNotice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnsupportedNetworkNotice.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,15 +1,25 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { ChainTypeEnum } from '@openfort/openfort-js';
3
+ import { useEffect } from 'react';
2
4
  import { DollarIcon, BuyIcon, WalletIcon, ReceiveIcon, ExternalLinkIcon } from '../../../assets/icons.js';
3
5
  import Logos from '../../../assets/logos.js';
4
6
  import { useFunding } from '../../../hooks/openfort/useFunding.js';
5
7
  import { useFundingChains } from '../../../hooks/openfort/useFundingChains.js';
6
8
  import useIsMobile from '../../../hooks/useIsMobile.js';
9
+ import { useOpenfortCore } from '../../../openfort/useOpenfort.js';
10
+ import { getPublishableKeyEnvironment } from '../../../utils/validation.js';
7
11
  import { ModalHeading } from '../../Common/Modal/styles.js';
12
+ import PoweredByFooter from '../../Common/PoweredByFooter/index.js';
8
13
  import { FundingMethod, routes } from '../../Openfort/types.js';
9
14
  import { useOpenfort } from '../../Openfort/useOpenfort.js';
10
15
  import { PageContent } from '../../PageContent/index.js';
16
+ import { EVM_BUY_CURRENCIES } from '../Buy/evmCurrencies.js';
17
+ import { SOLANA_BUY_CURRENCIES } from '../Buy/solanaCurrencies.js';
11
18
  import { getPaymentOptions } from './paymentOptions.js';
12
19
  import { DepositContent, OptionList, OptionButton, OptionLeft, OptionIconBadge, OptionInfo, OptionTitle, OptionSubtitle, LogoCluster } from './styles.js';
20
+ import { TestnetNotice } from './TestnetNotice.js';
21
+ import { UnsupportedNetworkNotice } from './UnsupportedNetworkNotice.js';
22
+ import { useFundingTarget } from './useFundingTarget.js';
13
23
 
14
24
  /** The action icon shown in each row's left badge (icons default to 20×20). */
15
25
  const METHOD_ICON = {
@@ -42,13 +52,25 @@ const hideBrokenLogo = (e) => {
42
52
  */
43
53
  const Deposit = () => {
44
54
  var _a;
45
- const { setRoute, setBuyForm, uiConfig } = useOpenfort();
55
+ const { setRoute, setBuyForm, uiConfig, publishableKey, triggerResize } = useOpenfort();
56
+ const { chainType } = useOpenfortCore();
46
57
  const isMobile = useIsMobile();
47
58
  const { isAvailable } = useFunding();
48
- const { chains } = useFundingChains();
59
+ const { chains, railChains, loading: chainsLoading } = useFundingChains();
60
+ const target = useFundingTarget();
61
+ // The rail can only deliver to chains it lists. If the embedded wallet's target
62
+ // chain (e.g. Polygon Amoy or a Solana testnet) isn't one of them, there's no
63
+ // deposit route at all — show the explanation instead of any method options.
64
+ const targetUnsupported = !chainsLoading && railChains.length > 0 && !railChains.some((c) => c.id === target.chain);
65
+ // Content swaps between the option list and the notice once chains resolve; the
66
+ // modal only re-measures on an explicit resize, so nudge it when that flips.
67
+ useEffect(() => {
68
+ triggerResize();
69
+ }, [targetUnsupported, triggerResize]);
49
70
  const options = getPaymentOptions({
50
71
  isMobile,
51
72
  fundingAvailable: isAvailable,
73
+ testnet: getPublishableKeyEnvironment(publishableKey) === 'test',
52
74
  methods: (_a = uiConfig.funding) === null || _a === void 0 ? void 0 : _a.methods,
53
75
  });
54
76
  // Distinct source-currency logos (USDC, USDT, ETH, …) for the "from address" row.
@@ -87,13 +109,21 @@ const Deposit = () => {
87
109
  }
88
110
  // Fiat rails reuse the existing Buy flow; preselect the chosen provider so
89
111
  // Apple Pay / Card land on the right rail.
90
- setBuyForm((prev) => ({ ...prev, providerId: target.providerId }));
112
+ setBuyForm((prev) => ({
113
+ ...prev,
114
+ providerId: target.providerId,
115
+ // Default the card-buy to USDC per chain family. Without this the EVM default
116
+ // resolves to the wallet's (often empty) asset list — "no supported tokens" —
117
+ // and the Solana native default would resolve to SOL (isSameToken treats any
118
+ // two natives as equal).
119
+ asset: chainType === ChainTypeEnum.SVM ? SOLANA_BUY_CURRENCIES[0] : EVM_BUY_CURRENCIES[0],
120
+ }));
91
121
  setRoute(routes.BUY);
92
122
  };
93
- return (jsxs(PageContent, { onBack: routes.CONNECTED, children: [jsx(ModalHeading, { children: "Add funds" }), jsx(DepositContent, { children: jsx(OptionList, { children: options.map((option) => {
123
+ return (jsxs(PageContent, { onBack: routes.CONNECTED, children: [jsx(ModalHeading, { children: "Add funds" }), jsx(TestnetNotice, {}), targetUnsupported ? (jsx(UnsupportedNetworkNotice, { targetChain: target.chain, railChains: railChains })) : (jsx(DepositContent, { children: jsx(OptionList, { children: options.map((option) => {
94
124
  var _a;
95
125
  return (jsxs(OptionButton, { type: "button", disabled: option.disabled, onClick: () => go(option.target), children: [jsxs(OptionLeft, { children: [jsx(OptionIconBadge, { children: METHOD_ICON[option.id] }), jsxs(OptionInfo, { children: [jsx(OptionTitle, { children: option.title }), jsx(OptionSubtitle, { children: (_a = option.disabledReason) !== null && _a !== void 0 ? _a : option.subtitle })] })] }), jsx(LogoCluster, { children: clusterFor(option.id) })] }, option.id));
96
- }) }) })] }));
126
+ }) }) })), jsx(PoweredByFooter, {})] }));
97
127
  };
98
128
 
99
129
  export { Deposit as default };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -28,6 +28,12 @@ type PaymentOptionsContext = {
28
28
  isMobile: boolean;
29
29
  /** When the funding backend is unavailable, crypto/CEX rows are disabled. */
30
30
  fundingAvailable: boolean;
31
+ /**
32
+ * Test-key (`pk_test_…`) project. The fiat (card/Apple Pay) and exchange rails
33
+ * settle real money on mainnet only — Stripe/Coinbase can't deliver to a testnet
34
+ * wallet — so they're disabled here. The crypto rails (Relay testnet) stay on.
35
+ */
36
+ testnet?: boolean;
31
37
  /**
32
38
  * Integrator-selected methods, in display order. When set, only these show
33
39
  * (still subject to device/availability gating). Omit to show all.
@@ -17,19 +17,19 @@ const ALL_METHODS = [
17
17
  {
18
18
  id: FundingMethod.WALLET,
19
19
  title: 'Transfer from wallet',
20
- subtitle: 'Min $1 · No fee · 10 sec',
20
+ subtitle: 'Min $1 · Bridge fee · 10 sec',
21
21
  target: { kind: 'wallet' },
22
22
  },
23
23
  {
24
24
  id: FundingMethod.ADDRESS,
25
25
  title: 'Transfer from address',
26
- subtitle: 'Min $1 · No fee · 10 sec',
26
+ subtitle: 'Min $1 · Bridge fee · 10 sec',
27
27
  target: { kind: 'crypto' },
28
28
  },
29
29
  {
30
30
  id: FundingMethod.EXCHANGE,
31
31
  title: 'Transfer from Exchange',
32
- subtitle: 'Min $1 · Network fee · 2 min',
32
+ subtitle: 'Min $5 · Network fee · 2 min',
33
33
  target: { kind: 'cex' },
34
34
  },
35
35
  ];
@@ -51,7 +51,13 @@ function getPaymentOptions(ctx) {
51
51
  ? [...visible].sort((a, b) => Number(b.id === FundingMethod.APPLE_PAY) - Number(a.id === FundingMethod.APPLE_PAY))
52
52
  : visible;
53
53
  return ordered.map((method) => {
54
- const fundingRail = method.target.kind === 'crypto' || method.target.kind === 'wallet' || method.target.kind === 'cex';
54
+ const kind = method.target.kind;
55
+ // Fiat (card/Apple Pay) and exchange rails move real money and only settle on
56
+ // mainnet, so a test-key project can't use them — disable with a clear reason.
57
+ if (ctx.testnet && (kind === 'buy' || kind === 'cex')) {
58
+ return { ...method, disabled: true, disabledReason: 'Not available on testnet' };
59
+ }
60
+ const fundingRail = kind === 'crypto' || kind === 'wallet' || kind === 'cex';
55
61
  if (fundingRail && !ctx.fundingAvailable) {
56
62
  return { ...method, disabled: true, disabledReason: 'Coming soon' };
57
63
  }
@@ -1 +1 @@
1
- {"version":3,"file":"paymentOptions.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"paymentOptions.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -21,11 +21,12 @@ export declare function useDepositRoute(kind: DepositRouteKind): {
21
21
  target: {
22
22
  chain: string;
23
23
  currency: string;
24
- address?: string;
25
24
  };
26
25
  pm: import("../../../hooks/openfort/useFunding").PaymentMethod | null;
27
26
  receiverAddress: string | null;
28
27
  sameChain: boolean;
28
+ targetUnsupported: boolean;
29
+ railChains: FundingChain[];
29
30
  status: import("../../../hooks/openfort/useFunding").SessionStatus | "idle";
30
31
  loading: boolean;
31
32
  error: Error | null;
@@ -1,9 +1,7 @@
1
- import { ChainTypeEnum } from '@openfort/openfort-js';
2
1
  import { useState, useRef, useEffect } from 'react';
3
2
  import { useEthereumEmbeddedWallet } from '../../../ethereum/hooks/useEthereumEmbeddedWallet.js';
4
3
  import { useFunding } from '../../../hooks/openfort/useFunding.js';
5
4
  import { useFundingChains, nominalUnits } from '../../../hooks/openfort/useFundingChains.js';
6
- import { useOpenfortCore } from '../../../openfort/useOpenfort.js';
7
5
  import { useSolanaEmbeddedWallet } from '../../../solana/hooks/useSolanaEmbeddedWallet.js';
8
6
  import { logger } from '../../../utils/logger.js';
9
7
  import { isCexDeliverable } from './cexChains.js';
@@ -24,20 +22,21 @@ function paymentMethodFor(chain, currency) {
24
22
  */
25
23
  function useDepositRoute(kind) {
26
24
  var _a, _b, _c, _d, _e, _f, _g, _h;
27
- const { chainType } = useOpenfortCore();
28
25
  const ethWallet = useEthereumEmbeddedWallet();
29
26
  const solWallet = useSolanaEmbeddedWallet();
30
- // Funds land in the active chain's embedded wallet (EVM or Solana).
31
- const wallet = chainType === ChainTypeEnum.SVM ? solWallet : ethWallet;
32
27
  const { session, status, error, loading, isAvailable, fund, payLink, reset } = useFunding();
33
- const { chains: allChains, loading: chainsLoading } = useFundingChains();
28
+ const { chains: allChains, railChains, loading: chainsLoading } = useFundingChains();
34
29
  const target = useFundingTarget();
35
- // Drop the destination chain funding is cross-chain; same-chain is a plain
36
- // transfer with no Relay route, so it shouldn't appear as a source option.
37
- const sourceChains = allChains.filter((c) => c.id !== target.chain);
38
- // The CEX rail rides Coinbase Onramp, which only delivers to a fixed set of EVM
39
- // chains offer those as the pay-with sources.
40
- const chains = kind === 'cex' ? sourceChains.filter((c) => isCexDeliverable(c.id)) : sourceChains;
30
+ // The deposit recipient must live on the TARGET chain, so resolve the wallet by
31
+ // the target's family not the active chainType, which can disagree with the
32
+ // target (e.g. an EVM session whose funding target is still Solana) and would
33
+ // send an EVM address as the recipient for a Solana destination.
34
+ const wallet = isSolana(target.chain) ? solWallet : ethWallet;
35
+ // Sources are the full Relay list, including the destination chain itself so
36
+ // same-chain deposits (e.g. Solana → Solana) are offered as a plain transfer to
37
+ // the wallet address, alongside the cross-chain bridge routes. The CEX rail rides
38
+ // Coinbase Onramp, which only delivers to a fixed set of EVM chains.
39
+ const chains = kind === 'cex' ? allChains.filter((c) => isCexDeliverable(c.id)) : allChains;
41
40
  // Where funds land: the active embedded wallet (the Relay deposit recipient).
42
41
  const address = wallet.status === 'connected' ? wallet.address : undefined;
43
42
  const [chainId, setChainId] = useState('');
@@ -50,6 +49,11 @@ function useDepositRoute(kind) {
50
49
  const activeCurrency = (_c = currencies.find((c) => c.symbol === currencySymbol)) !== null && _c !== void 0 ? _c : currencies[0];
51
50
  const chain = (_d = activeChain === null || activeChain === void 0 ? void 0 : activeChain.id) !== null && _d !== void 0 ? _d : target.chain;
52
51
  const sameChain = chain === target.chain;
52
+ // The rail only delivers to chains in its list; if the active funding TARGET (the
53
+ // embedded wallet's chain — e.g. Polygon Amoy or a Solana testnet) isn't one of
54
+ // them, there's no route. Don't call Relay (it would 400 with a cryptic "invalid
55
+ // currency"); the page prompts a switch to a supported chain instead.
56
+ const targetUnsupported = !chainsLoading && railChains.length > 0 && !railChains.some((c) => c.id === target.chain);
53
57
  const receiverAddress = sameChain
54
58
  ? (address !== null && address !== void 0 ? address : null)
55
59
  : ((_f = (_e = session === null || session === void 0 ? void 0 : session.paymentMethod) === null || _e === void 0 ? void 0 : _e.receiverAddress) !== null && _f !== void 0 ? _f : null);
@@ -57,6 +61,11 @@ function useDepositRoute(kind) {
57
61
  useEffect(() => {
58
62
  if (!address || !isAvailable || !activeChain || !activeCurrency)
59
63
  return;
64
+ if (targetUnsupported) {
65
+ lastKey.current = '';
66
+ reset();
67
+ return;
68
+ }
60
69
  if (sameChain) {
61
70
  lastKey.current = '';
62
71
  reset();
@@ -73,7 +82,19 @@ function useDepositRoute(kind) {
73
82
  destChain: target.chain,
74
83
  });
75
84
  fund({ chain: target.chain, currency: target.currency, address }, paymentMethodFor(activeChain.id, activeCurrency)).catch(() => { });
76
- }, [address, activeChain, activeCurrency, isAvailable, sameChain, fund, reset, target.chain, target.currency, kind]);
85
+ }, [
86
+ address,
87
+ activeChain,
88
+ activeCurrency,
89
+ isAvailable,
90
+ sameChain,
91
+ targetUnsupported,
92
+ fund,
93
+ reset,
94
+ target.chain,
95
+ target.currency,
96
+ kind,
97
+ ]);
77
98
  // Surface an empty source list (e.g. no Coinbase-deliverable chains) for diagnosis.
78
99
  useEffect(() => {
79
100
  if (!isAvailable || chainsLoading || chains.length > 0)
@@ -95,6 +116,8 @@ function useDepositRoute(kind) {
95
116
  pm,
96
117
  receiverAddress,
97
118
  sameChain,
119
+ targetUnsupported,
120
+ railChains,
98
121
  status,
99
122
  loading,
100
123
  error,
@@ -1 +1 @@
1
- {"version":3,"file":"useDepositRoute.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"useDepositRoute.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -2,12 +2,10 @@
2
2
  * The destination route Deposit-hub funding settles into. Integrators override the
3
3
  * chain and currency via `uiConfig.funding.{targetChain,targetCurrency}`; both
4
4
  * default to USDC on the active chain type (Base for EVM, Solana mainnet for SVM)
5
- * so the flow works with zero configuration. `address` is the optional integrator
6
- * override (`uiConfig.funding.targetAddress`); when unset, callers fall back to the
7
- * active embedded wallet for the destination chain family.
5
+ * so the flow works with zero configuration. The deposit recipient is always the
6
+ * active embedded wallet for the destination chain family — callers resolve it.
8
7
  */
9
8
  export declare function useFundingTarget(): {
10
9
  chain: string;
11
10
  currency: string;
12
- address?: string;
13
11
  };
@@ -7,19 +7,17 @@ import { DEST_CHAIN_SOL, DEST_CHAIN, DEST_USDC_SOL, DEST_USDC } from './sources.
7
7
  * The destination route Deposit-hub funding settles into. Integrators override the
8
8
  * chain and currency via `uiConfig.funding.{targetChain,targetCurrency}`; both
9
9
  * default to USDC on the active chain type (Base for EVM, Solana mainnet for SVM)
10
- * so the flow works with zero configuration. `address` is the optional integrator
11
- * override (`uiConfig.funding.targetAddress`); when unset, callers fall back to the
12
- * active embedded wallet for the destination chain family.
10
+ * so the flow works with zero configuration. The deposit recipient is always the
11
+ * active embedded wallet for the destination chain family — callers resolve it.
13
12
  */
14
13
  function useFundingTarget() {
15
- var _a, _b, _c, _d, _e;
14
+ var _a, _b, _c, _d;
16
15
  const { uiConfig } = useOpenfort();
17
16
  const { chainType } = useOpenfortCore();
18
17
  const isSolana = chainType === ChainTypeEnum.SVM;
19
18
  return {
20
19
  chain: (_b = (_a = uiConfig.funding) === null || _a === void 0 ? void 0 : _a.targetChain) !== null && _b !== void 0 ? _b : (isSolana ? DEST_CHAIN_SOL : DEST_CHAIN),
21
20
  currency: (_d = (_c = uiConfig.funding) === null || _c === void 0 ? void 0 : _c.targetCurrency) !== null && _d !== void 0 ? _d : (isSolana ? DEST_USDC_SOL : DEST_USDC),
22
- address: (_e = uiConfig.funding) === null || _e === void 0 ? void 0 : _e.targetAddress,
23
21
  };
24
22
  }
25
23
 
@@ -1 +1 @@
1
- {"version":3,"file":"useFundingTarget.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"useFundingTarget.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Watches a wallet's native balance and reports when it increases past the first
3
+ * observed value — i.e. a same-chain deposit landed. Same-chain "transfer from
4
+ * address" has no rail session to poll (the deposit address is the wallet
5
+ * itself), so arrival is read straight from the chain RPC.
6
+ *
7
+ * Self-contained single timeout chain (no shared query cache), so it can't fan
8
+ * out into a request storm: one read in flight at a time, with an interval that
9
+ * grows on each tick and resets to brisk when the user returns to the tab (the
10
+ * moment a deposit was likely just made). On arrival, cached balances are
11
+ * invalidated so the asset list refreshes, and polling stops.
12
+ */
13
+ export declare function useSameChainArrival({ address, chainId, enabled, }: {
14
+ address: string;
15
+ chainId: number;
16
+ enabled: boolean;
17
+ }): {
18
+ arrived: boolean;
19
+ };