@openfort/react 1.1.4 → 1.3.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.
- package/build/assets/icons.js +1 -1
- package/build/assets/logos.d.ts +15 -0
- package/build/assets/logos.js +9 -0
- package/build/assets/logos.js.map +1 -1
- package/build/components/Common/CopyToClipboard/CopyIconButton.d.ts +3 -1
- package/build/components/Common/CopyToClipboard/CopyIconButton.js +4 -4
- package/build/components/Common/CustomQRCode/index.d.ts +1 -1
- package/build/components/Common/CustomQRCode/index.js +3 -3
- package/build/components/Common/CustomQRCode/styles.d.ts +1 -0
- package/build/components/Common/CustomQRCode/styles.js +4 -4
- package/build/components/Common/CustomQRCode/types.d.ts +2 -0
- package/build/components/Common/Modal/styles.js +4 -1
- package/build/components/Common/Modal/styles.js.map +1 -1
- package/build/components/Common/SolanaChain/index.d.ts +8 -0
- package/build/components/Common/SolanaChain/index.js +40 -0
- package/build/components/Common/SolanaChain/index.js.map +1 -0
- package/build/components/ConnectModal/index.js +16 -2
- package/build/components/ConnectModal/index.js.map +1 -1
- package/build/components/Openfort/OpenfortProvider.js +4 -1
- package/build/components/Openfort/OpenfortProvider.js.map +1 -1
- package/build/components/Openfort/types.d.ts +92 -0
- package/build/components/Openfort/types.js +23 -1
- package/build/components/Openfort/types.js.map +1 -1
- package/build/components/Pages/AssetInventory/SolanaAssetInventory.d.ts +6 -0
- package/build/components/Pages/AssetInventory/SolanaAssetInventory.js +42 -0
- package/build/components/Pages/AssetInventory/SolanaAssetInventory.js.map +1 -0
- package/build/components/Pages/Buy/coinbaseApi.d.ts +1 -1
- package/build/components/Pages/Buy/coinbaseApi.js +2 -13
- package/build/components/Pages/Buy/coinbaseApi.js.map +1 -1
- package/build/components/Pages/Buy/evmCurrencies.d.ts +11 -0
- package/build/components/Pages/Buy/evmCurrencies.js +27 -0
- package/build/components/Pages/Buy/evmCurrencies.js.map +1 -0
- package/build/components/Pages/Buy/index.js +11 -3
- package/build/components/Pages/Buy/index.js.map +1 -1
- package/build/components/Pages/Buy/onrampApi.d.ts +8 -1
- package/build/components/Pages/Buy/onrampApi.js +24 -14
- package/build/components/Pages/Buy/onrampApi.js.map +1 -1
- package/build/components/Pages/Buy/solanaCurrencies.d.ts +9 -0
- package/build/components/Pages/Buy/solanaCurrencies.js +25 -0
- package/build/components/Pages/Buy/solanaCurrencies.js.map +1 -0
- package/build/components/Pages/Buy/stripeApi.d.ts +1 -1
- package/build/components/Pages/Buy/stripeApi.js +2 -13
- package/build/components/Pages/Buy/stripeApi.js.map +1 -1
- package/build/components/Pages/BuyComplete/index.js +7 -1
- package/build/components/Pages/BuyComplete/index.js.map +1 -1
- package/build/components/Pages/BuyProcessing/index.js +9 -5
- package/build/components/Pages/BuyProcessing/index.js.map +1 -1
- package/build/components/Pages/BuySelectProvider/index.js +11 -6
- package/build/components/Pages/BuySelectProvider/index.js.map +1 -1
- package/build/components/Pages/Connected/EthereumConnected.js +8 -32
- package/build/components/Pages/Connected/EthereumConnected.js.map +1 -1
- package/build/components/Pages/Connected/SolanaConnected.js +11 -5
- package/build/components/Pages/Connected/SolanaConnected.js.map +1 -1
- package/build/components/Pages/Deposit/AddressPageLink.d.ts +7 -0
- package/build/components/Pages/Deposit/AddressPageLink.js +17 -0
- package/build/components/Pages/Deposit/AddressPageLink.js.map +1 -0
- package/build/components/Pages/Deposit/AssetChainLogo.d.ts +9 -0
- package/build/components/Pages/Deposit/AssetChainLogo.js +24 -0
- package/build/components/Pages/Deposit/AssetChainLogo.js.map +1 -0
- package/build/components/Pages/Deposit/DepositAddressBlock.d.ts +21 -0
- package/build/components/Pages/Deposit/DepositAddressBlock.js +28 -0
- package/build/components/Pages/Deposit/DepositAddressBlock.js.map +1 -0
- package/build/components/Pages/Deposit/DepositProgress.d.ts +15 -0
- package/build/components/Pages/Deposit/DepositProgress.js +111 -0
- package/build/components/Pages/Deposit/DepositProgress.js.map +1 -0
- package/build/components/Pages/Deposit/DepositStatus.d.ts +9 -0
- package/build/components/Pages/Deposit/DepositStatus.js +43 -0
- package/build/components/Pages/Deposit/DepositStatus.js.map +1 -0
- package/build/components/Pages/Deposit/DepositSuccess.d.ts +6 -0
- package/build/components/Pages/Deposit/DepositSuccess.js +25 -0
- package/build/components/Pages/Deposit/DepositSuccess.js.map +1 -0
- package/build/components/Pages/Deposit/Details.d.ts +12 -0
- package/build/components/Pages/Deposit/Details.js +40 -0
- package/build/components/Pages/Deposit/Details.js.map +1 -0
- package/build/components/Pages/Deposit/LogoSelect.d.ts +12 -0
- package/build/components/Pages/Deposit/LogoSelect.js +95 -0
- package/build/components/Pages/Deposit/LogoSelect.js.map +1 -0
- package/build/components/Pages/Deposit/OrDivider.d.ts +2 -0
- package/build/components/Pages/Deposit/OrDivider.js +10 -0
- package/build/components/Pages/Deposit/OrDivider.js.map +1 -0
- package/build/components/Pages/Deposit/RouteSelectors.d.ts +13 -0
- package/build/components/Pages/Deposit/RouteSelectors.js +19 -0
- package/build/components/Pages/Deposit/RouteSelectors.js.map +1 -0
- package/build/components/Pages/Deposit/cexChains.d.ts +9 -0
- package/build/components/Pages/Deposit/cexChains.js +23 -0
- package/build/components/Pages/Deposit/cexChains.js.map +1 -0
- package/build/components/Pages/Deposit/formStyles.d.ts +24 -0
- package/build/components/Pages/Deposit/formStyles.js +83 -0
- package/build/components/Pages/Deposit/formStyles.js.map +1 -0
- package/build/components/Pages/Deposit/index.d.ts +7 -0
- package/build/components/Pages/Deposit/index.js +114 -0
- package/build/components/Pages/Deposit/index.js.map +1 -0
- package/build/components/Pages/Deposit/paymentOptions.d.ts +49 -0
- package/build/components/Pages/Deposit/paymentOptions.js +63 -0
- package/build/components/Pages/Deposit/paymentOptions.js.map +1 -0
- package/build/components/Pages/Deposit/sources.d.ts +17 -0
- package/build/components/Pages/Deposit/sources.js +22 -0
- package/build/components/Pages/Deposit/sources.js.map +1 -0
- package/build/components/Pages/Deposit/styles.d.ts +25 -0
- package/build/components/Pages/Deposit/styles.js +167 -0
- package/build/components/Pages/Deposit/styles.js.map +1 -0
- package/build/components/Pages/Deposit/useDepositRoute.d.ts +34 -0
- package/build/components/Pages/Deposit/useDepositRoute.js +106 -0
- package/build/components/Pages/Deposit/useDepositRoute.js.map +1 -0
- package/build/components/Pages/Deposit/useFundingTarget.d.ts +11 -0
- package/build/components/Pages/Deposit/useFundingTarget.js +25 -0
- package/build/components/Pages/Deposit/useFundingTarget.js.map +1 -0
- package/build/components/Pages/DepositCex/index.d.ts +11 -0
- package/build/components/Pages/DepositCex/index.js +229 -0
- package/build/components/Pages/DepositCex/index.js.map +1 -0
- package/build/components/Pages/DepositCrypto/index.d.ts +8 -0
- package/build/components/Pages/DepositCrypto/index.js +31 -0
- package/build/components/Pages/DepositCrypto/index.js.map +1 -0
- package/build/components/Pages/DepositWallet/DepositWalletDesktop.d.ts +20 -0
- package/build/components/Pages/DepositWallet/DepositWalletDesktop.js +139 -0
- package/build/components/Pages/DepositWallet/DepositWalletDesktop.js.map +1 -0
- package/build/components/Pages/DepositWallet/index.d.ts +9 -0
- package/build/components/Pages/DepositWallet/index.js +107 -0
- package/build/components/Pages/DepositWallet/index.js.map +1 -0
- package/build/components/Pages/DepositWallet/walletDeeplinks.d.ts +50 -0
- package/build/components/Pages/DepositWallet/walletDeeplinks.js +109 -0
- package/build/components/Pages/DepositWallet/walletDeeplinks.js.map +1 -0
- package/build/components/Pages/ExportKey/index.js +10 -2
- package/build/components/Pages/ExportKey/index.js.map +1 -1
- package/build/components/Pages/NoAssetsAvailable/index.js +5 -21
- package/build/components/Pages/NoAssetsAvailable/index.js.map +1 -1
- package/build/components/Pages/SelectToken/SolanaSelectToken.d.ts +1 -0
- package/build/components/Pages/SelectToken/SolanaSelectToken.js +50 -0
- package/build/components/Pages/SelectToken/SolanaSelectToken.js.map +1 -0
- package/build/components/Pages/SelectToken/index.js +13 -2
- package/build/components/Pages/SelectToken/index.js.map +1 -1
- package/build/components/Pages/SelectToken/styles.js +1 -1
- package/build/components/Pages/Send/SolanaSend.d.ts +1 -0
- package/build/components/Pages/Send/SolanaSend.js +89 -0
- package/build/components/Pages/Send/SolanaSend.js.map +1 -0
- package/build/components/Pages/Send/index.d.ts +2 -1
- package/build/components/Pages/Send/index.js +0 -1
- package/build/components/Pages/Send/index.js.map +1 -1
- package/build/components/Pages/Send/utils.js +4 -1
- package/build/components/Pages/Send/utils.js.map +1 -1
- package/build/components/Pages/SendConfirmation/EstimatedFees.js +5 -3
- package/build/components/Pages/SendConfirmation/EstimatedFees.js.map +1 -1
- package/build/components/Pages/SendConfirmation/SolanaSendConfirmation.d.ts +1 -0
- package/build/components/Pages/SendConfirmation/SolanaSendConfirmation.js +121 -0
- package/build/components/Pages/SendConfirmation/SolanaSendConfirmation.js.map +1 -0
- package/build/components/Pages/SendConfirmation/index.js +4 -3
- package/build/components/Pages/SendConfirmation/index.js.map +1 -1
- package/build/constants/logos.js +1 -0
- package/build/constants/logos.js.map +1 -1
- package/build/ethereum/hooks/useEthereumWalletAssets.js +212 -95
- package/build/ethereum/hooks/useEthereumWalletAssets.js.map +1 -1
- package/build/hooks/openfort/fundingClient.d.ts +34 -0
- package/build/hooks/openfort/fundingClient.js +60 -0
- package/build/hooks/openfort/fundingClient.js.map +1 -0
- package/build/hooks/openfort/useFunding.d.ts +159 -0
- package/build/hooks/openfort/useFunding.js +204 -0
- package/build/hooks/openfort/useFunding.js.map +1 -0
- package/build/hooks/openfort/useFundingChains.d.ts +49 -0
- package/build/hooks/openfort/useFundingChains.js +100 -0
- package/build/hooks/openfort/useFundingChains.js.map +1 -0
- package/build/hooks/useBalance.js +6 -1
- package/build/hooks/useBalance.js.map +1 -1
- package/build/index.d.ts +4 -1
- package/build/index.js +2 -1
- package/build/index.js.map +1 -1
- package/build/shared/hooks/useAsyncData.d.ts +11 -0
- package/build/shared/hooks/useAsyncData.js +73 -13
- package/build/shared/hooks/useAsyncData.js.map +1 -1
- package/build/solana/hooks/useSolanaWalletAssets.d.ts +24 -0
- package/build/solana/hooks/useSolanaWalletAssets.js +86 -0
- package/build/solana/hooks/useSolanaWalletAssets.js.map +1 -0
- package/build/solana/transfer.d.ts +61 -0
- package/build/solana/transfer.js +219 -0
- package/build/solana/transfer.js.map +1 -0
- package/build/solana/types.d.ts +8 -0
- package/build/utils/index.d.ts +2 -1
- package/build/utils/index.js +1 -1
- package/build/version.d.ts +1 -1
- package/build/version.js +1 -1
- package/build/wagmi/defaultConnectors.js +5 -1
- package/build/wagmi/defaultConnectors.js.map +1 -1
- package/package.json +13 -1
package/build/index.js
CHANGED
|
@@ -3,7 +3,7 @@ export { default as Avatar } from './components/Common/Avatar/index.js';
|
|
|
3
3
|
export { default as ChainIcon } from './components/Common/Chain/index.js';
|
|
4
4
|
export { OpenfortButton } from './components/ConnectButton/index.js';
|
|
5
5
|
export { OpenfortProvider } from './components/Openfort/OpenfortProvider.js';
|
|
6
|
-
export { UIAuthProvider as AuthProvider, LinkWalletOnSignUpOption } from './components/Openfort/types.js';
|
|
6
|
+
export { UIAuthProvider as AuthProvider, FundingMethod, LinkWalletOnSignUpOption } from './components/Openfort/types.js';
|
|
7
7
|
export { embeddedWalletId } from './constants/openfort.js';
|
|
8
8
|
export { OpenfortError, OpenfortReactErrorType as OpenfortErrorType, OpenfortReactErrorType } from './types.js';
|
|
9
9
|
export { useAuthCallback } from './hooks/openfort/auth/useAuthCallback.js';
|
|
@@ -14,6 +14,7 @@ export { useOAuth } from './hooks/openfort/auth/useOAuth.js';
|
|
|
14
14
|
export { usePhoneOtpAuth } from './hooks/openfort/auth/usePhoneOtpAuth.js';
|
|
15
15
|
export { useSignOut } from './hooks/openfort/auth/useSignOut.js';
|
|
16
16
|
export { use7702Authorization } from './hooks/openfort/use7702Authorization.js';
|
|
17
|
+
export { useFunding } from './hooks/openfort/useFunding.js';
|
|
17
18
|
export { useGrantPermissions } from './hooks/openfort/useGrantPermissions.js';
|
|
18
19
|
export { useRevokePermissions } from './hooks/openfort/useRevokePermissions.js';
|
|
19
20
|
export { useUI } from './hooks/openfort/useUI.js';
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -5,9 +5,20 @@ type UseAsyncDataOptions<T> = {
|
|
|
5
5
|
refetchInterval?: number;
|
|
6
6
|
staleTime?: number;
|
|
7
7
|
};
|
|
8
|
+
/**
|
|
9
|
+
* Drop cached entries so the next mount (or refetch) hits the network instead of
|
|
10
|
+
* painting stale data. Pass a substring matched against the serialized queryKey
|
|
11
|
+
* to target specific queries (e.g. `'walletAssets'`), or omit to clear everything.
|
|
12
|
+
* Used by balance-changing flows (deposit/mint/send) to force fresh balances.
|
|
13
|
+
*/
|
|
14
|
+
export declare function invalidateAsyncData(keyMatch?: string): void;
|
|
8
15
|
/**
|
|
9
16
|
* Simple fetch-with-cache hook. Replaces useQuery for internal SDK use.
|
|
10
17
|
* No external dependency on TanStack Query.
|
|
18
|
+
*
|
|
19
|
+
* Stale-while-revalidate: a cached (non-empty) result for the same `queryKey` is
|
|
20
|
+
* painted synchronously on (re)mount — so navigating away and back is instant —
|
|
21
|
+
* then refreshed in the background (skipped while younger than `staleTime`).
|
|
11
22
|
*/
|
|
12
23
|
export declare function useAsyncData<T>({ queryFn, queryKey, enabled, refetchInterval, staleTime, }: UseAsyncDataOptions<T>): {
|
|
13
24
|
data: T | undefined;
|
|
@@ -1,29 +1,79 @@
|
|
|
1
1
|
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
2
2
|
|
|
3
|
+
/** Module-level cache shared across hook instances, so revisiting a view paints instantly. */
|
|
4
|
+
const dataCache = new Map();
|
|
5
|
+
/**
|
|
6
|
+
* Serialize a queryKey to a stable cache string.
|
|
7
|
+
*
|
|
8
|
+
* `JSON.stringify` throws `TypeError: Do not know how to serialize a BigInt`,
|
|
9
|
+
* and queryKeys legitimately carry bigints (token amounts, balances, gas
|
|
10
|
+
* values — e.g. a native ETH send keys its gas estimate on the bigint amount).
|
|
11
|
+
* Without this replacer such a key crashes the whole modal render. A bigint is
|
|
12
|
+
* encoded as its decimal digits with an `n` suffix so distinct values stay
|
|
13
|
+
* distinct keys.
|
|
14
|
+
*/
|
|
15
|
+
function serializeQueryKey(queryKey) {
|
|
16
|
+
return JSON.stringify(queryKey, (_key, value) => (typeof value === 'bigint' ? `${value}n` : value));
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Drop cached entries so the next mount (or refetch) hits the network instead of
|
|
20
|
+
* painting stale data. Pass a substring matched against the serialized queryKey
|
|
21
|
+
* to target specific queries (e.g. `'walletAssets'`), or omit to clear everything.
|
|
22
|
+
* Used by balance-changing flows (deposit/mint/send) to force fresh balances.
|
|
23
|
+
*/
|
|
24
|
+
function invalidateAsyncData(keyMatch) {
|
|
25
|
+
if (!keyMatch) {
|
|
26
|
+
dataCache.clear();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
for (const key of Array.from(dataCache.keys())) {
|
|
30
|
+
if (key.includes(keyMatch))
|
|
31
|
+
dataCache.delete(key);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Empty/absent results are NOT cached — only meaningful data is. This prevents a
|
|
36
|
+
* transient empty response (e.g. a cold/erroring asset call) from being pinned
|
|
37
|
+
* and shown as "no balance" on later mounts.
|
|
38
|
+
*/
|
|
39
|
+
function isEmptyResult(result) {
|
|
40
|
+
if (result == null)
|
|
41
|
+
return true;
|
|
42
|
+
if (Array.isArray(result))
|
|
43
|
+
return result.length === 0;
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
3
46
|
/**
|
|
4
47
|
* Simple fetch-with-cache hook. Replaces useQuery for internal SDK use.
|
|
5
48
|
* No external dependency on TanStack Query.
|
|
49
|
+
*
|
|
50
|
+
* Stale-while-revalidate: a cached (non-empty) result for the same `queryKey` is
|
|
51
|
+
* painted synchronously on (re)mount — so navigating away and back is instant —
|
|
52
|
+
* then refreshed in the background (skipped while younger than `staleTime`).
|
|
6
53
|
*/
|
|
7
54
|
function useAsyncData({ queryFn, queryKey, enabled = true, refetchInterval, staleTime = 0, }) {
|
|
8
|
-
|
|
55
|
+
// Serialize queryKey to a stable string so the effect only re-runs when values change,
|
|
56
|
+
// not when array/object references change. Bigint-safe (see serializeQueryKey).
|
|
57
|
+
const queryKeyStr = serializeQueryKey(queryKey);
|
|
58
|
+
const [data, setData] = useState(() => { var _a; return (_a = dataCache.get(queryKeyStr)) === null || _a === void 0 ? void 0 : _a.data; });
|
|
9
59
|
const [error, setError] = useState(null);
|
|
10
60
|
const [isLoading, setIsLoading] = useState(false);
|
|
11
61
|
const lastFetchRef = useRef(0);
|
|
12
62
|
const intervalRef = useRef(null);
|
|
13
63
|
const queryFnRef = useRef(queryFn);
|
|
14
64
|
queryFnRef.current = queryFn;
|
|
15
|
-
|
|
16
|
-
// not when array/object references change.
|
|
17
|
-
const queryKeyStr = JSON.stringify(queryKey);
|
|
18
|
-
const fetchData = useCallback(async () => {
|
|
65
|
+
const fetchData = useCallback(async (showLoading = true) => {
|
|
19
66
|
if (!enabled)
|
|
20
67
|
return undefined;
|
|
21
|
-
|
|
68
|
+
if (showLoading)
|
|
69
|
+
setIsLoading(true);
|
|
22
70
|
setError(null);
|
|
23
71
|
try {
|
|
24
72
|
const result = await queryFnRef.current();
|
|
25
|
-
|
|
73
|
+
if (!isEmptyResult(result))
|
|
74
|
+
dataCache.set(queryKeyStr, { data: result, timestamp: Date.now() });
|
|
26
75
|
lastFetchRef.current = Date.now();
|
|
76
|
+
setData(result);
|
|
27
77
|
return result;
|
|
28
78
|
}
|
|
29
79
|
catch (err) {
|
|
@@ -34,12 +84,22 @@ function useAsyncData({ queryFn, queryKey, enabled = true, refetchInterval, stal
|
|
|
34
84
|
finally {
|
|
35
85
|
setIsLoading(false);
|
|
36
86
|
}
|
|
37
|
-
}, [enabled]);
|
|
87
|
+
}, [enabled, queryKeyStr]);
|
|
38
88
|
useEffect(() => {
|
|
39
89
|
if (!enabled)
|
|
40
90
|
return;
|
|
41
|
-
|
|
42
|
-
|
|
91
|
+
const cached = dataCache.get(queryKeyStr);
|
|
92
|
+
if (cached) {
|
|
93
|
+
// Paint cached data immediately; revalidate in the background unless still fresh.
|
|
94
|
+
setData(cached.data);
|
|
95
|
+
const fresh = staleTime > 0 && Date.now() - cached.timestamp < staleTime;
|
|
96
|
+
if (!fresh)
|
|
97
|
+
fetchData(false).catch(() => { });
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
fetchData(true).catch(() => { });
|
|
101
|
+
}
|
|
102
|
+
}, [enabled, queryKeyStr, staleTime, fetchData]);
|
|
43
103
|
useEffect(() => {
|
|
44
104
|
if (!enabled || !refetchInterval || refetchInterval <= 0)
|
|
45
105
|
return;
|
|
@@ -47,7 +107,7 @@ function useAsyncData({ queryFn, queryKey, enabled = true, refetchInterval, stal
|
|
|
47
107
|
const elapsed = Date.now() - lastFetchRef.current;
|
|
48
108
|
if (staleTime > 0 && elapsed < staleTime)
|
|
49
109
|
return;
|
|
50
|
-
fetchData().catch(() => { });
|
|
110
|
+
fetchData(false).catch(() => { });
|
|
51
111
|
}, refetchInterval);
|
|
52
112
|
return () => {
|
|
53
113
|
if (intervalRef.current) {
|
|
@@ -61,9 +121,9 @@ function useAsyncData({ queryFn, queryKey, enabled = true, refetchInterval, stal
|
|
|
61
121
|
error,
|
|
62
122
|
isLoading,
|
|
63
123
|
isPending: isLoading,
|
|
64
|
-
refetch: fetchData,
|
|
124
|
+
refetch: useCallback(() => fetchData(true), [fetchData]),
|
|
65
125
|
};
|
|
66
126
|
}
|
|
67
127
|
|
|
68
|
-
export { useAsyncData };
|
|
128
|
+
export { invalidateAsyncData, useAsyncData };
|
|
69
129
|
//# sourceMappingURL=useAsyncData.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useAsyncData.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useAsyncData.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** A holding in the connected Solana wallet: native SOL or an SPL token. */
|
|
2
|
+
type SolanaAsset = {
|
|
3
|
+
/** Mint address, or 'native' for SOL. */
|
|
4
|
+
mint: string;
|
|
5
|
+
symbol: string;
|
|
6
|
+
name: string;
|
|
7
|
+
/** Raw balance in base units (lamports for SOL, token base units otherwise). */
|
|
8
|
+
amount: bigint;
|
|
9
|
+
decimals: number;
|
|
10
|
+
isNative: boolean;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Returns the connected Solana wallet's balances: native SOL plus SPL token
|
|
14
|
+
* holdings, read directly from the cluster RPC. The SVM counterpart of
|
|
15
|
+
* {@link useEthereumWalletAssets}, feeding the Solana asset inventory. Refreshes
|
|
16
|
+
* on BALANCE_INVALIDATE_EVENT (e.g. after a deposit/send).
|
|
17
|
+
*/
|
|
18
|
+
export declare function useSolanaWalletAssets(): {
|
|
19
|
+
data: SolanaAsset[] | null;
|
|
20
|
+
isLoading: boolean;
|
|
21
|
+
isError: boolean;
|
|
22
|
+
refetch: () => Promise<unknown>;
|
|
23
|
+
};
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { BALANCE_INVALIDATE_EVENT } from '../../hooks/useBalance.js';
|
|
3
|
+
import { useAsyncData } from '../../shared/hooks/useAsyncData.js';
|
|
4
|
+
import { useSolanaContext } from '../SolanaContext.js';
|
|
5
|
+
import { useSolanaEmbeddedWallet } from './useSolanaEmbeddedWallet.js';
|
|
6
|
+
|
|
7
|
+
/** SPL Token + Token-2022 program ids — token accounts live under one of these. */
|
|
8
|
+
const TOKEN_PROGRAMS = ['TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'];
|
|
9
|
+
/**
|
|
10
|
+
* Known SPL mints → display metadata. An SPL token account carries only the mint
|
|
11
|
+
* and amount on-chain (no symbol/name), so common mints are mapped here; unknown
|
|
12
|
+
* mints fall back to a truncated mint address.
|
|
13
|
+
*/
|
|
14
|
+
const KNOWN_MINTS = {
|
|
15
|
+
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v: { symbol: 'USDC', name: 'USD Coin' },
|
|
16
|
+
Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB: { symbol: 'USDT', name: 'Tether USD' },
|
|
17
|
+
// Circle's devnet USDC mint (same UI label).
|
|
18
|
+
'4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU': { symbol: 'USDC', name: 'USD Coin' },
|
|
19
|
+
};
|
|
20
|
+
async function fetchSolanaAssets(addressStr, rpcUrl) {
|
|
21
|
+
var _a, _b;
|
|
22
|
+
const { address, createSolanaRpc } = await import('@solana/kit');
|
|
23
|
+
const rpc = createSolanaRpc(rpcUrl);
|
|
24
|
+
const owner = address(addressStr);
|
|
25
|
+
const out = [];
|
|
26
|
+
// Native SOL — always listed (even at zero) so it anchors the view.
|
|
27
|
+
const { value: lamports } = await rpc.getBalance(owner, { commitment: 'confirmed' }).send();
|
|
28
|
+
out.push({ mint: 'native', symbol: 'SOL', name: 'Solana', amount: BigInt(lamports), decimals: 9, isNative: true });
|
|
29
|
+
// SPL token balances across both token programs. The jsonParsed encoding yields
|
|
30
|
+
// a typed account whose `data.parsed.info` carries the mint and token amount.
|
|
31
|
+
for (const program of TOKEN_PROGRAMS) {
|
|
32
|
+
try {
|
|
33
|
+
const { value: accounts } = await rpc
|
|
34
|
+
.getTokenAccountsByOwner(owner, { programId: address(program) }, { encoding: 'jsonParsed', commitment: 'confirmed' })
|
|
35
|
+
.send();
|
|
36
|
+
for (const acc of accounts) {
|
|
37
|
+
const info = acc.account.data.parsed.info;
|
|
38
|
+
const amount = BigInt(info.tokenAmount.amount);
|
|
39
|
+
if (amount === BigInt(0))
|
|
40
|
+
continue;
|
|
41
|
+
const mint = info.mint;
|
|
42
|
+
const known = KNOWN_MINTS[mint];
|
|
43
|
+
out.push({
|
|
44
|
+
mint,
|
|
45
|
+
symbol: (_a = known === null || known === void 0 ? void 0 : known.symbol) !== null && _a !== void 0 ? _a : `${mint.slice(0, 4)}…${mint.slice(-4)}`,
|
|
46
|
+
name: (_b = known === null || known === void 0 ? void 0 : known.name) !== null && _b !== void 0 ? _b : 'SPL Token',
|
|
47
|
+
amount,
|
|
48
|
+
decimals: info.tokenAmount.decimals,
|
|
49
|
+
isNative: false,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Program absent or RPC hiccup — skip this program, keep what we have.
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Returns the connected Solana wallet's balances: native SOL plus SPL token
|
|
61
|
+
* holdings, read directly from the cluster RPC. The SVM counterpart of
|
|
62
|
+
* {@link useEthereumWalletAssets}, feeding the Solana asset inventory. Refreshes
|
|
63
|
+
* on BALANCE_INVALIDATE_EVENT (e.g. after a deposit/send).
|
|
64
|
+
*/
|
|
65
|
+
function useSolanaWalletAssets() {
|
|
66
|
+
const wallet = useSolanaEmbeddedWallet();
|
|
67
|
+
const { rpcUrl } = useSolanaContext();
|
|
68
|
+
const address = wallet.status === 'connected' && wallet.address ? wallet.address : undefined;
|
|
69
|
+
const { data, error, isLoading, refetch } = useAsyncData({
|
|
70
|
+
queryKey: ['solana-assets', address, rpcUrl],
|
|
71
|
+
queryFn: () => (address && rpcUrl ? fetchSolanaAssets(address, rpcUrl) : Promise.resolve([])),
|
|
72
|
+
enabled: Boolean(address && rpcUrl),
|
|
73
|
+
staleTime: 30000,
|
|
74
|
+
});
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (!address)
|
|
77
|
+
return;
|
|
78
|
+
const handler = () => refetch().catch(() => { });
|
|
79
|
+
window.addEventListener(BALANCE_INVALIDATE_EVENT, handler);
|
|
80
|
+
return () => window.removeEventListener(BALANCE_INVALIDATE_EVENT, handler);
|
|
81
|
+
}, [address, refetch]);
|
|
82
|
+
return { data: data !== null && data !== void 0 ? data : null, isLoading, isError: Boolean(error), refetch };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export { useSolanaWalletAssets };
|
|
86
|
+
//# sourceMappingURL=useSolanaWalletAssets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSolanaWalletAssets.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { OpenfortEmbeddedSolanaWalletProvider, SolanaCluster } from './types';
|
|
2
|
+
type SendSolParams = {
|
|
3
|
+
from: string;
|
|
4
|
+
to: string;
|
|
5
|
+
amountSol: number;
|
|
6
|
+
provider: OpenfortEmbeddedSolanaWalletProvider;
|
|
7
|
+
rpcUrl: string;
|
|
8
|
+
commitment?: 'processed' | 'confirmed' | 'finalized';
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Build, sign, and broadcast a native SOL transfer. Returns the transaction
|
|
12
|
+
* signature (base58). The wallet pays the network fee — use {@link sendSolGasless}
|
|
13
|
+
* to sponsor it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function sendSol({ from, to, amountSol, provider, rpcUrl, commitment, }: SendSolParams): Promise<string>;
|
|
16
|
+
type SendSplTokenParams = {
|
|
17
|
+
from: string;
|
|
18
|
+
to: string;
|
|
19
|
+
/** SPL mint address (base58). */
|
|
20
|
+
mint: string;
|
|
21
|
+
/** Amount in token base units (already scaled by `decimals`). */
|
|
22
|
+
amount: bigint;
|
|
23
|
+
decimals: number;
|
|
24
|
+
provider: OpenfortEmbeddedSolanaWalletProvider;
|
|
25
|
+
rpcUrl: string;
|
|
26
|
+
commitment?: 'processed' | 'confirmed' | 'finalized';
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Build, sign, and broadcast an SPL token transfer. Creates the recipient's
|
|
30
|
+
* associated token account if it doesn't exist yet (idempotent — a no-op when it
|
|
31
|
+
* already holds the token; the sender pays the small rent). The wallet pays the
|
|
32
|
+
* network fee — use {@link sendSplTokenGasless} to sponsor it. Returns the
|
|
33
|
+
* transaction signature (base58).
|
|
34
|
+
*/
|
|
35
|
+
export declare function sendSplToken({ from, to, mint, amount, decimals, provider, rpcUrl, commitment, }: SendSplTokenParams): Promise<string>;
|
|
36
|
+
type SendSolGaslessParams = {
|
|
37
|
+
from: string;
|
|
38
|
+
to: string;
|
|
39
|
+
amountSol: number;
|
|
40
|
+
provider: OpenfortEmbeddedSolanaWalletProvider;
|
|
41
|
+
cluster: SolanaCluster;
|
|
42
|
+
/** Project publishable key; sent to the Openfort Solana paymaster (Kora) as a Bearer token. */
|
|
43
|
+
publishableKey: string;
|
|
44
|
+
};
|
|
45
|
+
/** Send a native SOL transfer with fees sponsored by the Openfort paymaster (Kora). */
|
|
46
|
+
export declare function sendSolGasless({ from, to, amountSol, provider, cluster, publishableKey, }: SendSolGaslessParams): Promise<string>;
|
|
47
|
+
type SendSplTokenGaslessParams = {
|
|
48
|
+
from: string;
|
|
49
|
+
to: string;
|
|
50
|
+
/** SPL mint address (base58). */
|
|
51
|
+
mint: string;
|
|
52
|
+
/** Amount in token base units (already scaled by `decimals`). */
|
|
53
|
+
amount: bigint;
|
|
54
|
+
provider: OpenfortEmbeddedSolanaWalletProvider;
|
|
55
|
+
cluster: SolanaCluster;
|
|
56
|
+
/** Project publishable key; sent to the Openfort Solana paymaster (Kora) as a Bearer token. */
|
|
57
|
+
publishableKey: string;
|
|
58
|
+
};
|
|
59
|
+
/** Send an SPL token transfer with fees sponsored by the Openfort paymaster (Kora). */
|
|
60
|
+
export declare function sendSplTokenGasless({ from, to, mint, amount, provider, cluster, publishableKey, }: SendSplTokenGaslessParams): Promise<string>;
|
|
61
|
+
export {};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/** The System program id — the "token" for a native SOL transfer through Kora. */
|
|
2
|
+
const SYSTEM_PROGRAM_ID = '11111111111111111111111111111111';
|
|
3
|
+
const SEND_TIMEOUT_MS = 60000;
|
|
4
|
+
/** Decimal SOL → lamports, without floating-point loss. */
|
|
5
|
+
function solToLamports(amountSol) {
|
|
6
|
+
const [whole, frac = ''] = amountSol.toString().split('.');
|
|
7
|
+
const padded = (frac + '0'.repeat(9)).slice(0, 9);
|
|
8
|
+
return BigInt(`${whole || '0'}${padded}`);
|
|
9
|
+
}
|
|
10
|
+
/** Ed25519 signatures are 64 bytes; trim a trailing recovery byte if one is present. */
|
|
11
|
+
function toEd25519Signature(raw) {
|
|
12
|
+
const trimmed = raw.length === 65 ? raw.slice(0, 64) : raw;
|
|
13
|
+
if (trimmed.length !== 64) {
|
|
14
|
+
throw new Error(`Invalid Ed25519 signature: expected 64 bytes, got ${trimmed.length}`);
|
|
15
|
+
}
|
|
16
|
+
return trimmed;
|
|
17
|
+
}
|
|
18
|
+
/** Solana confirmation needs a wss endpoint; public cluster RPCs serve one at the same host. */
|
|
19
|
+
function deriveWssUrl(rpcUrl) {
|
|
20
|
+
return rpcUrl.replace(/^https?:\/\//, 'wss://');
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A `TransactionSigner` that signs message bytes through the embedded wallet
|
|
24
|
+
* provider (Ed25519). Shared by the native and SPL non-sponsored paths.
|
|
25
|
+
*/
|
|
26
|
+
function createEmbeddedSigner(kit, provider, fromAddress) {
|
|
27
|
+
return {
|
|
28
|
+
address: fromAddress,
|
|
29
|
+
signTransactions: async (transactions) => Promise.all(transactions.map(async (transaction) => {
|
|
30
|
+
const { signature } = await provider.signTransaction({
|
|
31
|
+
messageBytes: new Uint8Array(transaction.messageBytes),
|
|
32
|
+
});
|
|
33
|
+
const bytes = toEd25519Signature(new Uint8Array(kit.getBase58Encoder().encode(signature)));
|
|
34
|
+
return Object.freeze({ [fromAddress]: bytes });
|
|
35
|
+
})),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Build, sign, and broadcast a native SOL transfer. Returns the transaction
|
|
40
|
+
* signature (base58). The wallet pays the network fee — use {@link sendSolGasless}
|
|
41
|
+
* to sponsor it.
|
|
42
|
+
*/
|
|
43
|
+
async function sendSol({ from, to, amountSol, provider, rpcUrl, commitment = 'confirmed', }) {
|
|
44
|
+
const kit = await import('@solana/kit');
|
|
45
|
+
const { getTransferSolInstruction } = await import('@solana-program/system');
|
|
46
|
+
const fromAddress = kit.address(from);
|
|
47
|
+
const rpc = kit.createSolanaRpc(rpcUrl);
|
|
48
|
+
const rpcSubscriptions = kit.createSolanaRpcSubscriptions(deriveWssUrl(rpcUrl));
|
|
49
|
+
const signer = createEmbeddedSigner(kit, provider, fromAddress);
|
|
50
|
+
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
|
|
51
|
+
const message = kit.pipe(kit.createTransactionMessage({ version: 0 }), (tx) => kit.setTransactionMessageFeePayer(fromAddress, tx), (tx) => kit.setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) => kit.appendTransactionMessageInstruction(getTransferSolInstruction({
|
|
52
|
+
source: signer,
|
|
53
|
+
destination: kit.address(to),
|
|
54
|
+
amount: kit.lamports(solToLamports(amountSol)),
|
|
55
|
+
}), tx));
|
|
56
|
+
const signedTransaction = await kit.signTransactionMessageWithSigners(message);
|
|
57
|
+
const sendAndConfirm = kit.sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });
|
|
58
|
+
const abortController = new AbortController();
|
|
59
|
+
const timeout = setTimeout(() => abortController.abort(), SEND_TIMEOUT_MS);
|
|
60
|
+
try {
|
|
61
|
+
await sendAndConfirm(signedTransaction, {
|
|
62
|
+
commitment,
|
|
63
|
+
abortSignal: abortController.signal,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
clearTimeout(timeout);
|
|
68
|
+
}
|
|
69
|
+
return kit.getSignatureFromTransaction(signedTransaction);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Build, sign, and broadcast an SPL token transfer. Creates the recipient's
|
|
73
|
+
* associated token account if it doesn't exist yet (idempotent — a no-op when it
|
|
74
|
+
* already holds the token; the sender pays the small rent). The wallet pays the
|
|
75
|
+
* network fee — use {@link sendSplTokenGasless} to sponsor it. Returns the
|
|
76
|
+
* transaction signature (base58).
|
|
77
|
+
*/
|
|
78
|
+
async function sendSplToken({ from, to, mint, amount, decimals, provider, rpcUrl, commitment = 'confirmed', }) {
|
|
79
|
+
const kit = await import('@solana/kit');
|
|
80
|
+
const token = await import('@solana-program/token');
|
|
81
|
+
const fromAddress = kit.address(from);
|
|
82
|
+
const toAddress = kit.address(to);
|
|
83
|
+
const mintAddress = kit.address(mint);
|
|
84
|
+
const rpc = kit.createSolanaRpc(rpcUrl);
|
|
85
|
+
const rpcSubscriptions = kit.createSolanaRpcSubscriptions(deriveWssUrl(rpcUrl));
|
|
86
|
+
const signer = createEmbeddedSigner(kit, provider, fromAddress);
|
|
87
|
+
const [sourceAta] = await token.findAssociatedTokenPda({
|
|
88
|
+
owner: fromAddress,
|
|
89
|
+
tokenProgram: token.TOKEN_PROGRAM_ADDRESS,
|
|
90
|
+
mint: mintAddress,
|
|
91
|
+
});
|
|
92
|
+
const [destinationAta] = await token.findAssociatedTokenPda({
|
|
93
|
+
owner: toAddress,
|
|
94
|
+
tokenProgram: token.TOKEN_PROGRAM_ADDRESS,
|
|
95
|
+
mint: mintAddress,
|
|
96
|
+
});
|
|
97
|
+
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
|
|
98
|
+
const message = kit.pipe(kit.createTransactionMessage({ version: 0 }), (tx) => kit.setTransactionMessageFeePayer(fromAddress, tx), (tx) => kit.setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, tx), (tx) => kit.appendTransactionMessageInstructions([
|
|
99
|
+
token.getCreateAssociatedTokenIdempotentInstruction({
|
|
100
|
+
payer: signer,
|
|
101
|
+
ata: destinationAta,
|
|
102
|
+
owner: toAddress,
|
|
103
|
+
mint: mintAddress,
|
|
104
|
+
}),
|
|
105
|
+
token.getTransferCheckedInstruction({
|
|
106
|
+
source: sourceAta,
|
|
107
|
+
mint: mintAddress,
|
|
108
|
+
destination: destinationAta,
|
|
109
|
+
authority: signer,
|
|
110
|
+
amount,
|
|
111
|
+
decimals,
|
|
112
|
+
}),
|
|
113
|
+
], tx));
|
|
114
|
+
const signedTransaction = await kit.signTransactionMessageWithSigners(message);
|
|
115
|
+
const sendAndConfirm = kit.sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });
|
|
116
|
+
const abortController = new AbortController();
|
|
117
|
+
const timeout = setTimeout(() => abortController.abort(), SEND_TIMEOUT_MS);
|
|
118
|
+
try {
|
|
119
|
+
await sendAndConfirm(signedTransaction, {
|
|
120
|
+
commitment,
|
|
121
|
+
abortSignal: abortController.signal,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
clearTimeout(timeout);
|
|
126
|
+
}
|
|
127
|
+
return kit.getSignatureFromTransaction(signedTransaction);
|
|
128
|
+
}
|
|
129
|
+
/** The Openfort Solana paymaster (Kora) endpoint for a cluster. */
|
|
130
|
+
function koraRpcUrl(cluster) {
|
|
131
|
+
const segment = cluster === 'mainnet-beta' ? 'mainnet' : cluster;
|
|
132
|
+
return `https://api.openfort.io/rpc/solana/${segment}`;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Sponsor a transfer through the Openfort Solana paymaster (Kora): Kora is the
|
|
136
|
+
* fee payer, the user signs their part with the embedded wallet, and Kora
|
|
137
|
+
* co-signs + broadcasts. Requires a `sponsorSolTransaction` policy on the
|
|
138
|
+
* project. Returns the transaction signature (base58).
|
|
139
|
+
*/
|
|
140
|
+
async function sendViaKora({ from, to, amountBaseUnits, tokenMint, provider, cluster, publishableKey, }) {
|
|
141
|
+
// Kora's request takes a JS number; fail loudly rather than silently corrupt
|
|
142
|
+
// an amount that can't be represented exactly.
|
|
143
|
+
if (amountBaseUnits > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
144
|
+
throw new Error('Amount is too large to sponsor through the paymaster.');
|
|
145
|
+
}
|
|
146
|
+
const kit = await import('@solana/kit');
|
|
147
|
+
const { KoraClient } = await import('@solana/kora');
|
|
148
|
+
const client = new KoraClient({ rpcUrl: koraRpcUrl(cluster), apiKey: `Bearer ${publishableKey}` });
|
|
149
|
+
// 1. Kora's fee-payer signer.
|
|
150
|
+
const { signer_address } = await client.getPayerSigner();
|
|
151
|
+
const feePayer = kit.createNoopSigner(signer_address);
|
|
152
|
+
// 2. A sponsored transfer (native or SPL), with Kora as the fee payer.
|
|
153
|
+
const { instructions } = await client.transferTransaction({
|
|
154
|
+
amount: Number(amountBaseUnits),
|
|
155
|
+
token: tokenMint,
|
|
156
|
+
source: from,
|
|
157
|
+
destination: to,
|
|
158
|
+
signer_key: signer_address,
|
|
159
|
+
});
|
|
160
|
+
// 3. Build the message with Kora as fee payer.
|
|
161
|
+
const { blockhash } = await client.getBlockhash();
|
|
162
|
+
const message = kit.pipe(kit.createTransactionMessage({ version: 0 }), (tx) => kit.setTransactionMessageFeePayerSigner(feePayer, tx), (tx) => kit.setTransactionMessageLifetimeUsingBlockhash({
|
|
163
|
+
blockhash: blockhash,
|
|
164
|
+
lastValidBlockHeight: BigInt(0),
|
|
165
|
+
}, tx), (tx) => kit.appendTransactionMessageInstructions(instructions, tx));
|
|
166
|
+
// 4. Inject the user's Ed25519 signature alongside Kora's placeholder.
|
|
167
|
+
const partiallySigned = await kit.partiallySignTransactionMessageWithSigners(message);
|
|
168
|
+
const { signature } = await provider.signTransaction(new Uint8Array(partiallySigned.messageBytes));
|
|
169
|
+
const userSigned = {
|
|
170
|
+
...partiallySigned,
|
|
171
|
+
signatures: {
|
|
172
|
+
...partiallySigned.signatures,
|
|
173
|
+
[from]: toEd25519Signature(new Uint8Array(kit.getBase58Encoder().encode(signature))),
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
const wire = kit.getBase64EncodedWireTransaction(userSigned);
|
|
177
|
+
// 5. Kora co-signs (as fee payer) and broadcasts.
|
|
178
|
+
const response = (await client.signAndSendTransaction({
|
|
179
|
+
transaction: wire,
|
|
180
|
+
signer_key: signer_address,
|
|
181
|
+
}));
|
|
182
|
+
const direct = response.signature;
|
|
183
|
+
if (direct)
|
|
184
|
+
return direct;
|
|
185
|
+
const signedTxB64 = response.signed_transaction;
|
|
186
|
+
if (signedTxB64) {
|
|
187
|
+
// Wire format: [sigCount(1)][signature(64)]... — the first signature is the tx id.
|
|
188
|
+
const wireBytes = Uint8Array.from(atob(signedTxB64), (c) => c.charCodeAt(0));
|
|
189
|
+
return kit.getBase58Decoder().decode(wireBytes.slice(1, 65));
|
|
190
|
+
}
|
|
191
|
+
throw new Error('Failed to extract transaction signature from the Kora response');
|
|
192
|
+
}
|
|
193
|
+
/** Send a native SOL transfer with fees sponsored by the Openfort paymaster (Kora). */
|
|
194
|
+
async function sendSolGasless({ from, to, amountSol, provider, cluster, publishableKey, }) {
|
|
195
|
+
return sendViaKora({
|
|
196
|
+
from,
|
|
197
|
+
to,
|
|
198
|
+
amountBaseUnits: solToLamports(amountSol),
|
|
199
|
+
tokenMint: SYSTEM_PROGRAM_ID,
|
|
200
|
+
provider,
|
|
201
|
+
cluster,
|
|
202
|
+
publishableKey,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/** Send an SPL token transfer with fees sponsored by the Openfort paymaster (Kora). */
|
|
206
|
+
async function sendSplTokenGasless({ from, to, mint, amount, provider, cluster, publishableKey, }) {
|
|
207
|
+
return sendViaKora({
|
|
208
|
+
from,
|
|
209
|
+
to,
|
|
210
|
+
amountBaseUnits: amount,
|
|
211
|
+
tokenMint: mint,
|
|
212
|
+
provider,
|
|
213
|
+
cluster,
|
|
214
|
+
publishableKey,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export { sendSol, sendSolGasless, sendSplToken, sendSplTokenGasless };
|
|
219
|
+
//# sourceMappingURL=transfer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transfer.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/build/solana/types.d.ts
CHANGED
|
@@ -47,6 +47,14 @@ export type SolanaConfig = {
|
|
|
47
47
|
rpcUrls?: Partial<Record<'mainnet-beta' | 'devnet' | 'testnet', string>>;
|
|
48
48
|
/** Commitment level for transactions (default: 'confirmed') */
|
|
49
49
|
commitment?: SolanaCommitment;
|
|
50
|
+
/**
|
|
51
|
+
* Sponsor network fees for Solana sends through the Openfort paymaster (Kora).
|
|
52
|
+
* The SVM counterpart of `ethereum.ethereumFeeSponsorshipId`: when `true`, sends
|
|
53
|
+
* are routed gaslessly and the confirm screen marks the network fee as sponsored.
|
|
54
|
+
* Requires a `sponsorSolTransaction` policy on the project (resolved server-side
|
|
55
|
+
* from the publishable key). Defaults to `false` (user pays the fee).
|
|
56
|
+
*/
|
|
57
|
+
sponsorFees?: boolean;
|
|
50
58
|
/** UI options for Solana-connected screens */
|
|
51
59
|
ui?: SolanaUIOptions;
|
|
52
60
|
};
|
package/build/utils/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { truncateEthAddress, truncateSolanaAddress } from './format';
|
|
3
3
|
declare const nFormatter: (num: number, digits?: number) => string;
|
|
4
4
|
declare const detectBrowser: () => "" | import("detect-browser").Browser | "bot" | "node" | "react-native";
|
|
5
|
+
declare const isIOS: () => boolean;
|
|
5
6
|
declare const isAndroid: () => boolean;
|
|
6
7
|
declare const isMobile: () => boolean;
|
|
7
8
|
type ReactChildArray = ReturnType<typeof React.Children.toArray>;
|
|
@@ -9,4 +10,4 @@ declare function flattenChildren(children: React.ReactNode): ReactChildArray;
|
|
|
9
10
|
export declare const isWalletConnectConnector: (connectorId?: string) => connectorId is "walletConnect";
|
|
10
11
|
export declare const isCoinbaseWalletConnector: (connectorId?: string) => connectorId is "coinbaseWalletSDK";
|
|
11
12
|
export declare const isInjectedConnector: (connectorId?: string) => connectorId is "injected";
|
|
12
|
-
export { detectBrowser, flattenChildren, isAndroid, isMobile, nFormatter, truncateEthAddress, truncateSolanaAddress };
|
|
13
|
+
export { detectBrowser, flattenChildren, isAndroid, isIOS, isMobile, nFormatter, truncateEthAddress, truncateSolanaAddress, };
|
package/build/utils/index.js
CHANGED
|
@@ -63,5 +63,5 @@ const isWalletConnectConnector = (connectorId) => connectorId === 'walletConnect
|
|
|
63
63
|
const isCoinbaseWalletConnector = (connectorId) => connectorId === 'coinbaseWalletSDK';
|
|
64
64
|
const isInjectedConnector = (connectorId) => connectorId === 'injected';
|
|
65
65
|
|
|
66
|
-
export { detectBrowser, flattenChildren, isAndroid, isCoinbaseWalletConnector, isInjectedConnector, isMobile, isWalletConnectConnector, nFormatter };
|
|
66
|
+
export { detectBrowser, flattenChildren, isAndroid, isCoinbaseWalletConnector, isIOS, isInjectedConnector, isMobile, isWalletConnectConnector, nFormatter };
|
|
67
67
|
//# sourceMappingURL=index.js.map
|
package/build/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const OPENFORT_VERSION = "1.
|
|
1
|
+
export declare const OPENFORT_VERSION = "1.3.0";
|
package/build/version.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { safe, coinbaseWallet, walletConnect } from '@wagmi/connectors';
|
|
1
|
+
import { safe, injected, coinbaseWallet, walletConnect } from '@wagmi/connectors';
|
|
2
2
|
import { embeddedWalletConnector } from './embeddedConnector.js';
|
|
3
3
|
|
|
4
4
|
const defaultConnectors = ({ app, walletConnectProjectId, coinbaseWalletPreference, }) => {
|
|
@@ -10,6 +10,10 @@ const defaultConnectors = ({ app, walletConnectProjectId, coinbaseWalletPreferen
|
|
|
10
10
|
allowedDomains: [/gnosis-safe.io$/, /app.safe.global$/],
|
|
11
11
|
}));
|
|
12
12
|
}
|
|
13
|
+
// Targeted injected connectors so the browser-extension wallets surface as
|
|
14
|
+
// their own entries (e.g. the deposit "transfer from wallet" list), instead of
|
|
15
|
+
// a single generic "Injected" provider.
|
|
16
|
+
connectors.push(injected({ target: 'metaMask' }), injected({ target: 'phantom' }));
|
|
13
17
|
connectors.push(coinbaseWallet({
|
|
14
18
|
appName: app.name,
|
|
15
19
|
appLogoUrl: app.icon,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaultConnectors.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"defaultConnectors.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|