thirdweb 5.75.0 → 5.76.0-nightly-015293eb826b346871696183e96d49da44f31393-20241209000527
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/cjs/exports/react.js.map +1 -1
- package/dist/cjs/exports/utils.js +5 -1
- package/dist/cjs/exports/utils.js.map +1 -1
- package/dist/cjs/pay/convert/cryptoToFiat.js.map +1 -1
- package/dist/cjs/pay/convert/fiatToCrypto.js +1 -1
- package/dist/cjs/pay/convert/fiatToCrypto.js.map +1 -1
- package/dist/cjs/pay/convert/type.js +4 -0
- package/dist/cjs/pay/convert/type.js.map +1 -0
- package/dist/cjs/react/web/ui/ConnectWallet/Details.js +56 -16
- package/dist/cjs/react/web/ui/ConnectWallet/Details.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/ReceiveFunds.js +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/ReceiveFunds.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/SendFunds.js +3 -2
- package/dist/cjs/react/web/ui/ConnectWallet/screens/SendFunds.js.map +1 -1
- package/dist/cjs/react/web/ui/components/CopyIcon.js +1 -1
- package/dist/cjs/react/web/ui/components/CopyIcon.js.map +1 -1
- package/dist/cjs/react/web/ui/components/Skeleton.js +1 -1
- package/dist/cjs/react/web/ui/components/Skeleton.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/Account/balance.js +114 -26
- package/dist/cjs/react/web/ui/prebuilt/Account/balance.js.map +1 -1
- package/dist/cjs/react/web/ui/prebuilt/Account/provider.js +3 -0
- package/dist/cjs/react/web/ui/prebuilt/Account/provider.js.map +1 -1
- package/dist/cjs/utils/formatNumber.js +7 -1
- package/dist/cjs/utils/formatNumber.js.map +1 -1
- package/dist/cjs/utils/shortenLargeNumber.js +47 -0
- package/dist/cjs/utils/shortenLargeNumber.js.map +1 -0
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/version.js.map +1 -1
- package/dist/cjs/wallets/manager/index.js +35 -24
- package/dist/cjs/wallets/manager/index.js.map +1 -1
- package/dist/esm/exports/react.js.map +1 -1
- package/dist/esm/exports/utils.js +2 -0
- package/dist/esm/exports/utils.js.map +1 -1
- package/dist/esm/pay/convert/cryptoToFiat.js.map +1 -1
- package/dist/esm/pay/convert/fiatToCrypto.js +1 -1
- package/dist/esm/pay/convert/fiatToCrypto.js.map +1 -1
- package/dist/esm/pay/convert/type.js +3 -0
- package/dist/esm/pay/convert/type.js.map +1 -0
- package/dist/esm/react/web/ui/ConnectWallet/Details.js +57 -23
- package/dist/esm/react/web/ui/ConnectWallet/Details.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/ReceiveFunds.js +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/ReceiveFunds.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/SendFunds.js +3 -3
- package/dist/esm/react/web/ui/ConnectWallet/screens/SendFunds.js.map +1 -1
- package/dist/esm/react/web/ui/components/CopyIcon.js +1 -1
- package/dist/esm/react/web/ui/components/CopyIcon.js.map +1 -1
- package/dist/esm/react/web/ui/components/Skeleton.js +1 -1
- package/dist/esm/react/web/ui/components/Skeleton.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/Account/balance.js +113 -28
- package/dist/esm/react/web/ui/prebuilt/Account/balance.js.map +1 -1
- package/dist/esm/react/web/ui/prebuilt/Account/provider.js +3 -0
- package/dist/esm/react/web/ui/prebuilt/Account/provider.js.map +1 -1
- package/dist/esm/utils/formatNumber.js +7 -1
- package/dist/esm/utils/formatNumber.js.map +1 -1
- package/dist/esm/utils/shortenLargeNumber.js +44 -0
- package/dist/esm/utils/shortenLargeNumber.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/esm/wallets/manager/index.js +33 -24
- package/dist/esm/wallets/manager/index.js.map +1 -1
- package/dist/types/exports/react.d.ts +1 -1
- package/dist/types/exports/react.d.ts.map +1 -1
- package/dist/types/exports/utils.d.ts +2 -0
- package/dist/types/exports/utils.d.ts.map +1 -1
- package/dist/types/pay/convert/cryptoToFiat.d.ts +2 -1
- package/dist/types/pay/convert/cryptoToFiat.d.ts.map +1 -1
- package/dist/types/pay/convert/fiatToCrypto.d.ts +2 -1
- package/dist/types/pay/convert/fiatToCrypto.d.ts.map +1 -1
- package/dist/types/pay/convert/type.d.ts +7 -0
- package/dist/types/pay/convert/type.d.ts.map +1 -0
- package/dist/types/react/core/hooks/connection/ConnectButtonProps.d.ts +11 -0
- package/dist/types/react/core/hooks/connection/ConnectButtonProps.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/Details.d.ts +60 -0
- package/dist/types/react/web/ui/ConnectWallet/Details.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/screens/ReceiveFunds.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/screens/SendFunds.d.ts +15 -0
- package/dist/types/react/web/ui/ConnectWallet/screens/SendFunds.d.ts.map +1 -1
- package/dist/types/react/web/ui/components/CopyIcon.d.ts.map +1 -1
- package/dist/types/react/web/ui/components/Skeleton.d.ts +1 -0
- package/dist/types/react/web/ui/components/Skeleton.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/Account/balance.d.ts +58 -9
- package/dist/types/react/web/ui/prebuilt/Account/balance.d.ts.map +1 -1
- package/dist/types/react/web/ui/prebuilt/Account/provider.d.ts.map +1 -1
- package/dist/types/utils/formatNumber.d.ts +7 -1
- package/dist/types/utils/formatNumber.d.ts.map +1 -1
- package/dist/types/utils/shortenLargeNumber.d.ts +16 -0
- package/dist/types/utils/shortenLargeNumber.d.ts.map +1 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/types/version.d.ts.map +1 -1
- package/dist/types/wallets/manager/index.d.ts +4 -0
- package/dist/types/wallets/manager/index.d.ts.map +1 -1
- package/dist/types/wallets/wallet-connect/types.d.ts +1 -1
- package/dist/types/wallets/wallet-connect/types.d.ts.map +1 -1
- package/dist/types/wallets/wallet-types.d.ts +1 -1
- package/package.json +7 -6
- package/src/exports/react.ts +1 -0
- package/src/exports/utils.ts +3 -0
- package/src/pay/convert/cryptoToFiat.test.ts +21 -1
- package/src/pay/convert/cryptoToFiat.ts +2 -1
- package/src/pay/convert/fiatToCrypto.test.ts +21 -1
- package/src/pay/convert/fiatToCrypto.ts +3 -2
- package/src/pay/convert/type.ts +5 -0
- package/src/react/core/hooks/connection/ConnectButtonProps.ts +13 -0
- package/src/react/web/ui/ConnectWallet/ConnectButton.test.tsx +15 -0
- package/src/react/web/ui/ConnectWallet/Details.test.tsx +587 -0
- package/src/react/web/ui/ConnectWallet/Details.tsx +174 -67
- package/src/react/web/ui/ConnectWallet/screens/PrivateKey.test.tsx +54 -0
- package/src/react/web/ui/ConnectWallet/screens/ReceiveFunds.test.tsx +37 -0
- package/src/react/web/ui/ConnectWallet/screens/ReceiveFunds.tsx +6 -1
- package/src/react/web/ui/ConnectWallet/screens/SendFunds.test.tsx +67 -0
- package/src/react/web/ui/ConnectWallet/screens/SendFunds.tsx +3 -2
- package/src/react/web/ui/ConnectWallet/screens/StartScreen.test.tsx +71 -0
- package/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.test.ts +60 -0
- package/src/react/web/ui/ConnectWallet/screens/nativeToken.test.ts +42 -0
- package/src/react/web/ui/components/CopyIcon.tsx +5 -1
- package/src/react/web/ui/components/Skeleton.tsx +2 -0
- package/src/react/web/ui/prebuilt/Account/balance.test.tsx +167 -36
- package/src/react/web/ui/prebuilt/Account/balance.tsx +168 -28
- package/src/react/web/ui/prebuilt/Account/provider.test.tsx +16 -0
- package/src/react/web/ui/prebuilt/Account/provider.tsx +5 -0
- package/src/utils/formatNumber.ts +7 -1
- package/src/utils/shortenLargeNumber.test.ts +30 -0
- package/src/utils/shortenLargeNumber.ts +48 -0
- package/src/version.ts +1 -1
- package/src/wallets/manager/connection-manager.test.ts +290 -3
- package/src/wallets/manager/index.ts +45 -32
- package/src/wallets/wallet-connect/receiver/receiver.test.ts +1 -1
- package/src/wallets/wallet-connect/types.ts +1 -1
- package/src/wallets/wallet-types.ts +1 -1
@@ -0,0 +1,30 @@
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
2
|
+
import { shortenLargeNumber } from "./shortenLargeNumber.js";
|
3
|
+
|
4
|
+
describe("shortenLargeNumber", () => {
|
5
|
+
it("should not affect number below 999", () => {
|
6
|
+
expect(shortenLargeNumber(999)).toBe("999");
|
7
|
+
});
|
8
|
+
it("should toLocaleString number below 10000", () => {
|
9
|
+
expect(shortenLargeNumber(1000)).toBe("1,000");
|
10
|
+
expect(shortenLargeNumber(9999)).toBe("9,999");
|
11
|
+
});
|
12
|
+
it("should shorten the number to `k`", () => {
|
13
|
+
expect(shortenLargeNumber(10000)).toBe("10k");
|
14
|
+
});
|
15
|
+
it("should shorten the number to `M`", () => {
|
16
|
+
expect(shortenLargeNumber(1_000_000)).toBe("1M");
|
17
|
+
});
|
18
|
+
it("should shorten the number to `B`", () => {
|
19
|
+
expect(shortenLargeNumber(1_000_000_000)).toBe("1B");
|
20
|
+
});
|
21
|
+
it("should shorten the number to `k`", () => {
|
22
|
+
expect(shortenLargeNumber(11100)).toBe("11.1k");
|
23
|
+
});
|
24
|
+
it("should shorten the number to `M`", () => {
|
25
|
+
expect(shortenLargeNumber(1_100_000)).toBe("1.1M");
|
26
|
+
});
|
27
|
+
it("should shorten the number to `B`", () => {
|
28
|
+
expect(shortenLargeNumber(1_100_000_001)).toBe("1.1B");
|
29
|
+
});
|
30
|
+
});
|
@@ -0,0 +1,48 @@
|
|
1
|
+
/**
|
2
|
+
* Shorten the string for large value
|
3
|
+
* Mainly used for
|
4
|
+
* Examples:
|
5
|
+
* 10_000 -> 10k
|
6
|
+
* 1_000_000 -> 1M
|
7
|
+
* 1_000_000_000 -> 1B
|
8
|
+
* @example
|
9
|
+
* ```ts
|
10
|
+
* import { shortenLargeNumber } from "thirdweb/utils";
|
11
|
+
* const numStr = shortenLargeNumber(1_000_000_000, )
|
12
|
+
* ```
|
13
|
+
* @utils
|
14
|
+
*/
|
15
|
+
export function shortenLargeNumber(value: number) {
|
16
|
+
if (value < 1000) {
|
17
|
+
return value.toString();
|
18
|
+
}
|
19
|
+
if (value < 10_000) {
|
20
|
+
return value.toLocaleString("en-US");
|
21
|
+
}
|
22
|
+
if (value < 1_000_000) {
|
23
|
+
return formatLargeNumber(value, 1_000, "k");
|
24
|
+
}
|
25
|
+
if (value < 1_000_000_000) {
|
26
|
+
return formatLargeNumber(value, 1_000_000, "M");
|
27
|
+
}
|
28
|
+
return formatLargeNumber(value, 1_000_000_000, "B");
|
29
|
+
}
|
30
|
+
|
31
|
+
/**
|
32
|
+
* Shorten the string for large value (over 4 digits)
|
33
|
+
* 1000 -> 1000
|
34
|
+
* 10_000 -> 10k
|
35
|
+
* 1_000_000 -> 1M
|
36
|
+
* 1_000_000_000 -> 1B
|
37
|
+
*/
|
38
|
+
function formatLargeNumber(
|
39
|
+
value: number,
|
40
|
+
divisor: number,
|
41
|
+
suffix: "k" | "M" | "B",
|
42
|
+
) {
|
43
|
+
const quotient = value / divisor;
|
44
|
+
if (Number.isInteger(quotient)) {
|
45
|
+
return Math.floor(quotient) + suffix;
|
46
|
+
}
|
47
|
+
return quotient.toFixed(1).replace(/\.0$/, "") + suffix;
|
48
|
+
}
|
package/src/version.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export const version = "5.
|
1
|
+
export const version = "5.76.0-nightly-015293eb826b346871696183e96d49da44f31393-20241209000527";
|
@@ -6,7 +6,10 @@ import type { ThirdwebClient } from "../../client/client.js";
|
|
6
6
|
import type { AsyncStorage } from "../../utils/storage/AsyncStorage.js";
|
7
7
|
import type { Account, Wallet } from "../interfaces/wallet.js";
|
8
8
|
import type { SmartWalletOptions } from "../smart/types.js";
|
9
|
-
import {
|
9
|
+
import {
|
10
|
+
createConnectionManager,
|
11
|
+
handleSmartWalletConnection,
|
12
|
+
} from "./index.js";
|
10
13
|
|
11
14
|
describe.runIf(process.env.TW_SECRET_KEY)("Connection Manager", () => {
|
12
15
|
let storage: AsyncStorage;
|
@@ -26,7 +29,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("Connection Manager", () => {
|
|
26
29
|
wallet = {
|
27
30
|
id: "wallet-id",
|
28
31
|
getAccount: vi.fn().mockReturnValue(account),
|
29
|
-
subscribe: vi.fn(),
|
32
|
+
subscribe: vi.fn().mockReturnValue(vi.fn()),
|
30
33
|
disconnect: vi.fn(),
|
31
34
|
switchChain: vi.fn(),
|
32
35
|
getChain: vi.fn().mockReturnValue(sepolia),
|
@@ -44,7 +47,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("Connection Manager", () => {
|
|
44
47
|
await manager.connect(wallet, { client, onConnect });
|
45
48
|
|
46
49
|
expect(onConnect).toHaveBeenCalledWith(wallet);
|
47
|
-
expect(storage.setItem).
|
50
|
+
expect(storage.setItem).toHaveBeenCalled();
|
48
51
|
});
|
49
52
|
|
50
53
|
it("handleConnection should connect smart wallet", async () => {
|
@@ -65,4 +68,288 @@ describe.runIf(process.env.TW_SECRET_KEY)("Connection Manager", () => {
|
|
65
68
|
|
66
69
|
expect(manager.connectedWallets.getValue()).toContain(wallet);
|
67
70
|
});
|
71
|
+
|
72
|
+
it("should disconnect the active wallet when the EOA disconnects", async () => {
|
73
|
+
const manager = createConnectionManager(storage);
|
74
|
+
|
75
|
+
const smartWallet = await manager.handleConnection(wallet, {
|
76
|
+
client,
|
77
|
+
accountAbstraction: smartWalletOptions,
|
78
|
+
});
|
79
|
+
|
80
|
+
expect(manager.activeWalletStore.getValue()).toBe(smartWallet);
|
81
|
+
|
82
|
+
await wallet.disconnect();
|
83
|
+
|
84
|
+
expect(wallet.subscribe).toHaveBeenCalledWith(
|
85
|
+
"disconnect",
|
86
|
+
expect.any(Function),
|
87
|
+
);
|
88
|
+
});
|
89
|
+
|
90
|
+
it("should clear active wallet data on disconnect", async () => {
|
91
|
+
const manager = createConnectionManager(storage);
|
92
|
+
|
93
|
+
await manager.handleConnection(wallet, { client });
|
94
|
+
|
95
|
+
// Simulate wallet disconnect
|
96
|
+
manager.disconnectWallet(wallet);
|
97
|
+
|
98
|
+
expect(storage.removeItem).toHaveBeenCalledWith(
|
99
|
+
"thirdweb:active-wallet-id",
|
100
|
+
);
|
101
|
+
expect(manager.activeAccountStore.getValue()).toBeUndefined();
|
102
|
+
expect(manager.activeWalletChainStore.getValue()).toBeUndefined();
|
103
|
+
expect(manager.activeWalletStore.getValue()).toBeUndefined();
|
104
|
+
expect(manager.activeWalletConnectionStatusStore.getValue()).toBe(
|
105
|
+
"disconnected",
|
106
|
+
);
|
107
|
+
});
|
108
|
+
|
109
|
+
it("should throw an error if wallet has no account", async () => {
|
110
|
+
const manager = createConnectionManager(storage);
|
111
|
+
|
112
|
+
wallet = {
|
113
|
+
id: "wallet-id",
|
114
|
+
getAccount: vi.fn().mockReturnValue(null),
|
115
|
+
subscribe: vi.fn(),
|
116
|
+
disconnect: vi.fn(),
|
117
|
+
switchChain: vi.fn(),
|
118
|
+
getChain: vi.fn().mockReturnValue(sepolia),
|
119
|
+
getConfig: vi.fn(),
|
120
|
+
} as unknown as Wallet;
|
121
|
+
|
122
|
+
await expect(manager.handleConnection(wallet, { client })).rejects.toThrow(
|
123
|
+
"Cannot set a wallet without an account as active",
|
124
|
+
);
|
125
|
+
});
|
126
|
+
|
127
|
+
it("should set active wallet and update storage", async () => {
|
128
|
+
const manager = createConnectionManager(storage);
|
129
|
+
|
130
|
+
await manager.setActiveWallet(wallet);
|
131
|
+
|
132
|
+
expect(manager.activeWalletStore.getValue()).toBe(wallet);
|
133
|
+
expect(storage.setItem).toHaveBeenCalledWith(
|
134
|
+
"thirdweb:active-wallet-id",
|
135
|
+
wallet.id,
|
136
|
+
);
|
137
|
+
});
|
138
|
+
|
139
|
+
it("should switch active wallet chain", async () => {
|
140
|
+
const manager = createConnectionManager(storage);
|
141
|
+
|
142
|
+
await manager.handleConnection(wallet, { client });
|
143
|
+
|
144
|
+
const newChain = {
|
145
|
+
id: 2,
|
146
|
+
name: "New Chain",
|
147
|
+
rpc: "https://rpc.example.com",
|
148
|
+
};
|
149
|
+
|
150
|
+
// Mock the switchChain method to update the activeWalletChainStore
|
151
|
+
wallet.switchChain = vi.fn().mockImplementation((chain) => {
|
152
|
+
manager.activeWalletChainStore.setValue(chain);
|
153
|
+
});
|
154
|
+
|
155
|
+
await manager.switchActiveWalletChain(newChain);
|
156
|
+
|
157
|
+
expect(wallet.switchChain).toHaveBeenCalledWith(newChain);
|
158
|
+
});
|
159
|
+
|
160
|
+
it("should define chains", async () => {
|
161
|
+
const manager = createConnectionManager(storage);
|
162
|
+
await manager.handleConnection(wallet, { client });
|
163
|
+
|
164
|
+
const chains = [
|
165
|
+
{ id: 1, name: "Chain 1", rpc: "https://rpc1.example.com" },
|
166
|
+
{ id: 2, name: "Chain 2", rpc: "https://rpc2.example.com" },
|
167
|
+
];
|
168
|
+
manager.defineChains(chains);
|
169
|
+
|
170
|
+
const activeWalletChain = manager.activeWalletChainStore.getValue();
|
171
|
+
expect(activeWalletChain).toBeDefined();
|
172
|
+
});
|
173
|
+
|
174
|
+
it("should remove connected wallet", () => {
|
175
|
+
const manager = createConnectionManager(storage);
|
176
|
+
|
177
|
+
manager.addConnectedWallet(wallet);
|
178
|
+
expect(manager.connectedWallets.getValue()).toContain(wallet);
|
179
|
+
|
180
|
+
manager.removeConnectedWallet(wallet);
|
181
|
+
expect(manager.connectedWallets.getValue()).not.toContain(wallet);
|
182
|
+
});
|
183
|
+
|
184
|
+
it("should update active wallet chain to a defined chain", async () => {
|
185
|
+
const manager = createConnectionManager(storage);
|
186
|
+
|
187
|
+
// Connect the wallet to initialize the active wallet chain
|
188
|
+
await manager.handleConnection(wallet, { client });
|
189
|
+
|
190
|
+
// Define a new chain and update the definedChainsStore
|
191
|
+
const newChain = {
|
192
|
+
id: 11155111,
|
193
|
+
name: "New Defined Chain",
|
194
|
+
rpc: "https://rpc3.example.com",
|
195
|
+
};
|
196
|
+
manager.defineChains([newChain]);
|
197
|
+
|
198
|
+
// Simulate the effect that updates the active wallet chain
|
199
|
+
const definedChain = manager.activeWalletChainStore.getValue();
|
200
|
+
expect(definedChain).toEqual(newChain);
|
201
|
+
});
|
202
|
+
});
|
203
|
+
|
204
|
+
describe("handleSmartWalletConnection", () => {
|
205
|
+
let client: ThirdwebClient;
|
206
|
+
let eoaWallet: Wallet;
|
207
|
+
let smartWalletOptions: SmartWalletOptions;
|
208
|
+
|
209
|
+
beforeEach(() => {
|
210
|
+
client = TEST_CLIENT;
|
211
|
+
eoaWallet = {
|
212
|
+
id: "eoa-wallet-id",
|
213
|
+
getAccount: vi.fn().mockReturnValue(TEST_ACCOUNT_A),
|
214
|
+
subscribe: vi.fn().mockReturnValue(vi.fn()),
|
215
|
+
disconnect: vi.fn(),
|
216
|
+
switchChain: vi.fn(),
|
217
|
+
getChain: vi.fn().mockReturnValue(sepolia),
|
218
|
+
getConfig: vi.fn(),
|
219
|
+
} as unknown as Wallet;
|
220
|
+
smartWalletOptions = {
|
221
|
+
chain: sepolia,
|
222
|
+
} as SmartWalletOptions;
|
223
|
+
});
|
224
|
+
|
225
|
+
it("should connect a smart wallet and subscribe to disconnect event", async () => {
|
226
|
+
const onWalletDisconnect = vi.fn();
|
227
|
+
const smartWallet = await handleSmartWalletConnection(
|
228
|
+
eoaWallet,
|
229
|
+
client,
|
230
|
+
smartWalletOptions,
|
231
|
+
onWalletDisconnect,
|
232
|
+
);
|
233
|
+
|
234
|
+
expect(smartWallet.getAccount()).toBeTruthy();
|
235
|
+
|
236
|
+
expect(eoaWallet.subscribe).toHaveBeenCalledWith(
|
237
|
+
"disconnect",
|
238
|
+
expect.any(Function),
|
239
|
+
);
|
240
|
+
});
|
241
|
+
|
242
|
+
it("should call onWalletDisconnect when EOA wallet disconnects", async () => {
|
243
|
+
const onWalletDisconnect = vi.fn();
|
244
|
+
const smartWallet = await handleSmartWalletConnection(
|
245
|
+
eoaWallet,
|
246
|
+
client,
|
247
|
+
smartWalletOptions,
|
248
|
+
onWalletDisconnect,
|
249
|
+
);
|
250
|
+
|
251
|
+
// biome-ignore lint/suspicious/noExplicitAny: Mocked function
|
252
|
+
const disconnectCallback = (eoaWallet.subscribe as any).mock.calls[0][1];
|
253
|
+
disconnectCallback();
|
254
|
+
|
255
|
+
expect(onWalletDisconnect).toHaveBeenCalledWith(smartWallet);
|
256
|
+
});
|
257
|
+
|
258
|
+
it("should throw an error if EOA wallet has no account", async () => {
|
259
|
+
eoaWallet.getAccount = vi.fn().mockReturnValue(null);
|
260
|
+
|
261
|
+
await expect(
|
262
|
+
handleSmartWalletConnection(
|
263
|
+
eoaWallet,
|
264
|
+
client,
|
265
|
+
smartWalletOptions,
|
266
|
+
vi.fn(),
|
267
|
+
),
|
268
|
+
).rejects.toThrow("Cannot set a wallet without an account as active");
|
269
|
+
});
|
270
|
+
});
|
271
|
+
|
272
|
+
describe("Connection Manager Error Handling", () => {
|
273
|
+
let storage: AsyncStorage;
|
274
|
+
let client: ThirdwebClient;
|
275
|
+
let wallet: Wallet;
|
276
|
+
|
277
|
+
beforeEach(() => {
|
278
|
+
storage = {
|
279
|
+
getItem: vi.fn(),
|
280
|
+
setItem: vi.fn(),
|
281
|
+
removeItem: vi.fn(),
|
282
|
+
};
|
283
|
+
client = TEST_CLIENT;
|
284
|
+
wallet = {
|
285
|
+
id: "wallet-id",
|
286
|
+
getAccount: vi.fn().mockReturnValue(null), // Simulate wallet without an account
|
287
|
+
subscribe: vi.fn(),
|
288
|
+
disconnect: vi.fn(),
|
289
|
+
switchChain: vi.fn(),
|
290
|
+
getChain: vi.fn().mockReturnValue(sepolia),
|
291
|
+
getConfig: vi.fn(),
|
292
|
+
} as unknown as Wallet;
|
293
|
+
});
|
294
|
+
|
295
|
+
it("should throw an error if trying to set a wallet without an account as active", async () => {
|
296
|
+
const manager = createConnectionManager(storage);
|
297
|
+
|
298
|
+
await expect(manager.setActiveWallet(wallet)).rejects.toThrow(
|
299
|
+
"Cannot set a wallet without an account as active",
|
300
|
+
);
|
301
|
+
});
|
302
|
+
|
303
|
+
it("should throw an error if handleConnection is called with a wallet without an account", async () => {
|
304
|
+
const manager = createConnectionManager(storage);
|
305
|
+
|
306
|
+
await expect(manager.handleConnection(wallet, { client })).rejects.toThrow(
|
307
|
+
"Cannot set a wallet without an account as active",
|
308
|
+
);
|
309
|
+
});
|
310
|
+
});
|
311
|
+
|
312
|
+
describe("Connection Manager Event Subscriptions", () => {
|
313
|
+
let storage: AsyncStorage;
|
314
|
+
let client: ThirdwebClient;
|
315
|
+
let wallet: Wallet;
|
316
|
+
let account: Account;
|
317
|
+
|
318
|
+
beforeEach(() => {
|
319
|
+
storage = {
|
320
|
+
getItem: vi.fn(),
|
321
|
+
setItem: vi.fn(),
|
322
|
+
removeItem: vi.fn(),
|
323
|
+
};
|
324
|
+
client = TEST_CLIENT;
|
325
|
+
account = TEST_ACCOUNT_A;
|
326
|
+
wallet = {
|
327
|
+
id: "wallet-id",
|
328
|
+
getAccount: vi.fn().mockReturnValue(account),
|
329
|
+
subscribe: vi.fn().mockReturnValue(vi.fn()),
|
330
|
+
disconnect: vi.fn(),
|
331
|
+
switchChain: vi.fn(),
|
332
|
+
getChain: vi.fn().mockReturnValue(sepolia),
|
333
|
+
getConfig: vi.fn(),
|
334
|
+
} as unknown as Wallet;
|
335
|
+
});
|
336
|
+
|
337
|
+
it("should subscribe to accountChanged, chainChanged, and disconnect events", async () => {
|
338
|
+
const manager = createConnectionManager(storage);
|
339
|
+
|
340
|
+
await manager.handleConnection(wallet, { client });
|
341
|
+
|
342
|
+
expect(wallet.subscribe).toHaveBeenCalledWith(
|
343
|
+
"accountChanged",
|
344
|
+
expect.any(Function),
|
345
|
+
);
|
346
|
+
expect(wallet.subscribe).toHaveBeenCalledWith(
|
347
|
+
"chainChanged",
|
348
|
+
expect.any(Function),
|
349
|
+
);
|
350
|
+
expect(wallet.subscribe).toHaveBeenCalledWith(
|
351
|
+
"disconnect",
|
352
|
+
expect.any(Function),
|
353
|
+
);
|
354
|
+
});
|
68
355
|
});
|
@@ -125,27 +125,26 @@ export function createConnectionManager(storage: AsyncStorage) {
|
|
125
125
|
) => {
|
126
126
|
const account = wallet.getAccount();
|
127
127
|
if (!account) {
|
128
|
-
throw new Error("
|
128
|
+
throw new Error("Cannot set a wallet without an account as active");
|
129
129
|
}
|
130
130
|
|
131
131
|
const activeWallet = await (async () => {
|
132
132
|
if (options?.accountAbstraction && !hasSmartAccount(wallet)) {
|
133
133
|
return await handleSmartWalletConnection(
|
134
|
-
|
134
|
+
wallet,
|
135
135
|
options.client,
|
136
136
|
options.accountAbstraction,
|
137
|
+
onWalletDisconnect,
|
137
138
|
);
|
138
139
|
} else {
|
139
140
|
return wallet;
|
140
141
|
}
|
141
142
|
})();
|
142
143
|
|
143
|
-
|
144
|
-
addConnectedWallet(wallet);
|
144
|
+
await storage.setItem(LAST_ACTIVE_EOA_ID, wallet.id);
|
145
145
|
|
146
|
-
|
147
|
-
|
148
|
-
}
|
146
|
+
// add personal wallet to connected wallets list even if it's not the active one
|
147
|
+
addConnectedWallet(wallet);
|
149
148
|
|
150
149
|
handleSetActiveWallet(activeWallet);
|
151
150
|
|
@@ -158,22 +157,6 @@ export function createConnectionManager(storage: AsyncStorage) {
|
|
158
157
|
return activeWallet;
|
159
158
|
};
|
160
159
|
|
161
|
-
const handleSmartWalletConnection = async (
|
162
|
-
signer: Account,
|
163
|
-
client: ThirdwebClient,
|
164
|
-
options: SmartWalletOptions,
|
165
|
-
) => {
|
166
|
-
const wallet = smartWallet(options);
|
167
|
-
|
168
|
-
await wallet.connect({
|
169
|
-
personalAccount: signer,
|
170
|
-
client: client,
|
171
|
-
chain: options.chain,
|
172
|
-
});
|
173
|
-
|
174
|
-
return wallet;
|
175
|
-
};
|
176
|
-
|
177
160
|
const connect = async (wallet: Wallet, options?: ConnectManagerOptions) => {
|
178
161
|
// connectedWallet can be either wallet or smartWallet
|
179
162
|
const connectedWallet = await handleConnection(wallet, options);
|
@@ -184,7 +167,7 @@ export function createConnectionManager(storage: AsyncStorage) {
|
|
184
167
|
const handleSetActiveWallet = (activeWallet: Wallet) => {
|
185
168
|
const account = activeWallet.getAccount();
|
186
169
|
if (!account) {
|
187
|
-
throw new Error("
|
170
|
+
throw new Error("Cannot set a wallet without an account as active");
|
188
171
|
}
|
189
172
|
|
190
173
|
// also add it to connected wallets if it's not already there
|
@@ -357,11 +340,9 @@ export async function getStoredActiveWalletId(
|
|
357
340
|
if (value) {
|
358
341
|
return value as WalletId;
|
359
342
|
}
|
343
|
+
} catch {}
|
360
344
|
|
361
|
-
|
362
|
-
} catch {
|
363
|
-
return null;
|
364
|
-
}
|
345
|
+
return null;
|
365
346
|
}
|
366
347
|
|
367
348
|
/**
|
@@ -375,9 +356,41 @@ export async function getLastConnectedChain(
|
|
375
356
|
if (value) {
|
376
357
|
return JSON.parse(value) as Chain;
|
377
358
|
}
|
359
|
+
} catch {}
|
378
360
|
|
379
|
-
|
380
|
-
} catch {
|
381
|
-
return null;
|
382
|
-
}
|
361
|
+
return null;
|
383
362
|
}
|
363
|
+
|
364
|
+
/**
|
365
|
+
* @internal
|
366
|
+
*/
|
367
|
+
export const handleSmartWalletConnection = async (
|
368
|
+
eoaWallet: Wallet,
|
369
|
+
client: ThirdwebClient,
|
370
|
+
options: SmartWalletOptions,
|
371
|
+
onWalletDisconnect: (wallet: Wallet) => void,
|
372
|
+
) => {
|
373
|
+
const signer = eoaWallet.getAccount();
|
374
|
+
if (!signer) {
|
375
|
+
throw new Error("Cannot set a wallet without an account as active");
|
376
|
+
}
|
377
|
+
|
378
|
+
const wallet = smartWallet(options);
|
379
|
+
|
380
|
+
await wallet.connect({
|
381
|
+
personalAccount: signer,
|
382
|
+
client: client,
|
383
|
+
chain: options.chain,
|
384
|
+
});
|
385
|
+
|
386
|
+
// Disconnect the active wallet when the EOA disconnects if it the active wallet is a smart wallet
|
387
|
+
const disconnectUnsub = eoaWallet.subscribe("disconnect", () => {
|
388
|
+
handleDisconnect();
|
389
|
+
});
|
390
|
+
const handleDisconnect = () => {
|
391
|
+
disconnectUnsub();
|
392
|
+
onWalletDisconnect(wallet);
|
393
|
+
};
|
394
|
+
|
395
|
+
return wallet;
|
396
|
+
};
|
@@ -27,7 +27,7 @@ const URI_MOCK =
|
|
27
27
|
|
28
28
|
const DEFAULT_METADATA = getDefaultAppMetadata();
|
29
29
|
|
30
|
-
const listeners: Record<string, (
|
30
|
+
const listeners: Record<string, (_event?: unknown) => Promise<void>> = {};
|
31
31
|
|
32
32
|
const signClientMock = {
|
33
33
|
on: vi.fn((event, listener) => {
|
@@ -134,7 +134,7 @@ export type WalletAutoConnectionOption<T extends WalletId> =
|
|
134
134
|
* @example
|
135
135
|
* ```ts
|
136
136
|
* type X = WalletCreationOptions<'io.metamask'>
|
137
|
-
*
|
137
|
+
* ```
|
138
138
|
*/
|
139
139
|
export type WalletCreationOptions<T extends WalletId> = T extends "smart"
|
140
140
|
? SmartWalletOptions
|