@orderly.network/wallet-connector-privy 3.0.0-beta.0 → 3.0.0-beta.2

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/index.js CHANGED
@@ -188,16 +188,35 @@ var getPrivyEmbeddedWalletChainId = (chainId) => {
188
188
  }
189
189
  return parseInt(chainId.split("eip155:")[1]);
190
190
  };
191
- var defaultUseSolanaWallets = {
192
- ready: false,
193
- wallets: [],
194
- createWallet: () => Promise.resolve(),
195
- exportWallet: () => Promise.resolve()
191
+ var defaultPrivyWalletContextValue = {
192
+ connect: () => {
193
+ },
194
+ walletEVM: null,
195
+ walletSOL: null,
196
+ allWalletsEVM: [],
197
+ allWalletsSOL: [],
198
+ isConnected: false,
199
+ switchChain: () => Promise.reject(new Error("Privy is disabled")),
200
+ linkedAccount: null,
201
+ exportWallet: () => Promise.reject(new Error("Privy is disabled")),
202
+ createEvmWallet: () => Promise.reject(new Error("Privy is disabled")),
203
+ createSolanaWallet: () => Promise.reject(new Error("Privy is disabled")),
204
+ selectWallet: () => {
205
+ },
206
+ disconnect: () => Promise.resolve()
196
207
  };
197
- var defaultUseWallets = { wallets: [] };
198
208
  var PrivyWalletContext = React19.createContext(null);
199
209
  var PrivyWalletProvider = ({
200
210
  children
211
+ }) => {
212
+ const { connectorWalletType } = useWalletConnectorPrivy();
213
+ if (connectorWalletType.disablePrivy) {
214
+ return /* @__PURE__ */ React19__default.default.createElement(PrivyWalletContext.Provider, { value: defaultPrivyWalletContextValue }, children);
215
+ }
216
+ return /* @__PURE__ */ React19__default.default.createElement(PrivyWalletProviderInner, null, children);
217
+ };
218
+ var PrivyWalletProviderInner = ({
219
+ children
201
220
  }) => {
202
221
  const { network, solanaInfo, setSolanaInfo, connectorWalletType } = useWalletConnectorPrivy();
203
222
  const {
@@ -209,66 +228,115 @@ var PrivyWalletProvider = ({
209
228
  exportWallet: exportEvmWallet,
210
229
  createWallet: createEvmWallet
211
230
  } = reactAuth.usePrivy();
212
- const { wallets: walletsEVM } = connectorWalletType.disablePrivy ? defaultUseWallets : reactAuth.useWallets();
231
+ const { wallets: walletsEVM } = reactAuth.useWallets();
213
232
  const connectedRef = React19.useRef(false);
214
233
  const {
215
234
  ready: solanaReady,
216
235
  wallets: walletsSOL,
217
236
  createWallet: createSolanaWallet,
218
237
  exportWallet: exportSolanaWallet
219
- } = connectorWalletType.disablePrivy ? defaultUseSolanaWallets : reactAuth.useSolanaWallets();
238
+ } = reactAuth.useSolanaWallets();
220
239
  const [walletEVM, setWalletEVM] = React19.useState(null);
221
240
  const [walletSOL, setWalletSOL] = React19.useState(null);
241
+ const [allWalletsEVM, setAllWalletsEVM] = React19.useState([]);
242
+ const [allWalletsSOL, setAllWalletsSOL] = React19.useState([]);
243
+ const [selectedEvmAddress, setSelectedEvmAddress] = hooks.useLocalStorage(
244
+ "privy_selected_evm_address",
245
+ ""
246
+ );
247
+ const [selectedSolAddress, setSelectedSolAddress] = hooks.useLocalStorage(
248
+ "privy_selected_sol_address",
249
+ ""
250
+ );
251
+ const rawEvmWalletsRef = React19.useRef(/* @__PURE__ */ new Map());
222
252
  const { track } = hooks.useTrack();
223
253
  const linkedAccount = React19.useMemo(() => {
224
- if (user && user.linkedAccounts) {
225
- const account = user.linkedAccounts.filter((item) => item.type !== "wallet").sort(
226
- (a, b) => (b.latestVerifiedAt?.getTime() ?? 0) - (a.latestVerifiedAt?.getTime() ?? 0)
227
- )[0];
228
- let address = null;
229
- if (account.type === "email") {
230
- address = account.address;
231
- } else if (account.type === "twitter_oauth") {
232
- address = `@${account.username}`;
233
- } else if (account.type === "google_oauth") {
234
- address = `@${account.name}`;
235
- } else if (account.type === "telegram") {
236
- address = `@${account.username}`;
237
- }
238
- return {
239
- type: account.type,
240
- address
241
- };
254
+ const account = user?.linkedAccounts?.filter((item) => item.type !== "wallet" && item.type !== "smart_wallet").sort(
255
+ (a, b) => (b.latestVerifiedAt?.getTime() ?? 0) - (a.latestVerifiedAt?.getTime() ?? 0)
256
+ )[0];
257
+ if (!account) {
258
+ return null;
242
259
  }
243
- return null;
260
+ let address = null;
261
+ if (account.type === "email") {
262
+ address = account.address;
263
+ } else if (account.type === "twitter_oauth") {
264
+ address = `@${account.username}`;
265
+ } else if (account.type === "google_oauth") {
266
+ address = `@${account.name}`;
267
+ } else if (account.type === "telegram") {
268
+ address = `@${account.username}`;
269
+ }
270
+ return {
271
+ type: account.type,
272
+ address
273
+ };
244
274
  }, [user]);
245
275
  const switchChain = (chainId) => {
246
- const wallet = walletsEVM[0];
247
- if (wallet) {
248
- return wallet.switchChain(chainId);
276
+ const selectedAddress = walletEVM?.accounts[0]?.address;
277
+ const rawWallet = selectedAddress ? rawEvmWalletsRef.current.get(selectedAddress) : void 0;
278
+ if (rawWallet) {
279
+ return rawWallet.switchChain(chainId);
280
+ }
281
+ const fallback = walletsEVM.find((w) => w.connectorType === "embedded") ?? walletsEVM[0];
282
+ if (fallback) {
283
+ return fallback.switchChain(chainId);
249
284
  }
250
285
  return Promise.reject("no wallet");
251
286
  };
252
- const connect = () => {
287
+ const connect = (params) => {
288
+ if (params?.extraType) {
289
+ login({ loginMethods: [params.extraType] });
290
+ return;
291
+ }
253
292
  login();
254
293
  };
255
294
  const disconnect = () => {
256
295
  return logout();
257
296
  };
258
- const exportWallet = (namespace) => {
297
+ const exportWallet = (namespace, address) => {
259
298
  if (namespace === types.ChainNamespace.evm) {
260
299
  track(types.TrackerEventName.clickExportPrivateKey, {
261
300
  type: "evm"
262
301
  });
263
- return exportEvmWallet();
302
+ const addr = address ?? walletEVM?.accounts[0]?.address;
303
+ return exportEvmWallet(addr ? { address: addr } : void 0);
264
304
  } else if (namespace === types.ChainNamespace.solana) {
265
305
  track(types.TrackerEventName.clickExportPrivateKey, {
266
306
  type: "solana"
267
307
  });
268
- return exportSolanaWallet();
308
+ const addr = address ?? walletSOL?.accounts[0]?.address;
309
+ return exportSolanaWallet(addr ? { address: addr } : void 0);
269
310
  }
270
311
  return Promise.reject("no namespace");
271
312
  };
313
+ const selectWallet = React19.useCallback(
314
+ (namespace, address) => {
315
+ if (namespace === types.ChainNamespace.evm) {
316
+ const found = allWalletsEVM.find(
317
+ (w) => w.accounts[0]?.address === address
318
+ );
319
+ if (found) {
320
+ setWalletEVM(found);
321
+ setSelectedEvmAddress(address);
322
+ }
323
+ } else if (namespace === types.ChainNamespace.solana) {
324
+ const found = allWalletsSOL.find(
325
+ (w) => w.accounts[0]?.address === address
326
+ );
327
+ if (found) {
328
+ setWalletSOL(found);
329
+ setSelectedSolAddress(address);
330
+ }
331
+ }
332
+ },
333
+ [
334
+ allWalletsEVM,
335
+ allWalletsSOL,
336
+ setSelectedEvmAddress,
337
+ setSelectedSolAddress
338
+ ]
339
+ );
272
340
  const isConnected = React19.useMemo(() => {
273
341
  if (ready && authenticated) {
274
342
  return true;
@@ -277,76 +345,81 @@ var PrivyWalletProvider = ({
277
345
  }, [ready, authenticated]);
278
346
  React19.useEffect(() => {
279
347
  if (!authenticated || !walletsEVM || !walletsEVM[0]) {
348
+ setAllWalletsEVM([]);
280
349
  setWalletEVM(null);
281
350
  return;
282
351
  }
283
- const wallet = walletsEVM[0];
284
- wallet.getEthereumProvider().then((provider) => {
285
- setWalletEVM({
286
- label: "privy",
287
- icon: "",
288
- provider,
289
- accounts: [
290
- {
291
- address: wallet.address
292
- }
293
- ],
294
- chains: [
295
- {
296
- id: getPrivyEmbeddedWalletChainId(wallet.chainId) ?? 1,
297
- namespace: types.ChainNamespace.evm
298
- }
299
- ],
300
- chain: {
301
- id: getPrivyEmbeddedWalletChainId(wallet.chainId) ?? 1,
302
- namespace: types.ChainNamespace.evm
303
- }
304
- });
352
+ const embeddedWallets = walletsEVM.filter(
353
+ (w) => w.connectorType === "embedded"
354
+ );
355
+ const wallets = embeddedWallets.length > 0 ? embeddedWallets : [walletsEVM[0]];
356
+ const newMap = /* @__PURE__ */ new Map();
357
+ for (const w of wallets) {
358
+ newMap.set(w.address, w);
359
+ }
360
+ rawEvmWalletsRef.current = newMap;
361
+ Promise.all(
362
+ wallets.map(
363
+ (w) => w.getEthereumProvider().then(
364
+ (provider) => ({
365
+ label: "privy",
366
+ icon: "",
367
+ provider,
368
+ accounts: [{ address: w.address }],
369
+ chains: [
370
+ {
371
+ id: getPrivyEmbeddedWalletChainId(w.chainId) ?? 1,
372
+ namespace: types.ChainNamespace.evm
373
+ }
374
+ ],
375
+ chain: {
376
+ id: getPrivyEmbeddedWalletChainId(w.chainId) ?? 1,
377
+ namespace: types.ChainNamespace.evm
378
+ }
379
+ })
380
+ )
381
+ )
382
+ ).then((builtWallets) => {
383
+ setAllWalletsEVM(builtWallets);
384
+ const preferred = selectedEvmAddress ? builtWallets.find(
385
+ (w) => w.accounts[0]?.address === selectedEvmAddress
386
+ ) : void 0;
387
+ setWalletEVM(preferred ?? builtWallets[0] ?? null);
388
+ }).catch((e) => {
389
+ setAllWalletsEVM([]);
390
+ setWalletEVM(null);
305
391
  });
306
392
  }, [walletsEVM, authenticated]);
307
393
  React19.useEffect(() => {
308
394
  if (!authenticated) {
395
+ setAllWalletsSOL([]);
309
396
  setWalletSOL(null);
310
397
  return;
311
398
  }
312
399
  if (!solanaReady) {
313
400
  return;
314
401
  }
315
- if (!user) {
316
- return;
317
- }
318
- const embededSolanaWallet = (user?.linkedAccounts).find(
319
- (item) => item.chainType === "solana" && item.connectorType === "embedded"
320
- );
321
- if (!embededSolanaWallet) {
322
- createSolanaWallet().then();
323
- return;
324
- }
325
402
  if (!walletsSOL || !walletsSOL[0]) {
403
+ setAllWalletsSOL([]);
404
+ setWalletSOL(null);
326
405
  return;
327
406
  }
328
- const wallet = walletsSOL.find((w) => w.connectorType === "embedded");
329
- if (wallet) {
330
- if (walletSOL && wallet.address === walletSOL.accounts[0].address) {
331
- if (walletSOL.chain.id === SolanaChainsMap.get(network)) {
332
- return;
333
- }
334
- }
335
- setWalletSOL({
407
+ const embeddedWallets = walletsSOL.filter(
408
+ (w) => w.connectorType === "embedded"
409
+ );
410
+ const wallets = embeddedWallets.length > 0 ? embeddedWallets : [walletsSOL[0]];
411
+ const builtWallets = wallets.map(
412
+ (w) => ({
336
413
  label: "privy",
337
414
  icon: "",
338
415
  provider: {
339
- signMessage: wallet.signMessage,
340
- signTransaction: wallet.signTransaction,
341
- sendTransaction: wallet.sendTransaction,
416
+ signMessage: w.signMessage,
417
+ signTransaction: w.signTransaction,
418
+ sendTransaction: w.sendTransaction,
342
419
  network: solanaInfo?.network ?? walletAdapterBase.WalletAdapterNetwork.Devnet,
343
420
  rpcUrl: solanaInfo?.rpcUrl ?? void 0
344
421
  },
345
- accounts: [
346
- {
347
- address: wallet.address
348
- }
349
- ],
422
+ accounts: [{ address: w.address }],
350
423
  chains: [
351
424
  {
352
425
  id: SolanaChainsMap.get(network),
@@ -357,18 +430,12 @@ var PrivyWalletProvider = ({
357
430
  id: SolanaChainsMap.get(network),
358
431
  namespace: types.ChainNamespace.solana
359
432
  }
360
- });
361
- }
362
- }, [
363
- walletsSOL,
364
- authenticated,
365
- createSolanaWallet,
366
- solanaReady,
367
- user,
368
- walletSOL,
369
- network,
370
- solanaInfo
371
- ]);
433
+ })
434
+ );
435
+ setAllWalletsSOL(builtWallets);
436
+ const preferred = selectedSolAddress ? builtWallets.find((w) => w.accounts[0]?.address === selectedSolAddress) : void 0;
437
+ setWalletSOL(preferred ?? builtWallets[0] ?? null);
438
+ }, [walletsSOL, authenticated, solanaReady, network, solanaInfo]);
372
439
  React19.useEffect(() => {
373
440
  if (isConnected && linkedAccount) {
374
441
  if (connectedRef.current) {
@@ -386,25 +453,31 @@ var PrivyWalletProvider = ({
386
453
  connect,
387
454
  walletEVM,
388
455
  walletSOL,
456
+ allWalletsEVM,
457
+ allWalletsSOL,
389
458
  isConnected,
390
459
  disconnect,
391
460
  switchChain,
392
461
  linkedAccount,
393
462
  exportWallet,
394
463
  createEvmWallet,
395
- createSolanaWallet
464
+ createSolanaWallet,
465
+ selectWallet
396
466
  }),
397
467
  [
398
468
  connect,
399
469
  walletEVM,
400
470
  walletSOL,
471
+ allWalletsEVM,
472
+ allWalletsSOL,
401
473
  isConnected,
402
474
  disconnect,
403
475
  switchChain,
404
476
  linkedAccount,
405
477
  exportWallet,
406
478
  createEvmWallet,
407
- createSolanaWallet
479
+ createSolanaWallet,
480
+ selectWallet
408
481
  ]
409
482
  );
410
483
  return /* @__PURE__ */ React19__default.default.createElement(PrivyWalletContext.Provider, { value }, children);
@@ -1991,7 +2064,8 @@ function PrivyWalletHandleOption({
1991
2064
  {
1992
2065
  className: "oui-cursor-pointer oui-px-2 oui-py-1 oui-text-2xs oui-text-base-contrast-54 hover:oui-text-base-contrast",
1993
2066
  onClick: () => {
1994
- exportWallet(type);
2067
+ const ns = type === "EVM" /* EVM */ ? types.ChainNamespace.evm : types.ChainNamespace.solana;
2068
+ exportWallet(ns, address);
1995
2069
  }
1996
2070
  },
1997
2071
  /* @__PURE__ */ React19__default.default.createElement("div", null, t("common.export"))
@@ -2510,33 +2584,38 @@ function RenderPrivyWallet() {
2510
2584
  walletChainTypeConfig,
2511
2585
  connectorWalletType
2512
2586
  } = useWalletConnectorPrivy();
2513
- const { walletEVM, walletSOL, linkedAccount } = usePrivyWallet();
2587
+ const {
2588
+ walletEVM,
2589
+ walletSOL,
2590
+ allWalletsEVM,
2591
+ allWalletsSOL,
2592
+ linkedAccount,
2593
+ selectWallet
2594
+ } = usePrivyWallet();
2514
2595
  const { switchWallet, disconnect } = useWallet2();
2515
2596
  const { storageChain } = hooks.useStorageChain();
2516
2597
  const [walletList, setWalletList] = React19.useState([]);
2517
2598
  const [addWallet, setAddWallet] = React19.useState([]);
2518
2599
  const [loading, setLoading] = React19.useState(true);
2519
2600
  const isActive = React19.useCallback(
2520
- (walletType) => {
2601
+ (walletType, address) => {
2521
2602
  if (storageChain?.namespace === types.ChainNamespace.evm) {
2522
2603
  if (walletType === "EVM" /* EVM */) {
2523
- return !types.AbstractChains.has(storageChain?.chainId);
2604
+ if (types.AbstractChains.has(storageChain?.chainId)) return false;
2605
+ return walletEVM?.accounts[0]?.address === address;
2524
2606
  }
2525
2607
  return false;
2526
2608
  }
2527
2609
  if (storageChain?.namespace === types.ChainNamespace.solana) {
2528
- return walletType === "SOL" /* SOL */;
2610
+ if (walletType === "SOL" /* SOL */) {
2611
+ return walletSOL?.accounts[0]?.address === address;
2612
+ }
2613
+ return false;
2529
2614
  }
2530
2615
  return false;
2531
2616
  },
2532
- [storageChain]
2617
+ [storageChain, walletEVM, walletSOL]
2533
2618
  );
2534
- const isHaveEvmWallet = React19.useMemo(() => {
2535
- return walletEVM && walletEVM.accounts.length;
2536
- }, [walletEVM]);
2537
- const isHaveSolWallet = React19.useMemo(() => {
2538
- return walletSOL && walletSOL.accounts.length;
2539
- }, [walletSOL]);
2540
2619
  const renderWarning = React19.useCallback(() => {
2541
2620
  let showWarning = false;
2542
2621
  if (types.AbstractChains.has(storageChain?.chainId)) {
@@ -2577,18 +2656,31 @@ function RenderPrivyWallet() {
2577
2656
  return /* @__PURE__ */ React19__default.default.createElement("div", { className: "oui-mt-5 oui-flex oui-flex-col oui-gap-5" }, walletList.map((wallet) => /* @__PURE__ */ React19__default.default.createElement(
2578
2657
  WalletCard,
2579
2658
  {
2580
- key: wallet.type,
2659
+ key: wallet.address,
2581
2660
  type: wallet.type,
2582
2661
  address: wallet.address,
2583
- isActive: isActive(wallet.type),
2662
+ isActive: isActive(wallet.type, wallet.address),
2584
2663
  isPrivy: true,
2585
2664
  isMulti: walletList.length > 1,
2586
2665
  onActiveChange: () => {
2587
- switchWallet(wallet.type);
2666
+ const walletNamespace = wallet.type === "EVM" /* EVM */ ? types.ChainNamespace.evm : types.ChainNamespace.solana;
2667
+ selectWallet(walletNamespace, wallet.address);
2668
+ if (storageChain?.namespace !== walletNamespace) {
2669
+ switchWallet(wallet.type);
2670
+ }
2588
2671
  }
2589
2672
  }
2590
2673
  )), addWallet.map((node, index) => /* @__PURE__ */ React19__default.default.createElement("div", { key: index }, /* @__PURE__ */ React19__default.default.createElement("div", { className: "oui-my-5 oui-h-px oui-w-full oui-bg-line" }), /* @__PURE__ */ React19__default.default.createElement("div", { className: "oui-flex oui-w-full oui-flex-col oui-gap-2" }, node))));
2591
- }, [walletList, addWallet, isActive, switchWallet, t, loading]);
2674
+ }, [
2675
+ walletList,
2676
+ addWallet,
2677
+ isActive,
2678
+ switchWallet,
2679
+ selectWallet,
2680
+ storageChain,
2681
+ t,
2682
+ loading
2683
+ ]);
2592
2684
  React19.useEffect(() => {
2593
2685
  new Promise(
2594
2686
  (resolve) => setTimeout(() => {
@@ -2601,21 +2693,25 @@ function RenderPrivyWallet() {
2601
2693
  const tempWalletList = [];
2602
2694
  const tempAddWallet = [];
2603
2695
  if (!connectorWalletType.disableWagmi && walletChainTypeConfig.hasEvm) {
2604
- if (isHaveEvmWallet) {
2605
- tempWalletList.push({
2606
- type: "EVM" /* EVM */,
2607
- address: walletEVM.accounts[0].address
2608
- });
2696
+ if (allWalletsEVM.length > 0) {
2697
+ for (const w of allWalletsEVM) {
2698
+ tempWalletList.push({
2699
+ type: "EVM" /* EVM */,
2700
+ address: w.accounts[0].address
2701
+ });
2702
+ }
2609
2703
  } else {
2610
2704
  tempAddWallet.push(/* @__PURE__ */ React19__default.default.createElement(CreateEVMWallet, null));
2611
2705
  }
2612
2706
  }
2613
2707
  if (!connectorWalletType.disableSolana && walletChainTypeConfig.hasSol) {
2614
- if (isHaveSolWallet) {
2615
- tempWalletList.push({
2616
- type: "SOL" /* SOL */,
2617
- address: walletSOL.accounts[0].address
2618
- });
2708
+ if (allWalletsSOL.length > 0) {
2709
+ for (const w of allWalletsSOL) {
2710
+ tempWalletList.push({
2711
+ type: "SOL" /* SOL */,
2712
+ address: w.accounts[0].address
2713
+ });
2714
+ }
2619
2715
  } else {
2620
2716
  tempAddWallet.push(/* @__PURE__ */ React19__default.default.createElement(CreateSOLWallet, null));
2621
2717
  }
@@ -2625,10 +2721,8 @@ function RenderPrivyWallet() {
2625
2721
  }, [
2626
2722
  connectorWalletType,
2627
2723
  walletChainTypeConfig,
2628
- walletEVM,
2629
- walletSOL,
2630
- isHaveEvmWallet,
2631
- isHaveSolWallet
2724
+ allWalletsEVM,
2725
+ allWalletsSOL
2632
2726
  ]);
2633
2727
  React19.useEffect(() => {
2634
2728
  if (targetWalletType === "Abstract" /* ABSTRACT */) {
@@ -2639,7 +2733,7 @@ function RenderPrivyWallet() {
2639
2733
  });
2640
2734
  }
2641
2735
  }, [targetWalletType, setTargetWalletType]);
2642
- return /* @__PURE__ */ React19__default.default.createElement("div", null, /* @__PURE__ */ React19__default.default.createElement("div", { className: "oui-flex oui-items-center oui-justify-between" }, linkedAccount && /* @__PURE__ */ React19__default.default.createElement("div", { className: "oui-flex oui-items-center oui-justify-start oui-gap-2 oui-text-base-contrast" }, /* @__PURE__ */ React19__default.default.createElement("div", null, /* @__PURE__ */ React19__default.default.createElement(RenderPrivyTypeIcon, { type: linkedAccount.type, size: 24 })), /* @__PURE__ */ React19__default.default.createElement("div", { className: "oui-text-xs" }, linkedAccount.address)), /* @__PURE__ */ React19__default.default.createElement(
2736
+ return /* @__PURE__ */ React19__default.default.createElement("div", { className: "oui-flex oui-max-h-[70vh] oui-flex-col oui-overflow-y-auto oui-custom-scrollbar" }, /* @__PURE__ */ React19__default.default.createElement("div", { className: "oui-flex oui-items-center oui-justify-between" }, linkedAccount && /* @__PURE__ */ React19__default.default.createElement("div", { className: "oui-flex oui-items-center oui-justify-start oui-gap-2 oui-text-base-contrast" }, /* @__PURE__ */ React19__default.default.createElement("div", null, /* @__PURE__ */ React19__default.default.createElement(RenderPrivyTypeIcon, { type: linkedAccount.type, size: 24 })), /* @__PURE__ */ React19__default.default.createElement("div", { className: "oui-text-xs" }, linkedAccount.address)), /* @__PURE__ */ React19__default.default.createElement(
2643
2737
  "div",
2644
2738
  {
2645
2739
  className: "oui-cursor-pointer oui-text-2xs oui-font-semibold oui-text-primary",