@openfort/react 1.5.1 → 1.6.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/components/Common/Chain/styles.d.ts +10 -0
- package/build/components/Common/Chain/styles.js +103 -1
- package/build/components/Common/Chain/styles.js.map +1 -1
- package/build/components/Common/Modal/index.js +16 -0
- package/build/components/Common/Modal/index.js.map +1 -1
- package/build/components/Common/SolanaChain/index.d.ts +5 -4
- package/build/components/Common/SolanaChain/index.js +9 -17
- package/build/components/Common/SolanaChain/index.js.map +1 -1
- package/build/components/ConnectModal/index.js +2 -0
- package/build/components/ConnectModal/index.js.map +1 -1
- package/build/components/Openfort/OpenfortProvider.js +4 -0
- package/build/components/Openfort/OpenfortProvider.js.map +1 -1
- package/build/components/Openfort/context.d.ts +4 -1
- package/build/components/Openfort/types.d.ts +22 -0
- package/build/components/Openfort/types.js +1 -0
- package/build/components/Openfort/types.js.map +1 -1
- package/build/components/Pages/AssetInventory/SolanaAssetInventory.js +7 -7
- package/build/components/Pages/Buy/styles.js +10 -10
- package/build/components/Pages/Connected/EthereumConnected.js +7 -1
- package/build/components/Pages/Connected/EthereumConnected.js.map +1 -1
- package/build/components/Pages/Deposit/TestnetNotice.js +15 -3
- package/build/components/Pages/Deposit/TestnetNotice.js.map +1 -1
- package/build/components/Pages/Deposit/index.js +1 -2
- package/build/components/Pages/Deposit/index.js.map +1 -1
- package/build/components/Pages/Deposit/sources.d.ts +3 -0
- package/build/components/Pages/Deposit/sources.js +4 -1
- package/build/components/Pages/Deposit/sources.js.map +1 -1
- package/build/components/Pages/Deposit/useFundingTarget.d.ts +6 -4
- package/build/components/Pages/Deposit/useFundingTarget.js +18 -7
- package/build/components/Pages/Deposit/useFundingTarget.js.map +1 -1
- package/build/components/Pages/DepositCex/index.js +2 -1
- package/build/components/Pages/DepositCex/index.js.map +1 -1
- package/build/components/Pages/DepositWallet/index.js +15 -10
- package/build/components/Pages/DepositWallet/index.js.map +1 -1
- package/build/components/Pages/ExportKey/index.js +44 -4
- package/build/components/Pages/ExportKey/index.js.map +1 -1
- package/build/components/Pages/ExportKey/styles.d.ts +5 -0
- package/build/components/Pages/ExportKey/styles.js +47 -0
- package/build/components/Pages/ExportKey/styles.js.map +1 -0
- package/build/components/Pages/Receive/index.js +2 -2
- package/build/components/Pages/SelectToken/SolanaSelectToken.js +7 -7
- package/build/components/Pages/SelectToken/index.js +7 -3
- package/build/components/Pages/SelectToken/index.js.map +1 -1
- package/build/components/Pages/Send/EthereumSend.js +32 -6
- package/build/components/Pages/Send/EthereumSend.js.map +1 -1
- package/build/components/Pages/Send/SolanaSend.js +29 -5
- package/build/components/Pages/Send/SolanaSend.js.map +1 -1
- package/build/components/Pages/Send/styles.d.ts +17 -12
- package/build/components/Pages/Send/styles.js +104 -60
- package/build/components/Pages/Send/styles.js.map +1 -1
- package/build/components/Pages/SendConfirmation/ConfirmationSummary.d.ts +29 -0
- package/build/components/Pages/SendConfirmation/ConfirmationSummary.js +15 -0
- package/build/components/Pages/SendConfirmation/ConfirmationSummary.js.map +1 -0
- package/build/components/Pages/SendConfirmation/EstimatedFees.d.ts +3 -1
- package/build/components/Pages/SendConfirmation/EstimatedFees.js +22 -15
- package/build/components/Pages/SendConfirmation/EstimatedFees.js.map +1 -1
- package/build/components/Pages/SendConfirmation/SolanaSendConfirmation.js +18 -6
- package/build/components/Pages/SendConfirmation/SolanaSendConfirmation.js.map +1 -1
- package/build/components/Pages/SendConfirmation/index.js +23 -33
- package/build/components/Pages/SendConfirmation/index.js.map +1 -1
- package/build/components/Pages/SendConfirmation/styles.d.ts +9 -1
- package/build/components/Pages/SendConfirmation/styles.js +65 -19
- package/build/components/Pages/SendConfirmation/styles.js.map +1 -1
- package/build/components/Pages/SignMessage/index.d.ts +2 -0
- package/build/components/Pages/SignMessage/index.js +106 -0
- package/build/components/Pages/SignMessage/index.js.map +1 -0
- package/build/components/Pages/SignMessage/styles.d.ts +13 -0
- package/build/components/Pages/SignMessage/styles.js +99 -0
- package/build/components/Pages/SignMessage/styles.js.map +1 -0
- package/build/hooks/openfort/useSignMessage.d.ts +27 -0
- package/build/hooks/openfort/useSignMessage.js +52 -0
- package/build/hooks/openfort/useSignMessage.js.map +1 -0
- package/build/hooks/openfort/useUI.d.ts +6 -1
- package/build/hooks/openfort/useUI.js +15 -3
- package/build/hooks/openfort/useUI.js.map +1 -1
- package/build/index.d.ts +2 -1
- package/build/index.js +1 -0
- package/build/index.js.map +1 -1
- package/build/localizations/locales/en-US.js +1 -1
- package/build/solana/transfer.d.ts +12 -0
- package/build/solana/transfer.js +29 -1
- package/build/solana/transfer.js.map +1 -1
- package/build/utils/rpc.d.ts +6 -0
- package/build/utils/rpc.js +12 -1
- package/build/utils/rpc.js.map +1 -1
- package/build/version.d.ts +1 -1
- package/build/version.js +1 -1
- package/build/wagmi/components/ChainSelect/index.js +1 -93
- package/build/wagmi/components/ChainSelect/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,23 +1,34 @@
|
|
|
1
1
|
import { ChainTypeEnum } from '@openfort/openfort-js';
|
|
2
|
+
import { useEthereumEmbeddedWallet } from '../../../ethereum/hooks/useEthereumEmbeddedWallet.js';
|
|
2
3
|
import { useOpenfortCore } from '../../../openfort/useOpenfort.js';
|
|
3
4
|
import { useOpenfort } from '../../Openfort/useOpenfort.js';
|
|
4
|
-
import { DEST_CHAIN_SOL, DEST_CHAIN, DEST_USDC_SOL,
|
|
5
|
+
import { DEST_CHAIN_SOL, DEST_CHAIN, DEST_USDC, DEST_USDC_SOL, NATIVE_TOKEN_ADDRESS } from './sources.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* The destination route Deposit-hub funding settles into. Integrators override the
|
|
8
|
-
* chain and currency via `uiConfig.funding.{targetChain,targetCurrency}
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* chain and currency via `uiConfig.funding.{targetChain,targetCurrency}`. With no
|
|
10
|
+
* override the destination follows the wallet's ACTIVE chain — so a testnet wallet
|
|
11
|
+
* funds on its own network instead of being told "funding isn't available on Base".
|
|
12
|
+
* Currency defaults to USDC where we ship its address (Base, Solana mainnet) and to
|
|
13
|
+
* the native asset otherwise, so the destination currency is always valid on-chain.
|
|
14
|
+
* The deposit recipient is always the active embedded wallet — callers resolve it.
|
|
12
15
|
*/
|
|
13
16
|
function useFundingTarget() {
|
|
14
17
|
var _a, _b, _c, _d;
|
|
15
18
|
const { uiConfig } = useOpenfort();
|
|
16
19
|
const { chainType } = useOpenfortCore();
|
|
20
|
+
const ethereumWallet = useEthereumEmbeddedWallet();
|
|
17
21
|
const isSolana = chainType === ChainTypeEnum.SVM;
|
|
22
|
+
const activeChain = isSolana
|
|
23
|
+
? DEST_CHAIN_SOL
|
|
24
|
+
: ethereumWallet.status === 'connected'
|
|
25
|
+
? `eip155:${ethereumWallet.chainId}`
|
|
26
|
+
: DEST_CHAIN;
|
|
27
|
+
const chain = (_b = (_a = uiConfig.funding) === null || _a === void 0 ? void 0 : _a.targetChain) !== null && _b !== void 0 ? _b : activeChain;
|
|
28
|
+
const defaultCurrency = chain === DEST_CHAIN ? DEST_USDC : chain === DEST_CHAIN_SOL ? DEST_USDC_SOL : NATIVE_TOKEN_ADDRESS;
|
|
18
29
|
return {
|
|
19
|
-
chain
|
|
20
|
-
currency: (_d = (_c = uiConfig.funding) === null || _c === void 0 ? void 0 : _c.targetCurrency) !== null && _d !== void 0 ? _d :
|
|
30
|
+
chain,
|
|
31
|
+
currency: (_d = (_c = uiConfig.funding) === null || _c === void 0 ? void 0 : _c.targetCurrency) !== null && _d !== void 0 ? _d : defaultCurrency,
|
|
21
32
|
};
|
|
22
33
|
}
|
|
23
34
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFundingTarget.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useFundingTarget.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -21,6 +21,7 @@ import { DepositStatus } from '../Deposit/DepositStatus.js';
|
|
|
21
21
|
import { walletListBtn } from '../Deposit/formStyles.js';
|
|
22
22
|
import { isSolana, DEST_USDC } from '../Deposit/sources.js';
|
|
23
23
|
import { StepDivider, ButtonLogo } from '../Deposit/styles.js';
|
|
24
|
+
import { TestnetNotice } from '../Deposit/TestnetNotice.js';
|
|
24
25
|
import { useFundingTarget } from '../Deposit/useFundingTarget.js';
|
|
25
26
|
import { sanitizeForParsing, sanitizeAmountInput } from '../Send/utils.js';
|
|
26
27
|
|
|
@@ -213,7 +214,7 @@ const DepositCex = () => {
|
|
|
213
214
|
// success / refunded / expired screen (shared with the crypto rail).
|
|
214
215
|
if (isDepositFlowActive(status))
|
|
215
216
|
return jsx(DepositProgress, { status: status });
|
|
216
|
-
return (jsxs(PageContent, { onBack: routes.DEPOSIT, children: [jsx(ModalHeading, { children: "Transfer from Exchange" }), jsxs(Section, { children: [jsx(SectionLabel, { children: "Amount" }), jsxs(AmountCard, { children: [jsx(CurrencySymbol, { children: "$" }), jsx(AmountInput, { value: amount, onChange: handleAmountChange, onBlur: handleAmountBlur, placeholder: "0.00", inputMode: "decimal", autoComplete: "off" })] }), jsx(PresetList, { children: PRESETS.map((preset) => (jsxs(PresetButton, { type: "button", "$active": pressedPreset === preset, onClick: () => handlePreset(preset), children: ["$", preset] }, preset))) }), amountTooLow ? (jsxs("span", { style: errorHelper, children: ["Enter at least $", MIN_AMOUNT, ".00 \u2014 the Coinbase minimum."] })) : (jsxs("span", { style: helperText, children: ["Minimum $", MIN_AMOUNT, ".00"] })), chainSupported && (jsxs("span", { style: destinationRow, children: [destAssetLogo && jsx("img", { src: destAssetLogo, alt: "", style: destinationLogo, onError: hideBrokenLogo }), destChainLogo && jsx("img", { src: destChainLogo, alt: "", style: destinationLogo, onError: hideBrokenLogo })] }))] }), !isAvailable && jsx(ModalBody, { children: "Funding isn't available right now." }), !testnet && isAvailable && !chainSupported && (jsxs(ModalBody, { children: ["Coinbase can't deliver to ", destChainName, " yet."] })), !testnet && error && jsx(ModalBody, { style: { color: '#dc2626' }, children: error.message }), jsx(StepDivider, { children: "Then open an exchange" }), jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: 8, marginTop: 12 }, children: EXCHANGES.map((ex) => ex.comingSoon ? (jsxs("button", { type: "button", disabled: true, style: {
|
|
217
|
+
return (jsxs(PageContent, { onBack: routes.DEPOSIT, children: [jsx(ModalHeading, { children: "Transfer from Exchange" }), jsx(TestnetNotice, {}), jsxs(Section, { children: [jsx(SectionLabel, { children: "Amount" }), jsxs(AmountCard, { children: [jsx(CurrencySymbol, { children: "$" }), jsx(AmountInput, { value: amount, onChange: handleAmountChange, onBlur: handleAmountBlur, placeholder: "0.00", inputMode: "decimal", autoComplete: "off" })] }), jsx(PresetList, { children: PRESETS.map((preset) => (jsxs(PresetButton, { type: "button", "$active": pressedPreset === preset, onClick: () => handlePreset(preset), children: ["$", preset] }, preset))) }), amountTooLow ? (jsxs("span", { style: errorHelper, children: ["Enter at least $", MIN_AMOUNT, ".00 \u2014 the Coinbase minimum."] })) : (jsxs("span", { style: helperText, children: ["Minimum $", MIN_AMOUNT, ".00"] })), chainSupported && (jsxs("span", { style: destinationRow, children: [destAssetLogo && jsx("img", { src: destAssetLogo, alt: "", style: destinationLogo, onError: hideBrokenLogo }), destChainLogo && jsx("img", { src: destChainLogo, alt: "", style: destinationLogo, onError: hideBrokenLogo })] }))] }), !isAvailable && jsx(ModalBody, { children: "Funding isn't available right now." }), !testnet && isAvailable && !chainSupported && (jsxs(ModalBody, { children: ["Coinbase can't deliver to ", destChainName, " yet."] })), !testnet && error && jsx(ModalBody, { style: { color: '#dc2626' }, children: error.message }), jsx(StepDivider, { children: "Then open an exchange" }), jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: 8, marginTop: 12 }, children: EXCHANGES.map((ex) => ex.comingSoon ? (jsxs("button", { type: "button", disabled: true, style: {
|
|
217
218
|
...walletListBtn,
|
|
218
219
|
display: 'flex',
|
|
219
220
|
alignItems: 'center',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -6,6 +6,7 @@ import { useEthereumBridge } from '../../../ethereum/OpenfortEthereumBridgeConte
|
|
|
6
6
|
import useIsMobile from '../../../hooks/useIsMobile.js';
|
|
7
7
|
import styled from '../../../styles/styled/index.js';
|
|
8
8
|
import { isIOS } from '../../../utils/index.js';
|
|
9
|
+
import { TextLinkButton } from '../../Common/Button/styles.js';
|
|
9
10
|
import { ModalHeading, ModalBody } from '../../Common/Modal/styles.js';
|
|
10
11
|
import { ScrollArea } from '../../Common/ScrollArea/index.js';
|
|
11
12
|
import { routes } from '../../Openfort/types.js';
|
|
@@ -83,6 +84,8 @@ const DepositWallet = () => {
|
|
|
83
84
|
// (the funding deposit-address mint uses a fixed nominal amount regardless).
|
|
84
85
|
const [amount, setAmount] = useState('1');
|
|
85
86
|
const [pressedPreset, setPressedPreset] = useState(null);
|
|
87
|
+
// Collapse the wallet list to keep the picker short on mobile; "Show more" reveals the rest.
|
|
88
|
+
const [showAllWallets, setShowAllWallets] = useState(false);
|
|
86
89
|
const depositPageUrl = (_b = (_a = uiConfig.funding) === null || _a === void 0 ? void 0 : _a.depositPageUrl) !== null && _b !== void 0 ? _b : OPENFORT_DEPOSIT_PAGE_URL;
|
|
87
90
|
// Solana sources have no numeric chain id and no desktop EVM-extension send, so
|
|
88
91
|
// they route through the deeplink (Phantom) on every platform instead of the
|
|
@@ -125,20 +128,22 @@ const DepositWallet = () => {
|
|
|
125
128
|
// Trust's in-app dApp browser was removed on iOS (Apple, 2021) — the link
|
|
126
129
|
// dead-ends there, so hide it on iOS while keeping it on Android.
|
|
127
130
|
const deeplinks = isIOS() ? allDeeplinks.filter((d) => d.app !== 'trust') : allDeeplinks;
|
|
131
|
+
const WALLET_LIMIT = 3;
|
|
132
|
+
const visibleDeeplinks = showAllWallets ? deeplinks : deeplinks.slice(0, WALLET_LIMIT);
|
|
128
133
|
useEffect(() => {
|
|
129
134
|
triggerResize();
|
|
130
|
-
}, [route.receiverAddress, route.loading, route.status, deeplinks.length, triggerResize]);
|
|
135
|
+
}, [route.receiverAddress, route.loading, route.status, deeplinks.length, showAllWallets, triggerResize]);
|
|
131
136
|
if (isDepositFlowActive(route.status))
|
|
132
137
|
return jsx(DepositProgress, { status: route.status });
|
|
133
|
-
return (jsxs(PageContent, { onBack: routes.DEPOSIT, children: [jsx(ModalHeading, { children: "Transfer from wallet" }), jsx(TestnetNotice, {}), route.targetUnsupported && (jsx(UnsupportedNetworkNotice, { targetChain: route.target.chain, railChains: route.railChains })), !route.targetUnsupported && route.accountUnusableOnTarget && (jsx(AccountChainNotice, { targetChain: route.target.chain })), !route.targetUnsupported && !route.accountUnusableOnTarget && (jsxs(Layout, { children: [jsxs(TopFixed, { children: [jsx(RouteSelectors, { chains: route.chains, chain: route.chain, currency: route.currency, chainLabel: "Supported chain", onChainChange: route.setChain, onCurrencyChange: route.setCurrency }), !route.isAvailable && jsx(ModalBody, { children: "Funding isn't available right now." }), jsxs(Section, { children: [jsx(SectionLabel, { children: "Amount" }), jsxs(AmountCard, { children: [jsx(CurrencySymbol, { children: (_m = (_l = route.activeCurrency) === null || _l === void 0 ? void 0 : _l.symbol) !== null && _m !== void 0 ? _m : '' }), jsx(AmountInput, { value: amount, onChange: handleAmountChange, placeholder: "0.00", inputMode: "decimal", autoComplete: "off" })] }), jsx(PresetList, { children: PRESETS.map((preset) => (jsx(PresetButton, { type: "button", "$active": pressedPreset === preset, onClick: () => handlePreset(preset), children: preset }, preset))) })] }), jsx(StepDivider, { children: "Then select the wallet you want to use" })] }), jsx(ProvidersRegion, { children: isMobile || isSolanaSrc || !bridge ? (jsxs(Fragment, { children: [!depositPageUrl && (jsx(ModalBody, { style: { marginTop: 12 }, children: "Use a deposit address below to fund from your wallet." })), route.loading && !route.pm && (jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 }, children: [jsx(Skeleton, { "$h": "44px", "$r": "10px" }), jsx(Skeleton, { "$h": "44px", "$r": "10px" }), jsx(Skeleton, { "$h": "44px", "$r": "10px" })] })), deeplinks.length > 0 && (jsx(ScrollArea, { fill: true, children:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
return (jsxs(PageContent, { onBack: routes.DEPOSIT, children: [jsx(ModalHeading, { children: "Transfer from wallet" }), jsx(TestnetNotice, {}), route.targetUnsupported && (jsx(UnsupportedNetworkNotice, { targetChain: route.target.chain, railChains: route.railChains })), !route.targetUnsupported && route.accountUnusableOnTarget && (jsx(AccountChainNotice, { targetChain: route.target.chain })), !route.targetUnsupported && !route.accountUnusableOnTarget && (jsxs(Layout, { children: [jsxs(TopFixed, { children: [jsx(RouteSelectors, { chains: route.chains, chain: route.chain, currency: route.currency, chainLabel: "Supported chain", onChainChange: route.setChain, onCurrencyChange: route.setCurrency }), !route.isAvailable && jsx(ModalBody, { children: "Funding isn't available right now." }), jsxs(Section, { children: [jsx(SectionLabel, { children: "Amount" }), jsxs(AmountCard, { children: [jsx(CurrencySymbol, { children: (_m = (_l = route.activeCurrency) === null || _l === void 0 ? void 0 : _l.symbol) !== null && _m !== void 0 ? _m : '' }), jsx(AmountInput, { value: amount, onChange: handleAmountChange, placeholder: "0.00", inputMode: "decimal", autoComplete: "off" })] }), jsx(PresetList, { children: PRESETS.map((preset) => (jsx(PresetButton, { type: "button", "$active": pressedPreset === preset, onClick: () => handlePreset(preset), children: preset }, preset))) })] }), jsx(StepDivider, { children: "Then select the wallet you want to use" })] }), jsx(ProvidersRegion, { children: isMobile || isSolanaSrc || !bridge ? (jsxs(Fragment, { children: [!depositPageUrl && (jsx(ModalBody, { style: { marginTop: 12 }, children: "Use a deposit address below to fund from your wallet." })), route.loading && !route.pm && (jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 }, children: [jsx(Skeleton, { "$h": "44px", "$r": "10px" }), jsx(Skeleton, { "$h": "44px", "$r": "10px" }), jsx(Skeleton, { "$h": "44px", "$r": "10px" })] })), deeplinks.length > 0 && (jsx(ScrollArea, { fill: true, children: jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8 }, children: [visibleDeeplinks.map((d) => (jsxs("a", { href: amountValid ? d.url : undefined, "aria-disabled": !amountValid, target: "_blank", rel: "noreferrer", style: {
|
|
139
|
+
...walletListBtn,
|
|
140
|
+
display: 'flex',
|
|
141
|
+
alignItems: 'center',
|
|
142
|
+
justifyContent: 'center',
|
|
143
|
+
gap: 8,
|
|
144
|
+
opacity: amountValid ? 1 : 0.55,
|
|
145
|
+
pointerEvents: amountValid ? 'auto' : 'none',
|
|
146
|
+
}, children: [WALLET_LOGO[d.app] && jsx(ButtonLogo, { children: WALLET_LOGO[d.app] }), d.label, " \u2197"] }, d.app))), deeplinks.length > WALLET_LIMIT && (jsx(TextLinkButton, { type: "button", onClick: () => setShowAllWallets((v) => !v), style: { alignSelf: 'center', marginTop: 2 }, children: showAllWallets ? 'Show less' : `Show ${deeplinks.length - WALLET_LIMIT} more` }))] }) }))] })) : (jsx(DepositWalletDesktop, { receiverAddress: route.receiverAddress, activeChain: route.activeChain, activeCurrency: route.activeCurrency, loading: route.loading, amount: amount })) }), jsxs(FixedFooter, { children: [jsx(AddressPageLink, { label: "Or send to a deposit address" }), route.error && jsx(ModalBody, { style: { color: '#dc2626', marginTop: 12 }, children: route.error.message })] })] }))] }));
|
|
142
147
|
};
|
|
143
148
|
|
|
144
149
|
export { DepositWallet as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { useState, useEffect } from 'react';
|
|
2
|
+
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
3
3
|
import { KeyIcon } from '../../../assets/icons.js';
|
|
4
4
|
import { useEthereumEmbeddedWallet } from '../../../ethereum/hooks/useEthereumEmbeddedWallet.js';
|
|
5
|
-
import
|
|
6
|
-
import { CopyText } from '../../Common/CopyToClipboard/CopyText.js';
|
|
5
|
+
import { CopyIconButton } from '../../Common/CopyToClipboard/CopyIconButton.js';
|
|
7
6
|
import { ModalHeading, ModalContent, ModalBody } from '../../Common/Modal/styles.js';
|
|
8
7
|
import { FloatingGraphic } from '../../FloatingGraphic/index.js';
|
|
9
8
|
import { PageContent } from '../../PageContent/index.js';
|
|
9
|
+
import { Label, AddressRow, AddressField } from '../Receive/styles.js';
|
|
10
|
+
import { HoldButton, HoldFill, HoldLabel, KeyReveal } from './styles.js';
|
|
10
11
|
|
|
11
12
|
// TODO: Localize
|
|
13
|
+
const HOLD_MS = 5000;
|
|
12
14
|
const ExportKey = () => {
|
|
13
15
|
var _a, _b;
|
|
14
16
|
const wallet = useEthereumEmbeddedWallet();
|
|
@@ -22,6 +24,42 @@ const ExportKey = () => {
|
|
|
22
24
|
const [exportedKey, setExportedKey] = useState(null);
|
|
23
25
|
const [exportError, setExportError] = useState(null);
|
|
24
26
|
const [showExportedKey, setShowExportedKey] = useState(false);
|
|
27
|
+
// Press-and-hold gate: the key only reveals after a deliberate 5s hold.
|
|
28
|
+
const [progress, setProgress] = useState(0);
|
|
29
|
+
const holdingRef = useRef(false);
|
|
30
|
+
const rafRef = useRef(null);
|
|
31
|
+
const startRef = useRef(0);
|
|
32
|
+
const stopHold = useCallback(() => {
|
|
33
|
+
holdingRef.current = false;
|
|
34
|
+
if (rafRef.current !== null) {
|
|
35
|
+
cancelAnimationFrame(rafRef.current);
|
|
36
|
+
rafRef.current = null;
|
|
37
|
+
}
|
|
38
|
+
setProgress((p) => (p >= 1 ? p : 0));
|
|
39
|
+
}, []);
|
|
40
|
+
const startHold = useCallback(() => {
|
|
41
|
+
if (showExportedKey || holdingRef.current)
|
|
42
|
+
return;
|
|
43
|
+
holdingRef.current = true;
|
|
44
|
+
startRef.current = performance.now();
|
|
45
|
+
const tick = (now) => {
|
|
46
|
+
if (!holdingRef.current)
|
|
47
|
+
return;
|
|
48
|
+
const p = Math.min(1, (now - startRef.current) / HOLD_MS);
|
|
49
|
+
setProgress(p);
|
|
50
|
+
if (p >= 1) {
|
|
51
|
+
holdingRef.current = false;
|
|
52
|
+
setShowExportedKey(true);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
rafRef.current = requestAnimationFrame(tick);
|
|
56
|
+
};
|
|
57
|
+
rafRef.current = requestAnimationFrame(tick);
|
|
58
|
+
}, [showExportedKey]);
|
|
59
|
+
useEffect(() => () => {
|
|
60
|
+
if (rafRef.current !== null)
|
|
61
|
+
cancelAnimationFrame(rafRef.current);
|
|
62
|
+
}, []);
|
|
25
63
|
useEffect(() => {
|
|
26
64
|
const asyncExportKey = async () => {
|
|
27
65
|
try {
|
|
@@ -45,7 +83,9 @@ const ExportKey = () => {
|
|
|
45
83
|
logo: jsx(KeyIcon, {}),
|
|
46
84
|
}, logoBottomLeft: {
|
|
47
85
|
logo: jsx(KeyIcon, {}),
|
|
48
|
-
} }), jsxs(ModalContent, { children: [jsxs(ModalBody, { children: [isSmartAccount ? (jsxs("p", { style: { marginBottom: 6 }, children: ["This is your account's ", jsx("strong", { children: "owner (signer) key" }), " \u2014 not the account itself. Your smart account", accountAddress ? ` (${accountAddress.slice(0, 6)}…${accountAddress.slice(-4)})` : '', " is a contract with no private key, so importing this key into another wallet shows the owner address,", ' ', jsx("strong", { children: "not your funds" }), ". To move funds, use Send to withdraw to another wallet."] })) : (jsx("p", { style: { marginBottom: 6 }, children: "With your private key, you can access your account outside this application." })), jsx("p", { children: "Keep it safe and never share it with anyone you don't trust." })] }), !showExportedKey ? (
|
|
86
|
+
} }), jsxs(ModalContent, { children: [jsxs(ModalBody, { children: [isSmartAccount ? (jsxs("p", { style: { marginBottom: 6 }, children: ["This is your account's ", jsx("strong", { children: "owner (signer) key" }), " \u2014 not the account itself. Your smart account", accountAddress ? ` (${accountAddress.slice(0, 6)}…${accountAddress.slice(-4)})` : '', " is a contract with no private key, so importing this key into another wallet shows the owner address,", ' ', jsx("strong", { children: "not your funds" }), ". To move funds, use Send to withdraw to another wallet."] })) : (jsx("p", { style: { marginBottom: 6 }, children: "With your private key, you can access your account outside this application." })), jsx("p", { children: "Keep it safe and never share it with anyone you don't trust." })] }), !showExportedKey ? (jsxs(HoldButton, { type: "button", onPointerDown: startHold, onPointerUp: stopHold, onPointerLeave: stopHold, onPointerCancel: stopHold, style: { marginTop: 12 }, children: [jsx(HoldFill, { style: { width: `${progress * 100}%` } }), jsx(HoldLabel, { children: progress > 0
|
|
87
|
+
? `Hold to reveal… ${Math.ceil((1 - progress) * (HOLD_MS / 1000))}s`
|
|
88
|
+
: 'Hold 5s to reveal key' })] })) : exportError ? (jsx(ModalBody, { style: { marginTop: 12 }, "$error": true, children: exportError })) : exportedKey ? (jsxs(KeyReveal, { children: [jsx(Label, { children: "Your private key" }), jsxs(AddressRow, { children: [jsx(AddressField, { style: { fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace' }, children: exportedKey }), jsx(CopyIconButton, { value: exportedKey })] })] })) : (jsx(Fragment, { children: "Loading..." }))] })] }));
|
|
49
89
|
};
|
|
50
90
|
|
|
51
91
|
export { ExportKey as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Press-and-hold reveal button: a fill grows left→right over the hold duration. */
|
|
2
|
+
export declare const HoldButton: import("styled-components").StyledComponent<"button", any, {}, never>;
|
|
3
|
+
export declare const HoldFill: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
4
|
+
export declare const HoldLabel: import("styled-components").StyledComponent<"span", any, {}, never>;
|
|
5
|
+
export declare const KeyReveal: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import styled from '../../../styles/styled/index.js';
|
|
2
|
+
|
|
3
|
+
/** Press-and-hold reveal button: a fill grows left→right over the hold duration. */
|
|
4
|
+
const HoldButton = styled.button `
|
|
5
|
+
position: relative;
|
|
6
|
+
overflow: hidden;
|
|
7
|
+
width: 100%;
|
|
8
|
+
padding: 14px 16px;
|
|
9
|
+
border-radius: var(--ck-primary-button-border-radius, 16px);
|
|
10
|
+
border: 1px solid var(--ck-body-divider);
|
|
11
|
+
background: var(--ck-secondary-button-background);
|
|
12
|
+
color: var(--ck-body-color);
|
|
13
|
+
font-size: 16px;
|
|
14
|
+
font-weight: 600;
|
|
15
|
+
cursor: pointer;
|
|
16
|
+
user-select: none;
|
|
17
|
+
-webkit-user-select: none;
|
|
18
|
+
touch-action: none;
|
|
19
|
+
transition: border-color 150ms ease;
|
|
20
|
+
|
|
21
|
+
&:hover {
|
|
22
|
+
border-color: var(--ck-body-color-muted);
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
const HoldFill = styled.div `
|
|
26
|
+
position: absolute;
|
|
27
|
+
top: 0;
|
|
28
|
+
left: 0;
|
|
29
|
+
bottom: 0;
|
|
30
|
+
background: var(--ck-focus-color, #1a88f8);
|
|
31
|
+
opacity: 0.22;
|
|
32
|
+
pointer-events: none;
|
|
33
|
+
`;
|
|
34
|
+
const HoldLabel = styled.span `
|
|
35
|
+
position: relative;
|
|
36
|
+
z-index: 1;
|
|
37
|
+
`;
|
|
38
|
+
const KeyReveal = styled.div `
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
gap: 10px;
|
|
42
|
+
margin-top: 12px;
|
|
43
|
+
text-align: left;
|
|
44
|
+
`;
|
|
45
|
+
|
|
46
|
+
export { HoldButton, HoldFill, HoldLabel, KeyReveal };
|
|
47
|
+
//# sourceMappingURL=styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -8,7 +8,7 @@ import { useOpenfortCore } from '../../../openfort/useOpenfort.js';
|
|
|
8
8
|
import { useSolanaEmbeddedWallet } from '../../../solana/hooks/useSolanaEmbeddedWallet.js';
|
|
9
9
|
import { CopyIconButton } from '../../Common/CopyToClipboard/CopyIconButton.js';
|
|
10
10
|
import CustomQRCode from '../../Common/CustomQRCode/index.js';
|
|
11
|
-
import { ModalHeading
|
|
11
|
+
import { ModalHeading } from '../../Common/Modal/styles.js';
|
|
12
12
|
import { routes } from '../../Openfort/types.js';
|
|
13
13
|
import { useOpenfort } from '../../Openfort/useOpenfort.js';
|
|
14
14
|
import { PageContent } from '../../PageContent/index.js';
|
|
@@ -63,7 +63,7 @@ const Receive = () => {
|
|
|
63
63
|
const timer = setTimeout(() => context.triggerResize(), 100);
|
|
64
64
|
return () => clearTimeout(timer);
|
|
65
65
|
}, [address, context]);
|
|
66
|
-
return (jsx(PageContent, { onBack: isSolanaRoute ? routes.SOL_CONNECTED : routes.CONNECTED, children: jsxs(ReceiveContent, { children: [jsx(ModalHeading, { children: "Receive
|
|
66
|
+
return (jsx(PageContent, { onBack: isSolanaRoute ? routes.SOL_CONNECTED : routes.CONNECTED, children: jsxs(ReceiveContent, { children: [jsx(ModalHeading, { children: "Receive money" }), address && (jsx(QRWrapper, { children: jsx(CustomQRCode, { value: qrValue, image: jsx("div", { style: { padding: 10 }, children: renderLogo() }) }) })), jsxs(AddressSection, { children: [jsx(Label, { children: "Your wallet address" }), jsxs(AddressRow, { children: [jsx(AddressField, { children: address !== null && address !== void 0 ? address : '--' }), jsx(CopyIconButton, { value: address !== null && address !== void 0 ? address : '' })] })] }), networkLabel && jsxs(NetworkInfo, { children: ["Network: ", networkLabel] })] }) }));
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
export { Receive as default };
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useEffect
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
3
|
import { formatUnits } from 'viem';
|
|
4
|
-
import {
|
|
4
|
+
import { currencyLogoUrl } from '../../../constants/logos.js';
|
|
5
5
|
import { useSolanaWalletAssets } from '../../../solana/hooks/useSolanaWalletAssets.js';
|
|
6
6
|
import { ModalHeading } from '../../Common/Modal/styles.js';
|
|
7
7
|
import { routes } from '../../Openfort/types.js';
|
|
8
8
|
import { useOpenfort } from '../../Openfort/useOpenfort.js';
|
|
9
|
-
import {
|
|
9
|
+
import { AssetChainLogo } from '../Deposit/AssetChainLogo.js';
|
|
10
|
+
import { SelectTokenContent, EmptyState, TokenList, TokenButton, TokenLeftGroup, TokenInfo, TokenSymbol, TokenName, TokenBalance, TokenLogoArea } from './styles.js';
|
|
10
11
|
|
|
11
12
|
const ZERO = BigInt(0);
|
|
13
|
+
/** Token logo with the Solana chain badge, matching the EVM picker. */
|
|
12
14
|
function SolanaTokenLogo({ symbol }) {
|
|
13
|
-
var _a;
|
|
14
|
-
|
|
15
|
-
const url = (_a = TOKEN_LOGO[symbol.toUpperCase()]) !== null && _a !== void 0 ? _a : null;
|
|
16
|
-
return (jsx(TokenLogoArea, { children: url && !imgError ? (jsx(TokenLogoImg, { src: url, alt: symbol, onError: () => setImgError(true) })) : (jsx(TokenLogoFallback, { "$bg": symbolToColor(symbol), children: symbol.charAt(0).toUpperCase() })) }));
|
|
15
|
+
var _a, _b;
|
|
16
|
+
return (jsx(TokenLogoArea, { children: jsx(AssetChainLogo, { assetLogo: (_a = currencyLogoUrl(symbol)) !== null && _a !== void 0 ? _a : '', chainLogo: (_b = currencyLogoUrl('SOL')) !== null && _b !== void 0 ? _b : '', symbol: symbol }) }));
|
|
17
17
|
}
|
|
18
18
|
const SolanaSelectToken = () => {
|
|
19
19
|
const { setSendForm, setRoute, triggerResize } = useOpenfort();
|
|
@@ -2,6 +2,8 @@ import { jsxs, jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import { ChainTypeEnum } from '@openfort/openfort-js';
|
|
3
3
|
import { useState, useEffect } from 'react';
|
|
4
4
|
import { formatUnits } from 'viem';
|
|
5
|
+
import { currencyLogoUrl, chainLogoUrl } from '../../../constants/logos.js';
|
|
6
|
+
import { useEthereumEmbeddedWallet } from '../../../ethereum/hooks/useEthereumEmbeddedWallet.js';
|
|
5
7
|
import { useEthereumWalletAssets } from '../../../ethereum/hooks/useEthereumWalletAssets.js';
|
|
6
8
|
import { useOpenfortCore } from '../../../openfort/useOpenfort.js';
|
|
7
9
|
import { Arrow, ArrowChevron, TextLinkButton } from '../../Common/Button/styles.js';
|
|
@@ -10,8 +12,9 @@ import { routes } from '../../Openfort/types.js';
|
|
|
10
12
|
import { useOpenfort } from '../../Openfort/useOpenfort.js';
|
|
11
13
|
import { EVM_BUY_CURRENCIES } from '../Buy/evmCurrencies.js';
|
|
12
14
|
import { SOLANA_BUY_CURRENCIES } from '../Buy/solanaCurrencies.js';
|
|
15
|
+
import { AssetChainLogo } from '../Deposit/AssetChainLogo.js';
|
|
13
16
|
import { getAssetSymbol, getAssetDecimals, formatBalanceWithSymbol } from '../Send/utils.js';
|
|
14
|
-
import { SelectTokenContent, EmptyState, TokenList, TokenButton, TokenInfo, TokenSymbol, TokenName, TokenBalance } from './styles.js';
|
|
17
|
+
import { SelectTokenContent, EmptyState, TokenList, TokenButton, TokenLeftGroup, TokenLogoArea, TokenInfo, TokenSymbol, TokenName, TokenBalance } from './styles.js';
|
|
15
18
|
|
|
16
19
|
const ZERO = BigInt(0);
|
|
17
20
|
const usdFormatter = new Intl.NumberFormat('en-US', {
|
|
@@ -27,6 +30,7 @@ const SelectToken = ({ isBuyFlow }) => {
|
|
|
27
30
|
triggerResize();
|
|
28
31
|
}, [viewAllAssets]);
|
|
29
32
|
const { chainType } = useOpenfortCore();
|
|
33
|
+
const { chainId } = useEthereumEmbeddedWallet();
|
|
30
34
|
const { data: walletAssets, isLoading: isBalancesLoading } = useEthereumWalletAssets();
|
|
31
35
|
// Buys pick from a fixed buyable-currency list (USDC first, then native) per
|
|
32
36
|
// chain family, so the picker always has options even for a fresh wallet with no
|
|
@@ -68,7 +72,7 @@ const SelectToken = ({ isBuyFlow }) => {
|
|
|
68
72
|
return jsx(EmptyState, { children: "No supported tokens found for this network yet." });
|
|
69
73
|
}
|
|
70
74
|
return (jsxs(TokenList, { children: [selectableTokens.map((token) => {
|
|
71
|
-
var _a, _b, _c, _d, _e;
|
|
75
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
72
76
|
const key = token.type === 'erc20' ? token.address : 'native';
|
|
73
77
|
const displaySymbol = getAssetSymbol(token);
|
|
74
78
|
const displayName = ((_a = token.metadata) === null || _a === void 0 ? void 0 : _a.name) || displaySymbol || 'Unknown Token';
|
|
@@ -101,7 +105,7 @@ const SelectToken = ({ isBuyFlow }) => {
|
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
107
|
}
|
|
104
|
-
return (jsxs(TokenButton, { type: "button", onClick: () => handleSelect(token), style: { opacity: isDisabled ? 0.4 : 1, cursor: isDisabled ? 'not-allowed' : 'pointer' }, children: [jsxs(TokenInfo, { children: [jsx(TokenSymbol, { children: displayName }), isBuyFlow && jsx(TokenName, { children: displaySymbol })] }), isBuyFlow ? (jsx(Arrow, { width: "13", height: "12", viewBox: "0 0 13 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx(ArrowChevron, { stroke: "currentColor", d: "M7.51431 1.5L11.757 5.74264M7.5 10.4858L11.7426 6.24314" }) })) : (jsxs(TokenInfo, { children: [jsx(TokenBalance, { children: balanceDisplay }), usdValue ? jsx(TokenName, { style: { textAlign: 'end' }, children: usdValue }) : null] }))] }, key));
|
|
108
|
+
return (jsxs(TokenButton, { type: "button", onClick: () => handleSelect(token), style: { opacity: isDisabled ? 0.4 : 1, cursor: isDisabled ? 'not-allowed' : 'pointer' }, children: [jsxs(TokenLeftGroup, { children: [jsx(TokenLogoArea, { children: jsx(AssetChainLogo, { assetLogo: (_f = currencyLogoUrl(displaySymbol)) !== null && _f !== void 0 ? _f : '', chainLogo: (_g = chainLogoUrl(chainId)) !== null && _g !== void 0 ? _g : '', symbol: displaySymbol }) }), jsxs(TokenInfo, { children: [jsx(TokenSymbol, { children: displayName }), isBuyFlow && jsx(TokenName, { children: displaySymbol })] })] }), isBuyFlow ? (jsx(Arrow, { width: "13", height: "12", viewBox: "0 0 13 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx(ArrowChevron, { stroke: "currentColor", d: "M7.51431 1.5L11.757 5.74264M7.5 10.4858L11.7426 6.24314" }) })) : (jsxs(TokenInfo, { children: [jsx(TokenBalance, { children: balanceDisplay }), usdValue ? jsx(TokenName, { style: { textAlign: 'end' }, children: usdValue }) : null] }))] }, key));
|
|
105
109
|
}), !isBuyFlow && (jsx(TextLinkButton, { type: "button", onClick: () => {
|
|
106
110
|
setViewAllAssets(!viewAllAssets);
|
|
107
111
|
}, children: viewAllAssets ? 'View less assets' : 'View all assets' }))] }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useMemo } from 'react';
|
|
2
|
+
import { useEffect, useMemo } from 'react';
|
|
3
3
|
import { parseUnits, isAddress, formatUnits } from 'viem';
|
|
4
|
+
import { currencyLogoUrl, chainLogoUrl } from '../../../constants/logos.js';
|
|
5
|
+
import { useEthereumEmbeddedWallet } from '../../../ethereum/hooks/useEthereumEmbeddedWallet.js';
|
|
4
6
|
import { useEthereumWalletAssets } from '../../../ethereum/hooks/useEthereumWalletAssets.js';
|
|
5
7
|
import Button from '../../Common/Button/index.js';
|
|
6
8
|
import { Arrow, ArrowChevron } from '../../Common/Button/styles.js';
|
|
7
|
-
import Input from '../../Common/Input/index.js';
|
|
8
9
|
import { ModalHeading } from '../../Common/Modal/styles.js';
|
|
9
10
|
import { routes } from '../../Openfort/types.js';
|
|
10
11
|
import { useOpenfort } from '../../Openfort/useOpenfort.js';
|
|
11
12
|
import { PageContent } from '../../PageContent/index.js';
|
|
12
|
-
import {
|
|
13
|
+
import { AssetChainLogo } from '../Deposit/AssetChainLogo.js';
|
|
14
|
+
import { Form, SendCard, ToRow, CardLabel, RecipientInput, PasteButton, ErrorText, AmountRow, AmountField, TokenPill, PillLogo, AmountMeta, MetaText, BalanceMeta, UseMaxButton } from './styles.js';
|
|
13
15
|
import { isSameToken, sanitizeForParsing, formatBalance, sanitizeAmountInput } from './utils.js';
|
|
14
16
|
|
|
15
17
|
const EthereumSend = () => {
|
|
16
|
-
var _a, _b, _c, _d;
|
|
17
|
-
const { sendForm, setSendForm, setRoute } = useOpenfort();
|
|
18
|
+
var _a, _b, _c, _d, _e, _f;
|
|
19
|
+
const { sendForm, setSendForm, setRoute, triggerResize } = useOpenfort();
|
|
20
|
+
// Size the modal to the form on mount. Without this the screen isn't anchored
|
|
21
|
+
// and scrolls within the modal — every other Page triggers a resize on mount.
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
triggerResize();
|
|
24
|
+
}, [triggerResize]);
|
|
18
25
|
const { data: assets } = useEthereumWalletAssets();
|
|
26
|
+
const { chainId } = useEthereumEmbeddedWallet();
|
|
19
27
|
const matchedToken = useMemo(() => assets === null || assets === void 0 ? void 0 : assets.find((asset) => isSameToken(asset, sendForm.asset)), [assets, sendForm.asset]);
|
|
20
28
|
const selectedTokenOption = matchedToken !== null && matchedToken !== void 0 ? matchedToken : assets === null || assets === void 0 ? void 0 : assets[0];
|
|
21
29
|
const selectedToken = selectedTokenOption !== null && selectedTokenOption !== void 0 ? selectedTokenOption : sendForm.asset;
|
|
@@ -58,6 +66,16 @@ const EthereumSend = () => {
|
|
|
58
66
|
recipient: event.target.value,
|
|
59
67
|
}));
|
|
60
68
|
};
|
|
69
|
+
const handlePaste = async () => {
|
|
70
|
+
try {
|
|
71
|
+
const text = await navigator.clipboard.readText();
|
|
72
|
+
if (text)
|
|
73
|
+
setSendForm((prev) => ({ ...prev, recipient: text.trim() }));
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Clipboard unavailable or permission denied — leave the field as-is.
|
|
77
|
+
}
|
|
78
|
+
};
|
|
61
79
|
const handleAmountChange = (event) => {
|
|
62
80
|
const raw = sanitizeAmountInput(event.target.value);
|
|
63
81
|
if (raw === '' || /^[0-9]*\.?[0-9]*$/.test(raw)) {
|
|
@@ -81,7 +99,15 @@ const EthereumSend = () => {
|
|
|
81
99
|
};
|
|
82
100
|
const availableLabel = formatBalance(selectedBalanceValue, selectedDecimalsValue);
|
|
83
101
|
const maxDisabled = !selectedBalanceValue;
|
|
84
|
-
|
|
102
|
+
const fiatValue = useMemo(() => {
|
|
103
|
+
var _a, _b;
|
|
104
|
+
const perToken = (_b = (_a = selectedToken.metadata) === null || _a === void 0 ? void 0 : _a.fiat) === null || _b === void 0 ? void 0 : _b.value;
|
|
105
|
+
const n = Number(sanitizeForParsing(sendForm.amount));
|
|
106
|
+
if (!perToken || !Number.isFinite(n) || n <= 0)
|
|
107
|
+
return null;
|
|
108
|
+
return `$${(n * perToken).toFixed(2)}`;
|
|
109
|
+
}, [selectedToken.metadata, sendForm.amount]);
|
|
110
|
+
return (jsxs(PageContent, { onBack: routes.CONNECTED, children: [jsx(ModalHeading, { children: "Send money" }), jsxs(Form, { onSubmit: handleSubmit, children: [jsxs(SendCard, { children: [jsxs(ToRow, { children: [jsx(CardLabel, { children: "To" }), jsx(RecipientInput, { placeholder: "0x\u2026 or address", value: sendForm.recipient, onChange: handleRecipientChange, autoComplete: "off", spellCheck: false }), jsx(PasteButton, { type: "button", onClick: handlePaste, children: "Paste" })] }), sendForm.recipient && !recipientValid && jsx(ErrorText, { children: "Enter a valid wallet address." })] }), jsxs(SendCard, { children: [jsx(CardLabel, { children: "Amount" }), jsxs(AmountRow, { children: [jsx(AmountField, { placeholder: "0", value: sendForm.amount, onChange: handleAmountChange, inputMode: "decimal", autoComplete: "off" }), jsxs(TokenPill, { type: "button", onClick: handleOpenTokenSelector, children: [selectedSymbol && (jsx(PillLogo, { children: jsx(AssetChainLogo, { assetLogo: (_e = currencyLogoUrl(selectedSymbol)) !== null && _e !== void 0 ? _e : '', chainLogo: (_f = chainLogoUrl(chainId)) !== null && _f !== void 0 ? _f : '', symbol: selectedSymbol }) })), selectedSymbol || 'Select', jsx(Arrow, { width: "13", height: "12", viewBox: "0 0 13 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx(ArrowChevron, { stroke: "currentColor", d: "M7.51431 1.5L11.757 5.74264M7.5 10.4858L11.7426 6.24314", strokeWidth: "2", strokeLinecap: "round" }) })] })] }), jsxs(AmountMeta, { children: [jsx(MetaText, { style: { flex: 1, minWidth: 0 }, children: fiatValue !== null && fiatValue !== void 0 ? fiatValue : '' }), jsxs(BalanceMeta, { children: [jsx(MetaText, { children: availableLabel === '--' ? '--' : `${availableLabel} ${selectedSymbol}` }), jsx(UseMaxButton, { type: "button", onClick: handleMax, disabled: maxDisabled, children: "Use max" })] })] }), sendForm.amount && parsedAmount === null && jsx(ErrorText, { children: "Enter a valid amount." }), insufficientBalance && jsx(ErrorText, { children: "Insufficient balance for this transfer." })] }), jsx(Button, { variant: "primary", disabled: !canProceed, children: "Review transfer" })] })] }));
|
|
85
111
|
};
|
|
86
112
|
|
|
87
113
|
export { EthereumSend };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EthereumSend.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"EthereumSend.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useMemo } from 'react';
|
|
2
|
+
import { useEffect, useMemo } from 'react';
|
|
3
3
|
import { parseUnits, formatUnits } from 'viem';
|
|
4
|
+
import { currencyLogoUrl } from '../../../constants/logos.js';
|
|
4
5
|
import { useSolanaWalletAssets } from '../../../solana/hooks/useSolanaWalletAssets.js';
|
|
5
6
|
import Button from '../../Common/Button/index.js';
|
|
6
7
|
import { Arrow, ArrowChevron } from '../../Common/Button/styles.js';
|
|
7
|
-
import Input from '../../Common/Input/index.js';
|
|
8
8
|
import { ModalHeading } from '../../Common/Modal/styles.js';
|
|
9
9
|
import { routes } from '../../Openfort/types.js';
|
|
10
10
|
import { useOpenfort } from '../../Openfort/useOpenfort.js';
|
|
11
11
|
import { PageContent } from '../../PageContent/index.js';
|
|
12
|
-
import {
|
|
12
|
+
import { AssetChainLogo } from '../Deposit/AssetChainLogo.js';
|
|
13
|
+
import { Form, SendCard, ToRow, CardLabel, RecipientInput, PasteButton, ErrorText, AmountRow, AmountField, TokenPill, PillLogo, AmountMeta, MetaText, BalanceMeta, UseMaxButton } from './styles.js';
|
|
13
14
|
import { sanitizeForParsing, formatBalance, sanitizeAmountInput } from './utils.js';
|
|
14
15
|
|
|
15
16
|
const SOL_DECIMALS = 9;
|
|
@@ -26,8 +27,13 @@ function solAsset(balance) {
|
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
29
|
const SolanaSend = () => {
|
|
29
|
-
|
|
30
|
+
var _a, _b;
|
|
31
|
+
const { sendForm, setSendForm, setRoute, triggerResize } = useOpenfort();
|
|
30
32
|
const { data: assets } = useSolanaWalletAssets();
|
|
33
|
+
// Size the modal to the form on mount so it's anchored and doesn't scroll.
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
triggerResize();
|
|
36
|
+
}, [triggerResize]);
|
|
31
37
|
const asset = sendForm.asset;
|
|
32
38
|
const selected = asset.type === 'spl'
|
|
33
39
|
? { isSpl: true, mint: asset.address, decimals: asset.metadata.decimals, symbol: asset.metadata.symbol }
|
|
@@ -82,7 +88,25 @@ const SolanaSend = () => {
|
|
|
82
88
|
setSendForm((prev) => ({ ...prev, amount: formatUnits(balanceBase, selected.decimals) }));
|
|
83
89
|
};
|
|
84
90
|
const handleOpenTokenSelector = () => setRoute(routes.SOL_SEND_TOKEN_SELECT);
|
|
85
|
-
|
|
91
|
+
const handlePaste = async () => {
|
|
92
|
+
try {
|
|
93
|
+
const text = await navigator.clipboard.readText();
|
|
94
|
+
if (text)
|
|
95
|
+
setSendForm((prev) => ({ ...prev, recipient: text.trim() }));
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
// Clipboard unavailable or permission denied — leave the field as-is.
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
const fiatValue = useMemo(() => {
|
|
102
|
+
var _a, _b;
|
|
103
|
+
const perToken = (_b = (_a = asset.metadata) === null || _a === void 0 ? void 0 : _a.fiat) === null || _b === void 0 ? void 0 : _b.value;
|
|
104
|
+
const n = Number(sanitizeForParsing(sendForm.amount));
|
|
105
|
+
if (!perToken || !Number.isFinite(n) || n <= 0)
|
|
106
|
+
return null;
|
|
107
|
+
return `$${(n * perToken).toFixed(2)}`;
|
|
108
|
+
}, [asset.metadata, sendForm.amount]);
|
|
109
|
+
return (jsxs(PageContent, { onBack: routes.SOL_CONNECTED, children: [jsx(ModalHeading, { children: "Send money" }), jsxs(Form, { onSubmit: handleSubmit, children: [jsxs(SendCard, { children: [jsxs(ToRow, { children: [jsx(CardLabel, { children: "To" }), jsx(RecipientInput, { placeholder: "Solana address", value: sendForm.recipient, onChange: (e) => setSendForm((prev) => ({ ...prev, recipient: e.target.value })), autoComplete: "off", spellCheck: false }), jsx(PasteButton, { type: "button", onClick: handlePaste, children: "Paste" })] }), sendForm.recipient && !recipientValid && jsx(ErrorText, { children: "Enter a valid Solana address." })] }), jsxs(SendCard, { children: [jsx(CardLabel, { children: "Amount" }), jsxs(AmountRow, { children: [jsx(AmountField, { placeholder: "0", value: sendForm.amount, onChange: handleAmountChange, inputMode: "decimal", autoComplete: "off" }), jsxs(TokenPill, { type: "button", onClick: handleOpenTokenSelector, children: [selected.symbol && (jsx(PillLogo, { children: jsx(AssetChainLogo, { assetLogo: (_a = currencyLogoUrl(selected.symbol)) !== null && _a !== void 0 ? _a : '', chainLogo: (_b = currencyLogoUrl('SOL')) !== null && _b !== void 0 ? _b : '', symbol: selected.symbol }) })), selected.symbol, jsx(Arrow, { width: "13", height: "12", viewBox: "0 0 13 12", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx(ArrowChevron, { stroke: "currentColor", d: "M7.51431 1.5L11.757 5.74264M7.5 10.4858L11.7426 6.24314", strokeWidth: "2", strokeLinecap: "round" }) })] })] }), jsxs(AmountMeta, { children: [jsx(MetaText, { style: { flex: 1, minWidth: 0 }, children: fiatValue !== null && fiatValue !== void 0 ? fiatValue : '' }), jsxs(BalanceMeta, { children: [jsx(MetaText, { children: availableLabel === '--' ? '--' : `${availableLabel} ${selected.symbol}` }), jsx(UseMaxButton, { type: "button", onClick: handleMax, disabled: balanceBase === undefined, children: "Use max" })] })] }), sendForm.amount && parsedAmount === null && jsx(ErrorText, { children: "Enter a valid amount." }), insufficientBalance && jsxs(ErrorText, { children: ["Insufficient ", selected.symbol, " balance for this transfer."] })] }), jsx(Button, { variant: "primary", disabled: !canProceed, children: "Review transfer" })] })] }));
|
|
86
110
|
};
|
|
87
111
|
|
|
88
112
|
export { SolanaSend };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SolanaSend.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SolanaSend.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
export declare const Form: import("styled-components").StyledComponent<"form", any, {}, never>;
|
|
2
|
-
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const
|
|
5
|
-
|
|
6
|
-
export declare const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export declare const
|
|
11
|
-
export declare const
|
|
12
|
-
export declare const
|
|
13
|
-
export declare const
|
|
2
|
+
/** Rounded container shared by the "To" and "Amount" boxes. */
|
|
3
|
+
export declare const SendCard: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
4
|
+
export declare const CardLabel: import("styled-components").StyledComponent<"span", any, {}, never>;
|
|
5
|
+
/** "To" box: inline label, recipient input, and a Paste button. */
|
|
6
|
+
export declare const ToRow: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
7
|
+
export declare const RecipientInput: import("styled-components").StyledComponent<"input", any, {}, never>;
|
|
8
|
+
export declare const PasteButton: import("styled-components").StyledComponent<"button", any, {}, never>;
|
|
9
|
+
/** "Amount" box: large amount input with an inline token selector. */
|
|
10
|
+
export declare const AmountRow: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
11
|
+
export declare const AmountField: import("styled-components").StyledComponent<"input", any, {}, never>;
|
|
12
|
+
export declare const PillLogo: import("styled-components").StyledComponent<"span", any, {}, never>;
|
|
13
|
+
export declare const TokenPill: import("styled-components").StyledComponent<"button", any, {}, never>;
|
|
14
|
+
/** Bottom row of the amount box: fiat value (left), balance + Use max (right). */
|
|
15
|
+
export declare const AmountMeta: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
16
|
+
export declare const MetaText: import("styled-components").StyledComponent<"span", any, {}, never>;
|
|
17
|
+
export declare const BalanceMeta: import("styled-components").StyledComponent<"span", any, {}, never>;
|
|
18
|
+
export declare const UseMaxButton: import("styled-components").StyledComponent<"button", any, {}, never>;
|
|
14
19
|
export declare const ErrorText: import("styled-components").StyledComponent<"span", any, {}, never>;
|