@openfort/react 1.0.0 → 1.0.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/assets/icons.js +1 -1
- package/build/components/ConnectModal/index.js +3 -6
- package/build/components/ConnectModal/index.js.map +1 -1
- package/build/components/Pages/Send/index.js +1 -2
- package/build/components/Pages/Send/index.js.map +1 -1
- package/build/solana/hooks/utils.d.ts +0 -1
- package/build/solana/hooks/utils.js +2 -10
- package/build/solana/hooks/utils.js.map +1 -1
- package/build/version.d.ts +1 -1
- package/build/version.js +1 -1
- package/package.json +1 -1
- package/build/components/Pages/Send/SolanaSend.d.ts +0 -1
- package/build/components/Pages/Send/SolanaSend.js +0 -93
- package/build/components/Pages/Send/SolanaSend.js.map +0 -1
- package/build/components/Pages/SolanaSendConfirmation/index.d.ts +0 -1
- package/build/components/Pages/SolanaSendConfirmation/index.js +0 -152
- package/build/components/Pages/SolanaSendConfirmation/index.js.map +0 -1
- package/build/components/Pages/SolanaWallets/index.d.ts +0 -1
- package/build/components/Pages/SolanaWallets/index.js +0 -36
- package/build/components/Pages/SolanaWallets/index.js.map +0 -1
- package/build/shared/utils/validation.d.ts +0 -15
- package/build/shared/utils/validation.js +0 -27
- package/build/shared/utils/validation.js.map +0 -1
- package/build/solana/constants.d.ts +0 -21
- package/build/solana/constants.js +0 -24
- package/build/solana/constants.js.map +0 -1
- package/build/solana/utils/transfer.d.ts +0 -9
- package/build/solana/utils/transfer.js +0 -20
- package/build/solana/utils/transfer.js.map +0 -1
package/build/assets/icons.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
|
|
3
3
|
const SendIcon = ({ ...props }) => (jsxs("svg", { "aria-hidden": "true", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: [jsx("path", { d: "M5 19L19 5", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }), jsx("path", { d: "M9 5H19V15", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" })] }));
|
|
4
4
|
const ReceiveIcon = ({ ...props }) => (jsxs("svg", { "aria-hidden": "true", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: [jsx("path", { d: "M19 5L5 19", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }), jsx("path", { d: "M15 19H5V9", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" })] }));
|
|
@@ -44,11 +44,8 @@ import RemoveLinkedProvider from '../Pages/RemoveLinkedProvider/index.js';
|
|
|
44
44
|
import SelectToken from '../Pages/SelectToken/index.js';
|
|
45
45
|
import SelectWalletToRecover from '../Pages/SelectWalletToRecover/index.js';
|
|
46
46
|
import Send from '../Pages/Send/index.js';
|
|
47
|
-
import { SolanaSend } from '../Pages/Send/SolanaSend.js';
|
|
48
47
|
import SendConfirmation from '../Pages/SendConfirmation/index.js';
|
|
49
48
|
import SocialProviders from '../Pages/SocialProviders/index.js';
|
|
50
|
-
import SolanaSendConfirmation from '../Pages/SolanaSendConfirmation/index.js';
|
|
51
|
-
import SolanaWallets from '../Pages/SolanaWallets/index.js';
|
|
52
49
|
import ConnectUsing from './ConnectUsing.js';
|
|
53
50
|
import ConnectWithMobile from './ConnectWithMobile.js';
|
|
54
51
|
|
|
@@ -112,10 +109,10 @@ const CHAIN_PREFIXED_PAGES = {
|
|
|
112
109
|
'sol:connected': jsx(Connected, {}),
|
|
113
110
|
'sol:createWallet': jsx(CreateWallet, {}),
|
|
114
111
|
'sol:recoverWallet': jsx(RecoverPage, {}),
|
|
115
|
-
'sol:send':
|
|
116
|
-
'sol:sendConfirmation':
|
|
112
|
+
// 'sol:send': <SolanaSend />,
|
|
113
|
+
// 'sol:sendConfirmation': <SolanaSendConfirmation />,
|
|
117
114
|
'sol:receive': jsx(Receive, {}),
|
|
118
|
-
'sol:wallets':
|
|
115
|
+
// 'sol:wallets': <SolanaWallets />,
|
|
119
116
|
},
|
|
120
117
|
};
|
|
121
118
|
const DEFAULT_CONNECTED_ROUTE = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -2,11 +2,10 @@ import { jsx } from 'react/jsx-runtime';
|
|
|
2
2
|
import { ChainTypeEnum } from '@openfort/openfort-js';
|
|
3
3
|
import { useOpenfortCore } from '../../../openfort/useOpenfort.js';
|
|
4
4
|
import { EthereumSend } from './EthereumSend.js';
|
|
5
|
-
import { SolanaSend } from './SolanaSend.js';
|
|
6
5
|
|
|
7
6
|
const SEND_REGISTRY = {
|
|
8
7
|
[ChainTypeEnum.EVM]: EthereumSend,
|
|
9
|
-
[ChainTypeEnum.SVM]: SolanaSend,
|
|
8
|
+
// [ChainTypeEnum.SVM]: SolanaSend,
|
|
10
9
|
};
|
|
11
10
|
const Send = () => {
|
|
12
11
|
const { chainType } = useOpenfortCore();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;"}
|
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
function solToLamports(sol) {
|
|
4
|
-
// Use toFixed(9) to avoid scientific notation (e.g. 1e-9) for small values
|
|
5
|
-
const str = sol.toFixed(9);
|
|
6
|
-
const [whole = '0', frac = ''] = str.split('.');
|
|
7
|
-
const padded = frac.slice(0, 9);
|
|
8
|
-
return BigInt(whole) * LAMPORTS_PER_SOL + BigInt(padded);
|
|
9
|
-
}
|
|
1
|
+
const LAMPORTS_PER_SOL = BigInt(1000000000);
|
|
10
2
|
function formatSol(lamports, decimals = 4) {
|
|
11
3
|
const whole = lamports / LAMPORTS_PER_SOL;
|
|
12
4
|
const remainder = lamports % LAMPORTS_PER_SOL;
|
|
@@ -14,5 +6,5 @@ function formatSol(lamports, decimals = 4) {
|
|
|
14
6
|
return `${whole}.${fracStr}`.replace(new RegExp(`(\\d*\\.\\d{${decimals}})\\d*`), '$1');
|
|
15
7
|
}
|
|
16
8
|
|
|
17
|
-
export { formatSol
|
|
9
|
+
export { formatSol };
|
|
18
10
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
|
package/build/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const OPENFORT_VERSION = "1.0.
|
|
1
|
+
export declare const OPENFORT_VERSION = "1.0.1";
|
package/build/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function SolanaSend(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { useCallback } from 'react';
|
|
3
|
-
import { fetchSolanaBalance } from '../../../hooks/useBalance.js';
|
|
4
|
-
import { useAsyncData } from '../../../shared/hooks/useAsyncData.js';
|
|
5
|
-
import { isValidSolanaAddress } from '../../../shared/utils/validation.js';
|
|
6
|
-
import { BASE_FEE_LAMPORTS, RENT_EXEMPT_MINIMUM_LAMPORTS } from '../../../solana/constants.js';
|
|
7
|
-
import { useSolanaEmbeddedWallet } from '../../../solana/hooks/useSolanaEmbeddedWallet.js';
|
|
8
|
-
import { solToLamports, formatSol } from '../../../solana/hooks/utils.js';
|
|
9
|
-
import { useSolanaContext } from '../../../solana/SolanaContext.js';
|
|
10
|
-
import { logger } from '../../../utils/logger.js';
|
|
11
|
-
import Button from '../../Common/Button/index.js';
|
|
12
|
-
import Input from '../../Common/Input/index.js';
|
|
13
|
-
import { ModalHeading } from '../../Common/Modal/styles.js';
|
|
14
|
-
import { routes } from '../../Openfort/types.js';
|
|
15
|
-
import { useOpenfort } from '../../Openfort/useOpenfort.js';
|
|
16
|
-
import { PageContent } from '../../PageContent/index.js';
|
|
17
|
-
import { Form, Field, FieldLabel, AmountInputWrapper, MaxButton, HelperText, ErrorText } from './styles.js';
|
|
18
|
-
import { sanitizeForParsing, sanitizeAmountInput } from './utils.js';
|
|
19
|
-
|
|
20
|
-
const RENT_EXEMPT_LAMPORTS = RENT_EXEMPT_MINIMUM_LAMPORTS;
|
|
21
|
-
function SolanaSend() {
|
|
22
|
-
var _a, _b, _c;
|
|
23
|
-
const { rpcUrl } = useSolanaContext();
|
|
24
|
-
const { sendForm, setSendForm, setRoute } = useOpenfort();
|
|
25
|
-
const wallet = useSolanaEmbeddedWallet();
|
|
26
|
-
const recipient = sendForm.recipient;
|
|
27
|
-
const amount = sendForm.amount;
|
|
28
|
-
const walletAddress = wallet.status === 'connected' ? (_a = wallet.activeWallet) === null || _a === void 0 ? void 0 : _a.address : undefined;
|
|
29
|
-
const provider = wallet.status === 'connected' ? wallet.provider : null;
|
|
30
|
-
const balanceResult = useAsyncData({
|
|
31
|
-
queryKey: ['solana-balance', walletAddress, rpcUrl],
|
|
32
|
-
queryFn: async () => {
|
|
33
|
-
if (!walletAddress || !rpcUrl)
|
|
34
|
-
return null;
|
|
35
|
-
try {
|
|
36
|
-
const result = await fetchSolanaBalance(walletAddress, rpcUrl, 'confirmed');
|
|
37
|
-
return { value: result.value };
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
logger.error('Failed to fetch Solana balance:', error);
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
},
|
|
44
|
-
enabled: Boolean(walletAddress && rpcUrl),
|
|
45
|
-
});
|
|
46
|
-
const balanceLamports = (_c = (_b = balanceResult.data) === null || _b === void 0 ? void 0 : _b.value) !== null && _c !== void 0 ? _c : BigInt(0);
|
|
47
|
-
const recipientValid = recipient.length > 0 && isValidSolanaAddress(recipient);
|
|
48
|
-
const amountNum = amount === '' || amount === '.' ? null : parseFloat(amount);
|
|
49
|
-
const amountLamports = amountNum !== null && !Number.isNaN(amountNum) && amountNum > 0 ? solToLamports(amountNum) : null;
|
|
50
|
-
const insufficientBalance = amountLamports !== null && balanceLamports !== undefined ? amountLamports > balanceLamports : false;
|
|
51
|
-
const belowRentExempt = amountLamports !== null && balanceLamports !== undefined
|
|
52
|
-
? balanceLamports - amountLamports < RENT_EXEMPT_LAMPORTS
|
|
53
|
-
: false;
|
|
54
|
-
const hasAmount = amountLamports !== null && amountLamports > BigInt(0);
|
|
55
|
-
const amountValid = hasAmount && !insufficientBalance && !belowRentExempt;
|
|
56
|
-
const maxLamports = balanceLamports > BASE_FEE_LAMPORTS ? balanceLamports - BASE_FEE_LAMPORTS - RENT_EXEMPT_LAMPORTS : BigInt(0);
|
|
57
|
-
const maxLamportsSafe = maxLamports > BigInt(0) ? maxLamports : BigInt(0);
|
|
58
|
-
const canProceed = recipientValid && amountValid && !!provider;
|
|
59
|
-
const handleMax = useCallback(() => {
|
|
60
|
-
if (maxLamportsSafe <= BigInt(0))
|
|
61
|
-
return;
|
|
62
|
-
setSendForm((prev) => ({ ...prev, amount: formatSol(maxLamportsSafe, 9) }));
|
|
63
|
-
}, [maxLamportsSafe, setSendForm]);
|
|
64
|
-
const handleSubmit = (event) => {
|
|
65
|
-
event.preventDefault();
|
|
66
|
-
if (!canProceed || !amountLamports || amountLamports <= BigInt(0))
|
|
67
|
-
return;
|
|
68
|
-
const normalized = sanitizeForParsing(amount);
|
|
69
|
-
if (!normalized)
|
|
70
|
-
return;
|
|
71
|
-
setSendForm((prev) => ({
|
|
72
|
-
...prev,
|
|
73
|
-
amount: normalized,
|
|
74
|
-
recipient,
|
|
75
|
-
asset: prev.asset,
|
|
76
|
-
}));
|
|
77
|
-
setRoute(routes.SOL_SEND_CONFIRMATION);
|
|
78
|
-
};
|
|
79
|
-
const handleRecipientChange = (e) => {
|
|
80
|
-
setSendForm((prev) => ({ ...prev, recipient: e.target.value }));
|
|
81
|
-
};
|
|
82
|
-
const handleAmountChange = (e) => {
|
|
83
|
-
const raw = sanitizeAmountInput(e.target.value);
|
|
84
|
-
if (raw === '' || /^[0-9]*\.?[0-9]*$/.test(raw)) {
|
|
85
|
-
setSendForm((prev) => ({ ...prev, amount: raw }));
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
const availableLabel = balanceResult.data != null ? formatSol(balanceLamports) : '--';
|
|
89
|
-
return (jsxs(PageContent, { onBack: routes.SOL_CONNECTED, children: [jsx(ModalHeading, { children: "Send SOL" }), jsxs(Form, { onSubmit: handleSubmit, children: [jsxs(Field, { children: [jsx(FieldLabel, { children: "Amount" }), jsxs(AmountInputWrapper, { children: [jsx(Input, { placeholder: "0.00", value: amount, onChange: handleAmountChange, inputMode: "decimal", autoComplete: "off", style: { paddingRight: '86px' } }), jsx(MaxButton, { type: "button", onClick: handleMax, disabled: maxLamportsSafe <= BigInt(0), children: "Max" })] }), jsxs(HelperText, { children: ["Available: ", availableLabel, " SOL"] }), amount && amountNum !== null && Number.isNaN(amountNum) && jsx(ErrorText, { children: "Enter a valid amount." }), insufficientBalance && jsx(ErrorText, { children: "Insufficient balance for this transfer." }), belowRentExempt && jsx(ErrorText, { children: "Leave enough for rent-exempt minimum (~0.00089 SOL)." })] }), jsxs(Field, { children: [jsx(FieldLabel, { children: "Recipient address" }), jsx(Input, { placeholder: "Base58 address...", value: recipient, onChange: handleRecipientChange, autoComplete: "off" }), recipient && !recipientValid && jsx(ErrorText, { children: "Enter a valid Solana address." })] }), jsx(Button, { variant: "primary", disabled: !canProceed, type: "submit", children: "Review transfer" })] })] }));
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export { SolanaSend };
|
|
93
|
-
//# sourceMappingURL=SolanaSend.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SolanaSend.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default function SolanaSendConfirmation(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { ChainTypeEnum } from '@openfort/openfort-js';
|
|
3
|
-
import { createSolanaRpc, address, pipe, createTransactionMessage, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstruction, compileTransaction, getBase64EncodedWireTransaction, getBase58Encoder } from '@solana/kit';
|
|
4
|
-
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
5
|
-
import { TickIcon } from '../../../assets/icons.js';
|
|
6
|
-
import { OpenfortError, OpenfortReactErrorType } from '../../../types.js';
|
|
7
|
-
import { invalidateBalance } from '../../../hooks/useBalance.js';
|
|
8
|
-
import { getExplorerUrl } from '../../../shared/utils/explorer.js';
|
|
9
|
-
import { BASE_FEE_LAMPORTS } from '../../../solana/constants.js';
|
|
10
|
-
import { useSolanaEmbeddedWallet } from '../../../solana/hooks/useSolanaEmbeddedWallet.js';
|
|
11
|
-
import { solToLamports, formatSol } from '../../../solana/hooks/utils.js';
|
|
12
|
-
import { useSolanaContext } from '../../../solana/SolanaContext.js';
|
|
13
|
-
import { createTransferSolInstruction } from '../../../solana/utils/transfer.js';
|
|
14
|
-
import 'detect-browser';
|
|
15
|
-
import { truncateSolanaAddress } from '../../../utils/format.js';
|
|
16
|
-
import Button from '../../Common/Button/index.js';
|
|
17
|
-
import { CopyText } from '../../Common/CopyToClipboard/CopyText.js';
|
|
18
|
-
import Loader from '../../Common/Loading/index.js';
|
|
19
|
-
import { ModalHeading, ModalBody } from '../../Common/Modal/styles.js';
|
|
20
|
-
import { routes } from '../../Openfort/types.js';
|
|
21
|
-
import { useOpenfort } from '../../Openfort/useOpenfort.js';
|
|
22
|
-
import { PageContent } from '../../PageContent/index.js';
|
|
23
|
-
import { sanitizeForParsing } from '../Send/utils.js';
|
|
24
|
-
import { ButtonRow, SummaryList, SummaryItem, SummaryLabel, AmountValue, AddressValue, FeesValue, CheckIconWrapper, ErrorContainer, ErrorTitle, ErrorMessage } from '../SendConfirmation/styles.js';
|
|
25
|
-
|
|
26
|
-
const CONFIRM_POLL_MS = 500;
|
|
27
|
-
const CONFIRM_TIMEOUT_MS = 60000;
|
|
28
|
-
async function waitForConfirmation(rpcUrl, signature) {
|
|
29
|
-
var _a, _b;
|
|
30
|
-
const deadline = Date.now() + CONFIRM_TIMEOUT_MS;
|
|
31
|
-
while (Date.now() < deadline) {
|
|
32
|
-
const res = await fetch(rpcUrl, {
|
|
33
|
-
method: 'POST',
|
|
34
|
-
headers: { 'Content-Type': 'application/json' },
|
|
35
|
-
body: JSON.stringify({
|
|
36
|
-
jsonrpc: '2.0',
|
|
37
|
-
id: 1,
|
|
38
|
-
method: 'getSignatureStatuses',
|
|
39
|
-
params: [[signature], { searchTransactionHistory: true }],
|
|
40
|
-
}),
|
|
41
|
-
});
|
|
42
|
-
const data = await res.json();
|
|
43
|
-
const status = (_b = (_a = data.result) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b[0];
|
|
44
|
-
if (status === null || status === void 0 ? void 0 : status.err)
|
|
45
|
-
throw new Error(typeof status.err === 'object' ? JSON.stringify(status.err) : String(status.err));
|
|
46
|
-
if ((status === null || status === void 0 ? void 0 : status.confirmationStatus) === 'confirmed' || (status === null || status === void 0 ? void 0 : status.confirmationStatus) === 'finalized')
|
|
47
|
-
return;
|
|
48
|
-
await new Promise((r) => setTimeout(r, CONFIRM_POLL_MS));
|
|
49
|
-
}
|
|
50
|
-
throw new OpenfortError('Transaction confirmation timed out', OpenfortReactErrorType.UNEXPECTED_ERROR);
|
|
51
|
-
}
|
|
52
|
-
const ED25519_SIGNATURE_LENGTH = 64;
|
|
53
|
-
function decodeSignatureToBytes(signature) {
|
|
54
|
-
const encoded = getBase58Encoder().encode(signature);
|
|
55
|
-
let bytes = new Uint8Array(encoded);
|
|
56
|
-
if (bytes.length === ED25519_SIGNATURE_LENGTH + 1) {
|
|
57
|
-
bytes = bytes.slice(0, ED25519_SIGNATURE_LENGTH);
|
|
58
|
-
}
|
|
59
|
-
if (bytes.length === ED25519_SIGNATURE_LENGTH)
|
|
60
|
-
return bytes;
|
|
61
|
-
throw new OpenfortError(`Invalid signature: expected ${ED25519_SIGNATURE_LENGTH} bytes, got ${bytes.length}.`, OpenfortReactErrorType.CONFIGURATION_ERROR);
|
|
62
|
-
}
|
|
63
|
-
function SolanaSendConfirmation() {
|
|
64
|
-
var _a;
|
|
65
|
-
const { rpcUrl, cluster } = useSolanaContext();
|
|
66
|
-
const { sendForm, setRoute, triggerResize } = useOpenfort();
|
|
67
|
-
const wallet = useSolanaEmbeddedWallet();
|
|
68
|
-
const walletAddress = wallet.status === 'connected' ? (_a = wallet.activeWallet) === null || _a === void 0 ? void 0 : _a.address : undefined;
|
|
69
|
-
const provider = wallet.status === 'connected' ? wallet.provider : null;
|
|
70
|
-
const [txStatus, setTxStatus] = useState('idle');
|
|
71
|
-
const [txSignature, setTxSignature] = useState(null);
|
|
72
|
-
const [errorMessage, setErrorMessage] = useState(null);
|
|
73
|
-
const confirmAbortRef = useRef(null);
|
|
74
|
-
const normalisedAmount = sanitizeForParsing(sendForm.amount);
|
|
75
|
-
const parsedAmount = normalisedAmount && !Number.isNaN(parseFloat(normalisedAmount)) && parseFloat(normalisedAmount) > 0
|
|
76
|
-
? solToLamports(parseFloat(normalisedAmount))
|
|
77
|
-
: null;
|
|
78
|
-
const recipient = sendForm.recipient.trim();
|
|
79
|
-
const isSponsored = false;
|
|
80
|
-
const canProceed = !!provider &&
|
|
81
|
-
!!walletAddress &&
|
|
82
|
-
!!recipient &&
|
|
83
|
-
parsedAmount !== null &&
|
|
84
|
-
parsedAmount > BigInt(0) &&
|
|
85
|
-
txStatus === 'idle';
|
|
86
|
-
const handleConfirm = useCallback(async () => {
|
|
87
|
-
var _a;
|
|
88
|
-
if (!canProceed || !provider || !walletAddress || !parsedAmount || parsedAmount <= BigInt(0))
|
|
89
|
-
return;
|
|
90
|
-
setErrorMessage(null);
|
|
91
|
-
setTxStatus('signing');
|
|
92
|
-
try {
|
|
93
|
-
const rpc = createSolanaRpc(rpcUrl);
|
|
94
|
-
const { value: blockhash } = await rpc.getLatestBlockhash().send();
|
|
95
|
-
const fromAddress = address(walletAddress);
|
|
96
|
-
const transferInstruction = createTransferSolInstruction(walletAddress, recipient, parsedAmount);
|
|
97
|
-
const message = pipe(createTransactionMessage({ version: 0 }), (msg) => setTransactionMessageFeePayer(fromAddress, msg), (msg) => setTransactionMessageLifetimeUsingBlockhash(blockhash, msg), (msg) => appendTransactionMessageInstruction(transferInstruction, msg));
|
|
98
|
-
const compiled = compileTransaction(message);
|
|
99
|
-
const signed = await provider.signTransaction({ messageBytes: compiled.messageBytes });
|
|
100
|
-
const signatureBytes = decodeSignatureToBytes(signed.signature);
|
|
101
|
-
const signedTransaction = {
|
|
102
|
-
messageBytes: compiled.messageBytes,
|
|
103
|
-
signatures: { ...compiled.signatures, [fromAddress]: signatureBytes },
|
|
104
|
-
};
|
|
105
|
-
const encodedWire = getBase64EncodedWireTransaction(signedTransaction);
|
|
106
|
-
setTxStatus('sending');
|
|
107
|
-
await rpc
|
|
108
|
-
.sendTransaction(encodedWire, {
|
|
109
|
-
encoding: 'base64',
|
|
110
|
-
preflightCommitment: 'confirmed',
|
|
111
|
-
skipPreflight: false,
|
|
112
|
-
})
|
|
113
|
-
.send();
|
|
114
|
-
(_a = confirmAbortRef.current) === null || _a === void 0 ? void 0 : _a.abort();
|
|
115
|
-
const confirmController = new AbortController();
|
|
116
|
-
confirmAbortRef.current = confirmController;
|
|
117
|
-
await waitForConfirmation(rpcUrl, signed.signature);
|
|
118
|
-
setTxSignature(signed.signature);
|
|
119
|
-
setTxStatus('confirmed');
|
|
120
|
-
invalidateBalance();
|
|
121
|
-
}
|
|
122
|
-
catch (err) {
|
|
123
|
-
if (err instanceof DOMException && err.name === 'AbortError')
|
|
124
|
-
return;
|
|
125
|
-
setTxStatus('error');
|
|
126
|
-
const msg = err instanceof OpenfortError ? err.message : err instanceof Error ? err.message : String(err);
|
|
127
|
-
setErrorMessage(msg || 'Transaction failed');
|
|
128
|
-
}
|
|
129
|
-
}, [canProceed, provider, walletAddress, parsedAmount, recipient, rpcUrl]);
|
|
130
|
-
useEffect(() => {
|
|
131
|
-
return () => {
|
|
132
|
-
var _a;
|
|
133
|
-
(_a = confirmAbortRef.current) === null || _a === void 0 ? void 0 : _a.abort();
|
|
134
|
-
};
|
|
135
|
-
}, []);
|
|
136
|
-
useEffect(() => {
|
|
137
|
-
setTimeout(triggerResize, 10);
|
|
138
|
-
}, [txStatus, errorMessage, triggerResize]);
|
|
139
|
-
const feeDisplay = `~${formatSol(BASE_FEE_LAMPORTS, 6)} SOL`;
|
|
140
|
-
const explorerUrl = txSignature && cluster ? getExplorerUrl(ChainTypeEnum.SVM, { txHash: txSignature, cluster }) : undefined;
|
|
141
|
-
const handleOpenBlockExplorer = () => {
|
|
142
|
-
if (explorerUrl)
|
|
143
|
-
window.open(explorerUrl, '_blank', 'noopener,noreferrer');
|
|
144
|
-
};
|
|
145
|
-
if (txStatus === 'confirmed') {
|
|
146
|
-
return (jsxs(PageContent, { onBack: routes.SOL_CONNECTED, children: [jsx(Loader, { isSuccess: true, header: "Transfer Sent", description: `${normalisedAmount || '0'} SOL sent successfully` }), jsxs(ButtonRow, { children: [jsx(Button, { variant: "primary", onClick: handleOpenBlockExplorer, children: "View on Explorer" }), jsx(Button, { variant: "secondary", onClick: () => setRoute(routes.SOL_CONNECTED), children: "Back to profile" })] })] }));
|
|
147
|
-
}
|
|
148
|
-
return (jsxs(PageContent, { onBack: routes.SOL_SEND, children: [jsx(ModalHeading, { children: "Confirm transfer" }), jsx(ModalBody, { children: "Review the transaction details before sending." }), jsxs(SummaryList, { children: [jsxs(SummaryItem, { children: [jsx(SummaryLabel, { children: "Sending" }), jsxs(AmountValue, { children: [normalisedAmount || '0', " SOL"] })] }), jsxs(SummaryItem, { children: [jsx(SummaryLabel, { children: "From" }), jsx(AddressValue, { children: walletAddress ? (jsx(CopyText, { size: "1rem", value: walletAddress, children: truncateSolanaAddress(walletAddress) })) : ('--') })] }), jsxs(SummaryItem, { children: [jsx(SummaryLabel, { children: "To" }), jsx(AddressValue, { children: recipient ? (jsx(CopyText, { size: "1rem", value: recipient, children: truncateSolanaAddress(recipient) })) : ('--') })] }), jsxs(SummaryItem, { children: [jsx(SummaryLabel, { children: "Network fee" }), jsxs(FeesValue, { "$completed": isSponsored, children: [feeDisplay, jsx(CheckIconWrapper, { children: jsx(TickIcon, {}) })] })] }), isSponsored ] }), errorMessage && (jsxs(ErrorContainer, { children: [jsx(ErrorTitle, { children: "Transaction failed" }), jsx(ErrorMessage, { children: errorMessage })] })), jsxs(ButtonRow, { children: [jsxs(Button, { variant: "primary", onClick: handleConfirm, disabled: !canProceed, waiting: txStatus === 'signing' || txStatus === 'sending', children: [txStatus === 'idle' && 'Confirm', txStatus === 'signing' && 'Signing...', txStatus === 'sending' && 'Sending...', txStatus === 'error' && 'Try again'] }), jsx(Button, { variant: "secondary", onClick: () => setRoute(routes.SOL_SEND), disabled: txStatus !== 'idle', children: "Cancel" })] })] }));
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export { SolanaSendConfirmation as default };
|
|
152
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default function SolanaWallets(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { ChainTypeEnum } from '@openfort/openfort-js';
|
|
3
|
-
import { PlusIcon } from '../../../assets/icons.js';
|
|
4
|
-
import { toSolanaUserWallet } from '../../../hooks/openfort/walletTypes.js';
|
|
5
|
-
import { useOpenfortCore } from '../../../openfort/useOpenfort.js';
|
|
6
|
-
import { useSolanaEmbeddedWallet } from '../../../solana/hooks/useSolanaEmbeddedWallet.js';
|
|
7
|
-
import Button from '../../Common/Button/index.js';
|
|
8
|
-
import { ModalHeading, ModalBody } from '../../Common/Modal/styles.js';
|
|
9
|
-
import { WalletRecoveryIcon } from '../../Common/WalletRecoveryIcon/index.js';
|
|
10
|
-
import { recoverRoute } from '../../Openfort/routeHelpers.js';
|
|
11
|
-
import { routes } from '../../Openfort/types.js';
|
|
12
|
-
import { useOpenfort } from '../../Openfort/useOpenfort.js';
|
|
13
|
-
import { PageContent } from '../../PageContent/index.js';
|
|
14
|
-
import { ProvidersButton, ProviderIcon, ProviderLabel } from '../Providers/styles.js';
|
|
15
|
-
|
|
16
|
-
function WalletRow({ wallet }) {
|
|
17
|
-
const { setRoute } = useOpenfort();
|
|
18
|
-
const { chainType } = useOpenfortCore();
|
|
19
|
-
const display = wallet.address.length > 12 ? `${wallet.address.slice(0, 4)}...${wallet.address.slice(-4)}` : wallet.address;
|
|
20
|
-
const handleClick = () => {
|
|
21
|
-
const walletForRoute = toSolanaUserWallet(wallet);
|
|
22
|
-
setRoute(recoverRoute(chainType, walletForRoute));
|
|
23
|
-
};
|
|
24
|
-
return (jsx(ProvidersButton, { children: jsxs(Button, { onClick: handleClick, children: [jsx(ProviderLabel, { children: display }), jsx(ProviderIcon, { children: jsx(WalletRecoveryIcon, { recovery: wallet.recoveryMethod }) })] }) }));
|
|
25
|
-
}
|
|
26
|
-
function SolanaWallets() {
|
|
27
|
-
var _a;
|
|
28
|
-
const { setRoute } = useOpenfort();
|
|
29
|
-
const embeddedWallet = useSolanaEmbeddedWallet();
|
|
30
|
-
const wallets = (_a = embeddedWallet.wallets) !== null && _a !== void 0 ? _a : [];
|
|
31
|
-
const solanaWallets = wallets.filter((w) => w.chainType === ChainTypeEnum.SVM);
|
|
32
|
-
return (jsxs(PageContent, { onBack: routes.SOL_CONNECTED, children: [jsx(ModalHeading, { children: "Solana Wallets" }), jsxs(ModalBody, { children: [solanaWallets.map((wallet) => (jsx(WalletRow, { wallet: wallet }, wallet.id))), jsx(ProvidersButton, { children: jsx(Button, { onClick: () => setRoute(routes.SOL_CREATE_WALLET), icon: jsx(ProviderIcon, { children: jsx(PlusIcon, {}) }), children: jsx(ProviderLabel, { children: "Create new wallet" }) }) })] })] }));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export { SolanaWallets as default };
|
|
36
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Address validation utilities (dependency-free).
|
|
3
|
-
*
|
|
4
|
-
* openfort-js does not export address validation. The solana-sample example
|
|
5
|
-
* (openfort-js/examples/apps/solana-sample) uses @solana/kit's address() in a
|
|
6
|
-
* try/catch for Solana. We keep this shared util dependency-free so that
|
|
7
|
-
* consumers that don't use @solana/kit (e.g. EVM-only apps) don't pull it in.
|
|
8
|
-
* For stricter Solana validation when @solana/kit is available, use
|
|
9
|
-
* address(addr) from '@solana/kit' in a try/catch. React-native package has no
|
|
10
|
-
* shared address validation (no Send UI with recipient field in the repo).
|
|
11
|
-
*/
|
|
12
|
-
/**
|
|
13
|
-
* Validates a Solana address (Base58, 32–44 characters).
|
|
14
|
-
*/
|
|
15
|
-
export declare function isValidSolanaAddress(address: string): boolean;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Address validation utilities (dependency-free).
|
|
3
|
-
*
|
|
4
|
-
* openfort-js does not export address validation. The solana-sample example
|
|
5
|
-
* (openfort-js/examples/apps/solana-sample) uses @solana/kit's address() in a
|
|
6
|
-
* try/catch for Solana. We keep this shared util dependency-free so that
|
|
7
|
-
* consumers that don't use @solana/kit (e.g. EVM-only apps) don't pull it in.
|
|
8
|
-
* For stricter Solana validation when @solana/kit is available, use
|
|
9
|
-
* address(addr) from '@solana/kit' in a try/catch. React-native package has no
|
|
10
|
-
* shared address validation (no Send UI with recipient field in the repo).
|
|
11
|
-
*/
|
|
12
|
-
const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
13
|
-
function isValidBase58Character(c) {
|
|
14
|
-
return BASE58_ALPHABET.includes(c);
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Validates a Solana address (Base58, 32–44 characters).
|
|
18
|
-
*/
|
|
19
|
-
function isValidSolanaAddress(address) {
|
|
20
|
-
if (typeof address !== 'string' || address.length < 32 || address.length > 44) {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
return address.split('').every(isValidBase58Character);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export { isValidSolanaAddress };
|
|
27
|
-
//# sourceMappingURL=validation.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/** System Program's Transfer instruction index (SystemInstruction enum variant 2). */
|
|
2
|
-
export declare const TRANSFER_INSTRUCTION_INDEX = 2;
|
|
3
|
-
export declare const LAMPORTS_PER_SOL: bigint;
|
|
4
|
-
/**
|
|
5
|
-
* Solana System Program address.
|
|
6
|
-
* Not exported by @solana/kit v5 directly — defined here as a typed constant.
|
|
7
|
-
* Source: https://docs.solana.com/developing/runtime-facilities/programs#system-program
|
|
8
|
-
*/
|
|
9
|
-
export declare const SYSTEM_PROGRAM_ADDRESS = "11111111111111111111111111111111";
|
|
10
|
-
/**
|
|
11
|
-
* Base fee per signature (5,000 lamports). Does NOT include priority fees,
|
|
12
|
-
* which should be estimated dynamically via getPriorityFeeEstimate.
|
|
13
|
-
* See https://helius.dev/blog/solana-fees-in-theory-and-practice
|
|
14
|
-
*/
|
|
15
|
-
export declare const BASE_FEE_LAMPORTS: bigint;
|
|
16
|
-
/**
|
|
17
|
-
* Rent-exempt minimum for a zero-data system account (0 bytes of data).
|
|
18
|
-
* Derived from (128 + 0) bytes * 3,480 lamports/byte-year * 2 years = 890,880 lamports.
|
|
19
|
-
* For accounts with data, use getMinimumBalanceForRentExemption RPC call instead.
|
|
20
|
-
*/
|
|
21
|
-
export declare const RENT_EXEMPT_MINIMUM_LAMPORTS: bigint;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/** System Program's Transfer instruction index (SystemInstruction enum variant 2). */
|
|
2
|
-
const TRANSFER_INSTRUCTION_INDEX = 2;
|
|
3
|
-
const LAMPORTS_PER_SOL = BigInt(1000000000);
|
|
4
|
-
/**
|
|
5
|
-
* Solana System Program address.
|
|
6
|
-
* Not exported by @solana/kit v5 directly — defined here as a typed constant.
|
|
7
|
-
* Source: https://docs.solana.com/developing/runtime-facilities/programs#system-program
|
|
8
|
-
*/
|
|
9
|
-
const SYSTEM_PROGRAM_ADDRESS = '11111111111111111111111111111111';
|
|
10
|
-
/**
|
|
11
|
-
* Base fee per signature (5,000 lamports). Does NOT include priority fees,
|
|
12
|
-
* which should be estimated dynamically via getPriorityFeeEstimate.
|
|
13
|
-
* See https://helius.dev/blog/solana-fees-in-theory-and-practice
|
|
14
|
-
*/
|
|
15
|
-
const BASE_FEE_LAMPORTS = BigInt(5000);
|
|
16
|
-
/**
|
|
17
|
-
* Rent-exempt minimum for a zero-data system account (0 bytes of data).
|
|
18
|
-
* Derived from (128 + 0) bytes * 3,480 lamports/byte-year * 2 years = 890,880 lamports.
|
|
19
|
-
* For accounts with data, use getMinimumBalanceForRentExemption RPC call instead.
|
|
20
|
-
*/
|
|
21
|
-
const RENT_EXEMPT_MINIMUM_LAMPORTS = BigInt(890880);
|
|
22
|
-
|
|
23
|
-
export { BASE_FEE_LAMPORTS, LAMPORTS_PER_SOL, RENT_EXEMPT_MINIMUM_LAMPORTS, SYSTEM_PROGRAM_ADDRESS, TRANSFER_INSTRUCTION_INDEX };
|
|
24
|
-
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { AccountRole, address } from '@solana/kit';
|
|
2
|
-
export declare function createTransferSolInstruction(from: string, to: string, lamports: bigint): {
|
|
3
|
-
programAddress: ReturnType<typeof address>;
|
|
4
|
-
data: Uint8Array;
|
|
5
|
-
accounts: Array<{
|
|
6
|
-
address: ReturnType<typeof address>;
|
|
7
|
-
role: AccountRole;
|
|
8
|
-
}>;
|
|
9
|
-
};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { address, AccountRole } from '@solana/kit';
|
|
2
|
-
import { TRANSFER_INSTRUCTION_INDEX, SYSTEM_PROGRAM_ADDRESS } from '../constants.js';
|
|
3
|
-
|
|
4
|
-
function createTransferSolInstruction(from, to, lamports) {
|
|
5
|
-
const data = new Uint8Array(12);
|
|
6
|
-
const view = new DataView(data.buffer);
|
|
7
|
-
view.setUint32(0, TRANSFER_INSTRUCTION_INDEX, true);
|
|
8
|
-
view.setBigUint64(4, lamports, true);
|
|
9
|
-
return {
|
|
10
|
-
programAddress: address(SYSTEM_PROGRAM_ADDRESS),
|
|
11
|
-
data,
|
|
12
|
-
accounts: [
|
|
13
|
-
{ address: address(from), role: AccountRole.WRITABLE_SIGNER },
|
|
14
|
-
{ address: address(to), role: AccountRole.WRITABLE },
|
|
15
|
-
],
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export { createTransferSolInstruction };
|
|
20
|
-
//# sourceMappingURL=transfer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transfer.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;"}
|