@coin-voyage/crypto 2.5.0 → 2.5.2-beta.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/dist/evm/provider/base-provider.d.ts +2 -1
- package/dist/evm/provider/base-provider.js +2 -2
- package/dist/hooks/use-universal-connect.d.ts +7 -0
- package/dist/hooks/use-universal-connect.js +31 -19
- package/dist/hooks/use-universal-connect.test.d.ts +1 -0
- package/dist/hooks/use-universal-connect.test.js +51 -0
- package/dist/solana/provider/base-provider.d.ts +10 -5
- package/dist/solana/provider/base-provider.js +11 -5
- package/dist/solana/provider/base-provider.test.d.ts +1 -0
- package/dist/solana/provider/base-provider.test.js +24 -0
- package/dist/types/wallet.d.ts +6 -1
- package/dist/wallets/wallet-provider.js +6 -4
- package/package.json +2 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type PropsWithChildren } from "react";
|
|
2
2
|
import { EVMConfiguration } from "../create-default-evm-config";
|
|
3
|
-
export declare function EVMBaseProvider({ children, config, }: PropsWithChildren<{
|
|
3
|
+
export declare function EVMBaseProvider({ children, config, reconnectOnMount, }: PropsWithChildren<{
|
|
4
4
|
config?: EVMConfiguration;
|
|
5
|
+
reconnectOnMount?: boolean;
|
|
5
6
|
}>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { useMemo } from "react";
|
|
3
3
|
import { WagmiProvider } from "wagmi";
|
|
4
4
|
import { createDefaultEVMConfig } from "../create-default-evm-config";
|
|
5
|
-
export function EVMBaseProvider({ children, config, }) {
|
|
5
|
+
export function EVMBaseProvider({ children, config, reconnectOnMount = false, }) {
|
|
6
6
|
const evmConfig = useMemo(() => createDefaultEVMConfig(config), [config]);
|
|
7
|
-
return (_jsx(WagmiProvider, { config: evmConfig.config, reconnectOnMount:
|
|
7
|
+
return (_jsx(WagmiProvider, { config: evmConfig.config, reconnectOnMount: reconnectOnMount, children: children }));
|
|
8
8
|
}
|
|
@@ -11,6 +11,13 @@ interface UseUniversalConnectProps {
|
|
|
11
11
|
connector: any;
|
|
12
12
|
}) => void;
|
|
13
13
|
}
|
|
14
|
+
type SolanaConnectAdapter = {
|
|
15
|
+
connected: boolean;
|
|
16
|
+
connect: () => Promise<void>;
|
|
17
|
+
off: (event: "connect" | "error", listener: (value?: unknown) => void) => unknown;
|
|
18
|
+
once: (event: "connect" | "error", listener: (value?: unknown) => void) => unknown;
|
|
19
|
+
};
|
|
20
|
+
export declare function waitForSolanaWalletConnect(walletAdapter: SolanaConnectAdapter, timeoutMs?: number): Promise<void>;
|
|
14
21
|
export declare const useUniversalConnect: (props?: UseUniversalConnectProps) => {
|
|
15
22
|
connect: ({ walletConnector }: {
|
|
16
23
|
walletConnector: ChainTypeWalletConnector;
|
|
@@ -5,6 +5,36 @@ import { useWallet } from "@solana/wallet-adapter-react";
|
|
|
5
5
|
import { useCallback } from "react";
|
|
6
6
|
import { useConfig as useWagmiConfig, useConnect as useWagmiConnect } from "wagmi";
|
|
7
7
|
import { useLastConnector } from "./use-last-connector";
|
|
8
|
+
const SOLANA_CONNECT_TIMEOUT_MS = 30000;
|
|
9
|
+
export function waitForSolanaWalletConnect(walletAdapter, timeoutMs = SOLANA_CONNECT_TIMEOUT_MS) {
|
|
10
|
+
if (walletAdapter.connected)
|
|
11
|
+
return Promise.resolve();
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
let settled = false;
|
|
14
|
+
let timeoutId;
|
|
15
|
+
const cleanup = () => {
|
|
16
|
+
walletAdapter.off("connect", handleConnect);
|
|
17
|
+
walletAdapter.off("error", handleError);
|
|
18
|
+
if (timeoutId) {
|
|
19
|
+
clearTimeout(timeoutId);
|
|
20
|
+
timeoutId = undefined;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const settle = (callback) => {
|
|
24
|
+
if (settled)
|
|
25
|
+
return;
|
|
26
|
+
settled = true;
|
|
27
|
+
cleanup();
|
|
28
|
+
callback();
|
|
29
|
+
};
|
|
30
|
+
const handleConnect = () => settle(resolve);
|
|
31
|
+
const handleError = (err) => settle(() => reject(err));
|
|
32
|
+
walletAdapter.once("connect", handleConnect);
|
|
33
|
+
walletAdapter.once("error", handleError);
|
|
34
|
+
timeoutId = setTimeout(() => settle(() => reject(new Error("Solana wallet connection timed out"))), timeoutMs);
|
|
35
|
+
walletAdapter.connect().catch(handleError);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
8
38
|
export const useUniversalConnect = (props) => {
|
|
9
39
|
const utxoConfig = useBigmiConfig();
|
|
10
40
|
const evmConfig = useWagmiConfig();
|
|
@@ -63,25 +93,7 @@ export const useUniversalConnect = (props) => {
|
|
|
63
93
|
}
|
|
64
94
|
const walletAdapter = connector;
|
|
65
95
|
select(walletAdapter.name);
|
|
66
|
-
|
|
67
|
-
await new Promise((resolve, reject) => {
|
|
68
|
-
const handleConnect = () => {
|
|
69
|
-
cleanup();
|
|
70
|
-
resolve();
|
|
71
|
-
};
|
|
72
|
-
const handleError = (err) => {
|
|
73
|
-
cleanup();
|
|
74
|
-
reject(err);
|
|
75
|
-
};
|
|
76
|
-
const cleanup = () => {
|
|
77
|
-
walletAdapter.off("connect", handleConnect);
|
|
78
|
-
walletAdapter.off("error", handleError);
|
|
79
|
-
};
|
|
80
|
-
walletAdapter.once("connect", handleConnect);
|
|
81
|
-
walletAdapter.once("error", handleError);
|
|
82
|
-
walletAdapter.connect().catch(handleError);
|
|
83
|
-
});
|
|
84
|
-
}
|
|
96
|
+
await waitForSolanaWalletConnect(walletAdapter);
|
|
85
97
|
updateLastConnectorId(connector, ChainType.SOL);
|
|
86
98
|
onSuccess?.(undefined, { connector: walletAdapter });
|
|
87
99
|
break;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { waitForSolanaWalletConnect } from "./use-universal-connect";
|
|
3
|
+
class FakeSolanaWalletAdapter {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.connected = false;
|
|
6
|
+
this.listeners = new Map();
|
|
7
|
+
this.connect = vi.fn(() => new Promise(() => { }));
|
|
8
|
+
}
|
|
9
|
+
once(event, listener) {
|
|
10
|
+
this.listeners.set(event, new Set([...(this.listeners.get(event) ?? []), listener]));
|
|
11
|
+
return this;
|
|
12
|
+
}
|
|
13
|
+
off(event, listener) {
|
|
14
|
+
this.listeners.get(event)?.delete(listener);
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
emit(event, value) {
|
|
18
|
+
for (const listener of this.listeners.get(event) ?? []) {
|
|
19
|
+
listener(value);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
listenerCount(event) {
|
|
23
|
+
return this.listeners.get(event)?.size ?? 0;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
describe("waitForSolanaWalletConnect", () => {
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
vi.useRealTimers();
|
|
29
|
+
});
|
|
30
|
+
it("removes listeners when a wallet connect attempt times out", async () => {
|
|
31
|
+
vi.useFakeTimers();
|
|
32
|
+
const adapter = new FakeSolanaWalletAdapter();
|
|
33
|
+
const result = waitForSolanaWalletConnect(adapter, 100);
|
|
34
|
+
expect(adapter.listenerCount("connect")).toBe(1);
|
|
35
|
+
expect(adapter.listenerCount("error")).toBe(1);
|
|
36
|
+
const rejection = expect(result).rejects.toThrow("Solana wallet connection timed out");
|
|
37
|
+
await vi.advanceTimersByTimeAsync(100);
|
|
38
|
+
await rejection;
|
|
39
|
+
expect(adapter.listenerCount("connect")).toBe(0);
|
|
40
|
+
expect(adapter.listenerCount("error")).toBe(0);
|
|
41
|
+
});
|
|
42
|
+
it("removes listeners after a successful wallet connect event", async () => {
|
|
43
|
+
vi.useFakeTimers();
|
|
44
|
+
const adapter = new FakeSolanaWalletAdapter();
|
|
45
|
+
const result = waitForSolanaWalletConnect(adapter, 100);
|
|
46
|
+
adapter.emit("connect");
|
|
47
|
+
await expect(result).resolves.toBeUndefined();
|
|
48
|
+
expect(adapter.listenerCount("connect")).toBe(0);
|
|
49
|
+
expect(adapter.listenerCount("error")).toBe(0);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
import { type Adapter } from "@solana/wallet-adapter-base";
|
|
1
2
|
import { type PropsWithChildren } from "react";
|
|
2
|
-
import { WalletConnectParameters } from "wagmi/connectors";
|
|
3
3
|
import { SolanaConfiguration } from "../../types/wallet";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
interface BuildSolanaWalletsOptions {
|
|
5
|
+
configuredWallets?: Adapter[];
|
|
6
|
+
defaultWallets?: readonly Adapter[];
|
|
7
|
+
walletConnectWallet: Adapter;
|
|
8
|
+
}
|
|
9
|
+
export declare function buildSolanaWallets({ configuredWallets, defaultWallets, walletConnectWallet, }: BuildSolanaWalletsOptions): Adapter[];
|
|
10
|
+
export declare function SolanaBaseProvider({ children, config }: PropsWithChildren<{
|
|
11
|
+
config?: SolanaConfiguration;
|
|
8
12
|
}>): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -5,11 +5,17 @@ import { ConnectionProvider, WalletProvider } from "@solana/wallet-adapter-react
|
|
|
5
5
|
import { WalletConnectWalletAdapter } from "@solana/wallet-adapter-walletconnect";
|
|
6
6
|
import { useMemo } from "react";
|
|
7
7
|
const DEFAULT_SOLANA_RPC = "https://solana-mainnet.g.alchemy.com/v2/vPIG6RGK7rUDSwR1MHfEgXlZ2acwA4MG";
|
|
8
|
-
const
|
|
9
|
-
export function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
const DEFAULT_WALLETS = [new CoinbaseWalletAdapter()];
|
|
9
|
+
export function buildSolanaWallets({ configuredWallets = [], defaultWallets = DEFAULT_WALLETS, walletConnectWallet, }) {
|
|
10
|
+
return [...configuredWallets, ...defaultWallets, walletConnectWallet];
|
|
11
|
+
}
|
|
12
|
+
export function SolanaBaseProvider({ children, config }) {
|
|
13
|
+
const walletConnectWallet = useMemo(() => getWalletConnectConnector(config?.walletConnect), [config?.walletConnect]);
|
|
14
|
+
const wallets = useMemo(() => buildSolanaWallets({
|
|
15
|
+
configuredWallets: config?.walletConfiguration?.wallets,
|
|
16
|
+
walletConnectWallet,
|
|
17
|
+
}), [config?.walletConfiguration?.wallets, walletConnectWallet]);
|
|
18
|
+
return (_jsx(ConnectionProvider, { endpoint: config?.rpcUrl ?? DEFAULT_SOLANA_RPC, children: _jsx(WalletProvider, { ...config?.walletConfiguration, localStorageKey: config?.walletConfiguration?.localStorageKey || "@coin-voyage/solana-wallet", autoConnect: config?.walletConfiguration?.autoConnect, wallets: wallets, children: children }) }));
|
|
13
19
|
}
|
|
14
20
|
function getWalletConnectConnector(params) {
|
|
15
21
|
return new WalletConnectWalletAdapter({
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { buildSolanaWallets } from "./base-provider";
|
|
3
|
+
const createAdapter = (name) => ({ name });
|
|
4
|
+
describe("buildSolanaWallets", () => {
|
|
5
|
+
it("does not mutate the default wallet list across repeated builds", () => {
|
|
6
|
+
const configuredWallet = createAdapter("Configured");
|
|
7
|
+
const coinbaseWallet = createAdapter("Coinbase");
|
|
8
|
+
const walletConnectWallet = createAdapter("WalletConnect");
|
|
9
|
+
const defaultWallets = [coinbaseWallet];
|
|
10
|
+
const firstWallets = buildSolanaWallets({
|
|
11
|
+
configuredWallets: [configuredWallet],
|
|
12
|
+
defaultWallets,
|
|
13
|
+
walletConnectWallet,
|
|
14
|
+
});
|
|
15
|
+
const secondWallets = buildSolanaWallets({
|
|
16
|
+
configuredWallets: [configuredWallet],
|
|
17
|
+
defaultWallets,
|
|
18
|
+
walletConnectWallet,
|
|
19
|
+
});
|
|
20
|
+
expect(firstWallets).toEqual([configuredWallet, coinbaseWallet, walletConnectWallet]);
|
|
21
|
+
expect(secondWallets).toEqual(firstWallets);
|
|
22
|
+
expect(defaultWallets).toEqual([coinbaseWallet]);
|
|
23
|
+
});
|
|
24
|
+
});
|
package/dist/types/wallet.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { ChainId, ChainType } from "@coin-voyage/shared/types";
|
|
2
2
|
import type { createDAppKit } from "@mysten/dapp-kit-react";
|
|
3
|
+
import { Adapter } from "@solana/wallet-adapter-base";
|
|
3
4
|
import type { WalletProviderProps } from "@solana/wallet-adapter-react";
|
|
5
|
+
import { WalletConnectParameters } from "wagmi/connectors";
|
|
4
6
|
import type { EVMConfiguration } from "../evm/create-default-evm-config";
|
|
5
7
|
import type { UTXOConfiguration } from "../utxo/create-default-utxo-config";
|
|
6
8
|
import type { WalletConnector } from "./wallet-connector";
|
|
@@ -24,7 +26,10 @@ export type WalletConfiguration = {
|
|
|
24
26
|
*/
|
|
25
27
|
export type SolanaConfiguration = {
|
|
26
28
|
rpcUrl?: string;
|
|
27
|
-
walletConfiguration?: Omit<WalletProviderProps, "children"
|
|
29
|
+
walletConfiguration?: Omit<WalletProviderProps, "children" | "wallets"> & {
|
|
30
|
+
wallets?: Adapter[];
|
|
31
|
+
};
|
|
32
|
+
walletConnect?: WalletConnectParameters;
|
|
28
33
|
};
|
|
29
34
|
type SuiDAppKitOptions = Parameters<typeof createDAppKit>[0];
|
|
30
35
|
export type SuiDAppKitConfiguration = Pick<SuiDAppKitOptions, "autoConnect" | "enableBurnerWallet" | "slushWalletConfig" | "storage" | "storageKey" | "walletInitializers">;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
2
3
|
import { EVMProvider } from "../evm/provider/provider";
|
|
3
4
|
import { QueryProvider } from "../query/provider";
|
|
4
5
|
import { SolanaProvider } from "../solana/provider/provider";
|
|
5
6
|
import { SuiProvider } from "../sui/provider/provider";
|
|
6
7
|
import { UTXOProvider } from "../utxo/provider/provider";
|
|
7
8
|
export function WalletProvider({ children, config, }) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const solanaConfig = useMemo(() => ({
|
|
10
|
+
...config?.solana,
|
|
11
|
+
walletConnect: config?.evm?.walletConnect,
|
|
12
|
+
}), [config?.solana, config?.evm?.walletConnect]);
|
|
13
|
+
return (_jsx(QueryProvider, { children: _jsx(EVMProvider, { config: config?.evm, children: _jsx(SolanaProvider, { config: solanaConfig, children: _jsx(UTXOProvider, { config: config?.utxo, children: _jsx(SuiProvider, { config: config?.sui, children: children }) }) }) }) }));
|
|
12
14
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coin-voyage/crypto",
|
|
3
3
|
"description": "Crypto utilities for Coin Voyage",
|
|
4
|
-
"version": "2.5.0",
|
|
4
|
+
"version": "2.5.2-beta.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"author": "Lars <lars@coinvoyage.io>",
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"@solana/wallet-adapter-walletconnect": "0.1.21",
|
|
113
113
|
"@solana/wallet-adapter-base": "0.9.27",
|
|
114
114
|
"@solana/wallet-adapter-coinbase": "0.1.23",
|
|
115
|
-
"@coin-voyage/shared": "2.5.
|
|
115
|
+
"@coin-voyage/shared": "2.5.1-beta.3"
|
|
116
116
|
},
|
|
117
117
|
"devDependencies": {
|
|
118
118
|
"@types/elliptic": "6.4.18"
|