@coin-voyage/crypto 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/package.json +67 -0
  2. package/src/assets/icons.tsx +16 -0
  3. package/src/evm/base-provider.tsx +22 -0
  4. package/src/evm/create-default-evm-config.ts +123 -0
  5. package/src/evm/external-context.ts +4 -0
  6. package/src/evm/use-evm-transaction.ts +35 -0
  7. package/src/evm/use-sign-in-with-evm.ts +54 -0
  8. package/src/evm/verify-message.ts +3 -0
  9. package/src/hooks/index.ts +6 -0
  10. package/src/hooks/use-account-disconnect.ts +47 -0
  11. package/src/hooks/use-account.ts +171 -0
  12. package/src/hooks/use-combined-wallets.ts +165 -0
  13. package/src/hooks/use-prepare-transaction.ts +32 -0
  14. package/src/hooks/use-universal-connect.ts +141 -0
  15. package/src/lib/config/chain.ts +13 -0
  16. package/src/lib/connectors/coinbase.ts +9 -0
  17. package/src/lib/connectors/metaMask.ts +6 -0
  18. package/src/lib/connectors/types.ts +12 -0
  19. package/src/lib/connectors/utils.ts +23 -0
  20. package/src/lib/connectors/walletConnect.ts +18 -0
  21. package/src/lib/utils/connector.ts +22 -0
  22. package/src/lib/utils/get-connector-icon.ts +13 -0
  23. package/src/lib/utils/get-wallet-priority.ts +15 -0
  24. package/src/lib/utils/is-wallet-installed.ts +40 -0
  25. package/src/lib/utils/message.ts +29 -0
  26. package/src/solana/base-provider.tsx +29 -0
  27. package/src/solana/external-context.ts +3 -0
  28. package/src/solana/get-or-create-ata.ts +85 -0
  29. package/src/solana/use-solana-transaction.ts +83 -0
  30. package/src/sui/base-provider.tsx +22 -0
  31. package/src/sui/client.ts +3 -0
  32. package/src/sui/constants.ts +5 -0
  33. package/src/sui/external-context.ts +3 -0
  34. package/src/sui/use-sign-in-with-sui.ts +55 -0
  35. package/src/sui/use-sui-transaction.ts +56 -0
  36. package/src/sui/verify-message.ts +18 -0
  37. package/src/types/index.ts +29 -0
  38. package/src/types/sign-in-with.ts +13 -0
  39. package/src/types/utxo-connector-id.ts +10 -0
  40. package/src/types/wallet-connector.ts +14 -0
  41. package/src/types/wallet.ts +55 -0
  42. package/src/utxo/base-provider.tsx +24 -0
  43. package/src/utxo/create-default-bigmi-config.ts +69 -0
  44. package/src/utxo/create-psbt-tx.ts +72 -0
  45. package/src/utxo/external-context.ts +3 -0
  46. package/src/utxo/get-address-utxo.ts +36 -0
  47. package/src/utxo/send-btc.ts +223 -0
  48. package/src/utxo/use-utxo-transaction.tsx +28 -0
  49. package/src/utxo/utxo-public-client.ts +60 -0
  50. package/src/utxo/verify-message.ts +35 -0
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@coin-voyage/crypto",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "sideEffects": false,
6
+ "exports": {
7
+ ".": "./src/index.ts",
8
+ "./hooks": "./src/hooks/index.ts",
9
+ "./lib": "./src/lib/**/*.ts",
10
+ "./types": "./src/types/index.ts",
11
+ "./evm": "./src/evm/*.ts",
12
+ "./utxo": "./src/utxo/*.ts",
13
+ "./solana": "./src/solana/*.ts",
14
+ "./sui": "./src/sui/*.ts",
15
+ "./*": [
16
+ "./src/*.ts",
17
+ "./src/*.tsx"
18
+ ]
19
+ },
20
+ "files": [
21
+ "src"
22
+ ],
23
+ "typesVersions": {
24
+ "*": {
25
+ "*": [
26
+ "src/*",
27
+ "src/*/index.d.ts"
28
+ ]
29
+ }
30
+ },
31
+ "dependencies": {
32
+ "@bigmi/client": "0.1.0",
33
+ "@bigmi/core": "0.1.0",
34
+ "@noble/secp256k1": "1.7.1",
35
+ "@scure/base": "1.1.1",
36
+ "@scure/btc-signer": "1.6.0",
37
+ "bitcoinjs-lib": "6.1.7",
38
+ "bitcoinjs-message": "^2.2.0",
39
+ "bitcoin-address-validation": "^2.2.3",
40
+ "@mysten/dapp-kit": "0.14.48",
41
+ "@mysten/sui": "1.21.0",
42
+ "@mysten/wallet-standard": "0.13.24",
43
+ "@solana/spl-token": "0.4.9",
44
+ "@solana/wallet-adapter-base": "0.9.23",
45
+ "viem": "2.22.9",
46
+ "wagmi": "2.14.8",
47
+ "@coin-voyage/shared": "0.0.1"
48
+ },
49
+ "devDependencies": {
50
+ "@types/elliptic": "6.4.18"
51
+ },
52
+ "peerDependencies": {
53
+ "@bigmi/react": "0.1.0",
54
+ "@tanstack/react-query": "^5.64.1",
55
+ "react": ">=18",
56
+ "react-dom": ">=18",
57
+ "@solana/wallet-adapter-react": "^0.15.35",
58
+ "@solana/web3.js": "^1.98.0"
59
+ },
60
+ "scripts": {
61
+ "build": "tsc --build --force",
62
+ "release:build": "pnpm build",
63
+ "clean": "rm -rf node_modules",
64
+ "type-check": "tsc --noEmit",
65
+ "test": "vitest run"
66
+ }
67
+ }
@@ -0,0 +1,16 @@
1
+ export const getWalletIcon = (id: string): string | undefined => {
2
+ switch (id) {
3
+ case "walletConnect":
4
+ return "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='512' height='512'%3e %3cradialGradient id='a' cx='0%25' cy='50%25' r='100%25'%3e %3cstop offset='0' stop-color='%235d9df6'/%3e %3cstop offset='1' stop-color='%23006fff'/%3e %3c/radialGradient%3e %3cg fill='none' fill-rule='evenodd'%3e %3cpath fill='url(%23a)' d='M256 0c141.385 0 256 114.615 256 256S397.385 512 256 512 0 397.385 0 256 114.615 0 256 0z'/%3e %3cpath fill='white' fill-rule='nonzero' d='M162.692 197.709c51.533-50.279 135.084-50.279 186.617 0l6.202 6.05a6.327 6.327 0 0 1 0 9.105l-21.216 20.7a3.357 3.357 0 0 1-4.666 0l-8.535-8.328c-35.95-35.075-94.238-35.075-130.188 0l-9.14 8.918a3.357 3.357 0 0 1-4.666 0l-21.216-20.7a6.327 6.327 0 0 1 0-9.104zm230.493 42.809 18.883 18.422a6.327 6.327 0 0 1 0 9.104l-85.142 83.07c-2.577 2.514-6.754 2.514-9.33 0l-60.43-58.957a1.679 1.679 0 0 0-2.332 0l-60.427 58.958c-2.576 2.513-6.754 2.514-9.33 0l-85.145-83.072a6.327 6.327 0 0 1 0-9.104l18.883-18.422c2.576-2.514 6.754-2.514 9.33 0l60.43 58.958a1.679 1.679 0 0 0 2.332 0l60.427-58.958c2.576-2.514 6.754-2.514 9.33 0l60.43 58.958a1.679 1.679 0 0 0 2.332 0l60.428-58.957c2.577-2.514 6.755-2.514 9.331 0z'/%3e %3c/g%3e %3c/svg%3e"
5
+ case "coinbaseWalletSDK":
6
+ return "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 40 40'%3e %3cpath fill='%231652F0' d='M20 40c11.046 0 20-8.954 20-20S31.046 0 20 0 0 8.954 0 20s8.954 20 20 20Z'/%3e %3cpath fill='white' fill-rule='evenodd' d='M5.455 20c0 8.034 6.512 14.546 14.546 14.546 8.033 0 14.545-6.512 14.545-14.545 0-8.034-6.512-14.546-14.545-14.546-8.034 0-14.546 6.512-14.546 14.546Zm11.859-4.685a2 2 0 0 0-2 2v5.373a2 2 0 0 0 2 2h5.373a2 2 0 0 0 2-2v-5.373a2 2 0 0 0-2-2h-5.373Z' clip-rule='evenodd'/%3e %3c/svg%3e"
7
+ case "safe":
8
+ return "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 661.62 661.47'%3e %3cpath fill='%2312ff80' d='M531.98 330.7h-49.42c-14.76 0-26.72 11.96-26.72 26.72v71.73c0 14.76-11.96 26.72-26.72 26.72H232.51c-14.76 0-26.72 11.96-26.72 26.72v49.42c0 14.76 11.96 26.72 26.72 26.72H440.5c14.76 0 26.55-11.96 26.55-26.72v-39.65c0-14.76 11.96-25.23 26.72-25.23h38.2c14.76 0 26.72-11.96 26.72-26.72v-83.3c0-14.76-11.96-26.41-26.72-26.41Zm-326.2-98.18c0-14.76 11.96-26.72 26.72-26.72h196.49c14.76 0 26.72-11.96 26.72-26.72v-49.42c0-14.76-11.96-26.72-26.72-26.72H221.11c-14.76 0-26.72 11.96-26.72 26.72v38.08c0 14.76-11.96 26.72-26.72 26.72h-38.03c-14.76 0-26.72 11.96-26.72 26.72v83.39c0 14.76 12.01 26.12 26.77 26.12h49.42c14.76 0 26.72-11.96 26.72-26.72l-.05-71.44Zm101.77 46.23h47.47c15.47 0 28.02 12.56 28.02 28.02v47.47c0 15.47-12.56 28.02-28.02 28.02h-47.47c-15.47 0-28.02-12.56-28.02-28.02v-47.47c0-15.47 12.56-28.02 28.02-28.02Z'/%3e %3c/svg%3e"
9
+ case "metaMaskSDK":
10
+ case "io.metamask":
11
+ return "data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' fill='none'%3e %3cpath fill='%23E17726' stroke='%23E17726' stroke-linecap='round' stroke-linejoin='round' stroke-width='.303' d='m26.815 5-9.38 6.939 1.749-4.09z'/%3e %3cpath fill='%23E27625' stroke='%23E27625' stroke-linecap='round' stroke-linejoin='round' stroke-width='.303' d='m5.185 5 9.295 6.996-1.664-4.14zM23.44 21.083l-2.499 3.812 5.347 1.47 1.527-5.196zm-19.246.086 1.52 5.197 5.333-1.47-2.484-3.813z'/%3e %3cpath fill='%23E27625' stroke='%23E27625' stroke-linecap='round' stroke-linejoin='round' stroke-width='.303' d='m10.76 14.645-1.484 2.241 5.282.243-.171-5.69-3.626 3.213zm10.48.007-3.684-3.284-.12 5.761 5.282-.243zM11.046 24.896l3.205-1.542-2.755-2.142zm6.71-1.55 3.184 1.55-.428-3.69z'/%3e %3cpath fill='%23D5BFB2' stroke='%23D5BFB2' stroke-linecap='round' stroke-linejoin='round' stroke-width='.303' d='m20.94 24.896-3.184-1.543.257 2.07-.029.879zm-9.895 0 2.97 1.406-.021-.878.257-2.07z'/%3e %3cpath fill='%23233447' stroke='%23233447' stroke-linecap='round' stroke-linejoin='round' stroke-width='.303' d='m14.065 19.834-2.64-.771 1.87-.857.777 1.628zm3.862 0 .786-1.635 1.877.857-2.663.785z'/%3e %3cpath fill='%23CC6228' stroke='%23CC6228' stroke-linecap='round' stroke-linejoin='round' stroke-width='.303' d='m11.046 24.895.464-3.812-2.948.086zm9.444-3.812.45 3.812 2.499-3.726zm2.235-4.197-5.283.242.486 2.713.785-1.642 1.877.857zm-11.3 2.177 1.87-.857.778 1.628.492-2.713-5.282-.235z'/%3e %3cpath fill='%23E27525' stroke='%23E27525' stroke-linecap='round' stroke-linejoin='round' stroke-width='.303' d='m9.283 16.886 2.213 4.319-.072-2.142zm11.307 2.177-.085 2.142 2.213-4.32zm-6.025-1.934-.5 2.712.629 3.198.143-4.219zm2.87 0-.257 1.684.128 4.226.622-3.205-.493-2.713z'/%3e %3cpath fill='%23F5841F' stroke='%23F5841F' stroke-linecap='round' stroke-linejoin='round' stroke-width='.303' d='m17.928 19.834-.621 3.206.45.314 2.748-2.142.085-2.148zm-6.504-.77.072 2.141 2.755 2.142.443-.307-.621-3.206-2.656-.77z'/%3e %3cpath fill='%23C0AC9D' stroke='%23C0AC9D' stroke-linecap='round' stroke-linejoin='round' stroke-width='.303' d='m17.991 26.302.022-.878-.243-.2h-3.54l-.236.2.021.878-2.97-1.407 1.043.857 2.106 1.45h3.605l2.113-1.457 1.027-.85-2.955 1.407z'/%3e %3cpath fill='%23161616' stroke='%23161616' stroke-linecap='round' stroke-linejoin='round' stroke-width='.303' d='m17.756 23.345-.45-.307h-2.613l-.442.314-.257 2.07.236-.2h3.54l.243.2-.257-2.07z'/%3e %3cpath fill='%23763E1A' stroke='%23763E1A' stroke-linecap='round' stroke-linejoin='round' stroke-width='.303' d='M27.215 12.389 28 8.569 26.815 5l-9.066 6.71 3.49 2.934 4.926 1.435 1.085-1.263-.47-.343.749-.685-.571-.443.75-.571-.5-.385zM4 8.562l.8 3.827-.514.378.763.57-.57.45.742.686-.471.343 1.085 1.263 4.925-1.428 3.491-2.948L5.185 5z'/%3e %3cpath fill='%23F5841F' stroke='%23F5841F' stroke-linecap='round' stroke-linejoin='round' stroke-width='.303' d='m26.166 16.078-4.926-1.427 1.485 2.234-2.213 4.319 2.927-.036h4.375zM10.76 14.644l-4.925 1.434-1.642 5.09h4.376l2.927.036-2.213-4.319 1.485-2.241zm6.675 2.484.321-5.425 1.428-3.855h-6.368l1.428 3.855.321 5.425.122 1.699v4.212h2.62l.014-4.212z'/%3e %3c/svg%3e"
12
+ default:
13
+ break
14
+ }
15
+ }
16
+
@@ -0,0 +1,22 @@
1
+ import { type PropsWithChildren, useRef } from "react"
2
+ import { WagmiProvider } from "wagmi"
3
+ import {
4
+ DefaultWagmiConfigProps,
5
+ type DefaultWagmiConfigResult,
6
+ createDefaultEVMConfig,
7
+ } from "./create-default-evm-config"
8
+
9
+ export function EVMBaseProvider({ children, config }: PropsWithChildren<{
10
+ config?: DefaultWagmiConfigProps
11
+ }>) {
12
+ const evm = useRef<DefaultWagmiConfigResult | null>(null)
13
+ if (!evm?.current) {
14
+ evm.current = createDefaultEVMConfig(config)
15
+ }
16
+
17
+ return (
18
+ <WagmiProvider config={evm.current.config} reconnectOnMount={false}>
19
+ {children}
20
+ </WagmiProvider>
21
+ )
22
+ }
@@ -0,0 +1,123 @@
1
+ import { createClient, http } from "viem"
2
+ import type { Config, CreateConnectorFn } from "wagmi"
3
+ import { createConfig } from "wagmi"
4
+ import {
5
+ safe,
6
+ type CoinbaseWalletParameters,
7
+ type MetaMaskParameters,
8
+ type WalletConnectParameters,
9
+ } from "wagmi/connectors"
10
+ import { DEFAULT_CHAINS } from "../lib/config/chain"
11
+ import { createCoinbaseConnector } from "../lib/connectors/coinbase"
12
+ import { createMetaMaskConnector } from "../lib/connectors/metaMask"
13
+ import { createWalletConnectConnector } from "../lib/connectors/walletConnect"
14
+ import { isWalletInstalled } from "../lib/utils/is-wallet-installed"
15
+
16
+ export interface DefaultWagmiConfigProps {
17
+ walletConnect?: WalletConnectParameters
18
+ coinbase?: CoinbaseWalletParameters
19
+ metaMask?: MetaMaskParameters
20
+ evmConfig?: {
21
+ ssr?: boolean
22
+ multiInjectedProviderDiscovery?: boolean
23
+ }
24
+ connectors?: CreateConnectorFn[]
25
+ /**
26
+ * Load Wallet SDKs only if the wallet is the most recently connected wallet
27
+ */
28
+ lazy?: boolean
29
+ }
30
+
31
+ export interface DefaultWagmiConfigResult {
32
+ config: Config
33
+ }
34
+
35
+ /**
36
+ * Creates default EVM config that can be later synced (via useSyncEVMConfig) with chains fetched from user config.
37
+ * @param props Properties to setup connectors. {@link DefaultWagmiConfigProps}
38
+ * @returns EVM config and connectors. {@link DefaultWagmiConfigResult}
39
+ * @example
40
+ * const { config, connectors } = createDefaultEVMConfig({
41
+ * walletConnect: {
42
+ * projectId: import.meta.env.VITE_WALLET_CONNECT,
43
+ * },
44
+ * coinbase: { appName: 'Coin Voyage' },
45
+ * });
46
+ * export const WalletProvider: FC<PropsWithChildren> = ({ children }) => {
47
+ * const { chains } = useAvailableChains();
48
+ * useSyncEVMConfig(config, connectors, chains);
49
+ * return (
50
+ * <WagmiProvider config={wagmi.config} reconnectOnMount={false}>
51
+ * {children}
52
+ * </WagmiProvider>
53
+ * );
54
+ * };
55
+ */
56
+ export function createDefaultEVMConfig(
57
+ props?: DefaultWagmiConfigProps
58
+ ): DefaultWagmiConfigResult {
59
+ const connectors: CreateConnectorFn[] = [...(props?.connectors ?? [])]
60
+
61
+ const anyWindow = typeof window !== "undefined" ? (window as any) : undefined
62
+ const localStorage = anyWindow?.localStorage
63
+ // in Multisig env, window.parent is not equal to window
64
+ const shouldUseSafeConnector = anyWindow && anyWindow.parent !== anyWindow
65
+
66
+ const multiInjectedProviderDiscovery = shouldUseSafeConnector
67
+ ? false
68
+ : (props?.evmConfig?.multiInjectedProviderDiscovery ?? true)
69
+
70
+ if (shouldUseSafeConnector) {
71
+ connectors.unshift(safe({
72
+ allowedDomains: [/gnosis-safe.io$/, /app.safe.global$/],
73
+ }))
74
+ }
75
+
76
+ // Retrieve the ID of the most recently connected wallet connector from storage
77
+ const recentConnectorId = localStorage?.getItem(`wagmi.recentConnectorId`)
78
+
79
+ // If WalletConnect is the most recently connected wallet or lazy loading is disabled,
80
+ // add the WalletConnect connector to the beginning of the connectors list
81
+ const walletConnect = createWalletConnectConnector({
82
+ ...props?.walletConnect,
83
+ projectId:
84
+ props?.walletConnect?.projectId ?? "ea6c5b36001c18b96e06128f14c06f40",
85
+ })
86
+ if (recentConnectorId?.includes?.("walletConnect") || !props?.lazy) {
87
+ connectors.unshift(walletConnect)
88
+ } else {
89
+ connectors.push(walletConnect)
90
+ }
91
+
92
+ if (!isWalletInstalled("coinbase")) {
93
+ const coinbase = createCoinbaseConnector(props?.coinbase ?? {
94
+ appName: "Coin Voyage",
95
+ overrideIsMetaMask: false
96
+ });
97
+ if (recentConnectorId?.includes?.("coinbaseWalletSDK") || !props?.lazy) {
98
+ connectors.unshift(coinbase)
99
+ } else {
100
+ connectors.push(coinbase)
101
+ }
102
+ }
103
+
104
+ if (props?.metaMask && !isWalletInstalled("metaMask")) {
105
+ if (recentConnectorId?.includes?.("metaMaskSDK") || !props.lazy) {
106
+ connectors.unshift(createMetaMaskConnector(props.metaMask))
107
+ }
108
+ }
109
+
110
+ const config = createConfig({
111
+ ...props?.evmConfig,
112
+ chains: DEFAULT_CHAINS,
113
+ client({ chain }) {
114
+ return createClient({ chain, transport: http() })
115
+ },
116
+ connectors,
117
+ multiInjectedProviderDiscovery
118
+ })
119
+
120
+ return {
121
+ config
122
+ }
123
+ }
@@ -0,0 +1,4 @@
1
+ import { createContext } from "react"
2
+
3
+ // This context is used when the implementing party provides a context (External Wagmi Context)
4
+ export const EVMExternalContext = createContext<boolean>(false)
@@ -0,0 +1,35 @@
1
+ import type { PaymentDetails } from "@coin-voyage/shared/api";
2
+ import { Address, erc20Abi } from "viem";
3
+ import { useSendTransaction, useWriteContract } from "wagmi";
4
+
5
+ export function useEVMTransaction(): {
6
+ execute: (paymentDetails: PaymentDetails) => Promise<string>;
7
+ } {
8
+ const { writeContractAsync } = useWriteContract();
9
+ const { sendTransactionAsync } = useSendTransaction();
10
+
11
+ const execute = async (paymentDetails: PaymentDetails) => {
12
+ const value = paymentDetails.source_amount.raw_amount
13
+ const isNative = !paymentDetails.source_currency.address
14
+ const to = paymentDetails.deposit_address as Address
15
+ const chainId = paymentDetails.source_currency.chain_id
16
+ if (!isNative) {
17
+ return sendTransactionAsync({
18
+ to,
19
+ value,
20
+ chainId,
21
+ });
22
+ }
23
+ const contractAddress = paymentDetails.source_currency.address;
24
+ const tx = await writeContractAsync({
25
+ abi: erc20Abi,
26
+ address: contractAddress as Address,
27
+ functionName: "transfer",
28
+ chainId,
29
+ args: [to, value],
30
+ });
31
+ return tx as string
32
+ }
33
+
34
+ return { execute }
35
+ }
@@ -0,0 +1,54 @@
1
+ import { ChainType } from "@coin-voyage/shared/common";
2
+ import { Connector, useAccount, useConnect, useSignMessage } from "wagmi";
3
+ import { useCombinedWallets } from "../hooks/use-combined-wallets";
4
+ import { toMessage } from "../lib/utils/message";
5
+ import { SignInMessage } from "../types";
6
+ import { SignInWith } from "../types/sign-in-with";
7
+
8
+
9
+ export function useSignInWithEvm({ signIn, callbackUrl }: SignInWith) {
10
+ const { address, connector } = useAccount();
11
+ const { connectAsync } = useConnect();
12
+
13
+ const { installedWallets } = useCombinedWallets(ChainType.EVM)
14
+ const { signMessageAsync } = useSignMessage();
15
+
16
+ const handleSignature = async (address: string) => {
17
+ const msg = {
18
+ domain: window.location.host,
19
+ address,
20
+ statement: "Sign in with Ethereum to CoinVoyage.io",
21
+ uri: window.location.origin,
22
+ nonce: Math.random().toString(),
23
+ version: "1"
24
+ } as SignInMessage;
25
+
26
+ const message = toMessage(msg, "Ethereum");
27
+ const signature = await signMessageAsync({ message });
28
+
29
+ signIn("ethereum", {
30
+ address,
31
+ message,
32
+ domain: window.location.host,
33
+ signature,
34
+ callbackUrl: callbackUrl ?? "/"
35
+ });
36
+ };
37
+
38
+ const onSelect = async (id: string) => {
39
+ const selectedWallet = installedWallets.find((w) => w.id === id);
40
+ const selectedConnector = selectedWallet?.connectors?.[0].connector as Connector | undefined;
41
+ if (!selectedConnector) return;
42
+
43
+ if (connector?.id === selectedConnector.id && address) {
44
+ handleSignature(address);
45
+ return;
46
+ }
47
+
48
+ const res = await connectAsync({ connector: selectedConnector });
49
+ if (!res.accounts[0]) return;
50
+ handleSignature(res.accounts[0]);
51
+ };
52
+
53
+ return { onSelect, installedWallets };
54
+ }
@@ -0,0 +1,3 @@
1
+ import { verifyMessage as verifyMessageInternal } from 'viem';
2
+
3
+ export const verifyMessage = verifyMessageInternal;
@@ -0,0 +1,6 @@
1
+ export * from "./use-account"
2
+ export * from "./use-account-disconnect"
3
+ export * from "./use-combined-wallets"
4
+ export * from "./use-prepare-transaction"
5
+ export * from "./use-universal-connect"
6
+
@@ -0,0 +1,47 @@
1
+ import { useConfig as useBigmiConfig } from "@bigmi/react"
2
+ import { ChainType } from "@coin-voyage/shared/common"
3
+ import { useDisconnectWallet } from "@mysten/dapp-kit"
4
+ import { useWallet } from "@solana/wallet-adapter-react"
5
+ import type { Config } from "wagmi"
6
+ import { useConfig as useWagmiConfig } from "wagmi"
7
+ import { disconnect, getAccount } from "wagmi/actions"
8
+ import type { Account } from "./use-account"
9
+
10
+ export const useAccountDisconnect = () => {
11
+ const bigmiConfig = useBigmiConfig()
12
+ const wagmiConfig = useWagmiConfig()
13
+ const { disconnect: solanaDisconnect } = useWallet()
14
+ const { mutateAsync: suiDisconnect } = useDisconnectWallet()
15
+
16
+ const handleDisconnect = async (config: Config) => {
17
+ const connectedAccount = getAccount(config)
18
+ if (connectedAccount.connector) {
19
+ await disconnect(config, { connector: connectedAccount.connector })
20
+ }
21
+ }
22
+
23
+ return async (account?: Account) => {
24
+ switch (account?.chainType) {
25
+ case ChainType.EVM:
26
+ await handleDisconnect(wagmiConfig)
27
+ break
28
+ case ChainType.UTXO:
29
+ await handleDisconnect(bigmiConfig)
30
+ break
31
+ case ChainType.SOL:
32
+ await solanaDisconnect()
33
+ break
34
+ case ChainType.SUI:
35
+ await suiDisconnect()
36
+ break
37
+ default:
38
+ // disconnect all wallets
39
+ Promise.all([
40
+ handleDisconnect(wagmiConfig),
41
+ handleDisconnect(bigmiConfig),
42
+ solanaDisconnect(),
43
+ suiDisconnect(),
44
+ ])
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,171 @@
1
+ import { useConfig as useBigmiConfig } from "@bigmi/react"
2
+ import { ChainId, ChainType } from "@coin-voyage/shared/common"
3
+ import { useCurrentAccount, useCurrentWallet } from "@mysten/dapp-kit"
4
+ import { useWallet } from "@solana/wallet-adapter-react"
5
+ import { useMemo } from "react"
6
+ import type { Connector } from "wagmi"
7
+ import { useAccount as useAccountInternal } from "wagmi"
8
+ import type { WalletAdapterExtended } from "../lib/connectors/types"
9
+ import { extendsWalletAdapter } from "../lib/connectors/utils"
10
+ import { getConnector } from "../lib/utils/connector"
11
+ import type { WalletProps } from "../types/wallet"
12
+ import { SuiConnector } from "../types/wallet-connector"
13
+
14
+ export interface AccountBase<CT extends ChainType, ConnectorType = undefined> {
15
+ address?: string
16
+ addresses?: readonly string[]
17
+ chainId?: number
18
+ chainType: CT
19
+ connector?: ConnectorType
20
+ isConnected: boolean
21
+ isConnecting: boolean
22
+ isDisconnected: boolean
23
+ isReconnecting: boolean
24
+ status: "connected" | "reconnecting" | "connecting" | "disconnected"
25
+ }
26
+
27
+ export type EVMAccount = AccountBase<ChainType.EVM, Connector>
28
+ export type SOLANAAccount = AccountBase<ChainType.SOL, WalletAdapterExtended>
29
+ export type UTXOAccount = AccountBase<ChainType.UTXO, Connector>
30
+ export type SUIAccount = AccountBase<ChainType.SUI, SuiConnector>
31
+ export type DefaultAccount = AccountBase<ChainType>
32
+
33
+ export type Account =
34
+ | EVMAccount
35
+ | SOLANAAccount
36
+ | UTXOAccount
37
+ | SUIAccount
38
+ | DefaultAccount
39
+
40
+ export interface AccountResult {
41
+ account: Account
42
+ /**
43
+ * Connected accounts
44
+ */
45
+ accounts: Account[]
46
+ }
47
+
48
+ interface UseAccountArgs {
49
+ selectedWallet: WalletProps | undefined
50
+ chainType: ChainType | undefined
51
+ }
52
+
53
+ const defaultAccount: AccountBase<ChainType> = {
54
+ chainType: ChainType.EVM,
55
+ isConnected: false,
56
+ isConnecting: false,
57
+ isReconnecting: false,
58
+ isDisconnected: true,
59
+ status: "disconnected",
60
+ }
61
+
62
+ /**
63
+ * @param args When we provide args we want to return either account with corresponding chainType or default disconnected one
64
+ * @returns - Account result
65
+ */
66
+ export const useAccount = (args?: UseAccountArgs): AccountResult => {
67
+ const bigmiConfig = useBigmiConfig()
68
+ const bigmiAccount = useAccountInternal({ config: bigmiConfig })
69
+ const wagmiAccount = useAccountInternal()
70
+ const { wallet } = useWallet()
71
+ const suiWallet = useCurrentWallet()
72
+ const suiAccount = useCurrentAccount()
73
+
74
+ const lastConnectedAccount = args?.selectedWallet
75
+ ? getConnector(args?.selectedWallet.connectors, args?.chainType)
76
+ : undefined
77
+ // biome-ignore lint/correctness/useExhaustiveDependencies:
78
+ return useMemo(() => {
79
+ const solana: Account = wallet?.adapter.publicKey
80
+ ? {
81
+ address: wallet?.adapter.publicKey.toString(),
82
+ chainId: ChainId.SOL,
83
+ chainType: ChainType.SOL,
84
+ connector: extendsWalletAdapter(wallet.adapter, wallet.adapter.name),
85
+ isConnected: Boolean(wallet?.adapter.publicKey),
86
+ isConnecting: false,
87
+ isReconnecting: false,
88
+ isDisconnected: !wallet,
89
+ status: "connected",
90
+ }
91
+ : {
92
+ chainType: ChainType.SOL,
93
+ isConnected: false,
94
+ isConnecting: false,
95
+ isReconnecting: false,
96
+ isDisconnected: true,
97
+ status: "disconnected",
98
+ }
99
+ const sui: Account = suiAccount
100
+ ? {
101
+ address: suiAccount.address,
102
+ chainId: ChainId.SUI,
103
+ chainType: ChainType.SUI,
104
+ connector: suiWallet.currentWallet ?? undefined,
105
+ isConnected: Boolean(suiWallet.connectionStatus === "connected"),
106
+ isConnecting: false,
107
+ isReconnecting: false,
108
+ isDisconnected: !suiWallet,
109
+ status: "connected",
110
+ }
111
+ : {
112
+ chainType: ChainType.SUI,
113
+ isConnected: false,
114
+ isConnecting: false,
115
+ isReconnecting: false,
116
+ isDisconnected: true,
117
+ status: "disconnected",
118
+ }
119
+ const evm: Account = { ...wagmiAccount, chainType: ChainType.EVM }
120
+ const utxo: Account = { ...bigmiAccount, chainType: ChainType.UTXO }
121
+ const accounts = [evm, solana, sui, utxo]
122
+ const connectedAccounts = accounts.filter(
123
+ (account) => account.isConnected && account.address
124
+ )
125
+
126
+ // If a chainType argument is provided, attempt to find a connected account with the matching chainType.
127
+ // If no matching account is found, fallback to the default account.
128
+ // If no chainType argument, selectedAccount should be used.
129
+ const selectedChainTypeAccount = args?.chainType
130
+ ? connectedAccounts.find(
131
+ (account) => account.chainType === args?.chainType
132
+ ) || defaultAccount
133
+ : undefined
134
+
135
+ // If lastConnectedAccount exists, attempt to find a connected account with a matching connector ID or name.
136
+ // If no matching account is found, fallback to the first connected account.
137
+ // If lastConnectedAccount is not present, simply select the first connected account.
138
+ const selectedAccount = lastConnectedAccount
139
+ ? connectedAccounts.find((account) => {
140
+ const connectorIdMatch =
141
+ (lastConnectedAccount as Connector)?.id ===
142
+ (account.connector as Connector)?.id
143
+ const connectorNameMatch =
144
+ !(lastConnectedAccount as Connector)?.id &&
145
+ (lastConnectedAccount as WalletAdapterExtended)?.name ===
146
+ account.connector?.name
147
+ return connectorIdMatch || connectorNameMatch
148
+ }) || connectedAccounts[0]
149
+ : connectedAccounts[0]
150
+
151
+ return {
152
+ account: selectedChainTypeAccount || selectedAccount || defaultAccount,
153
+ // We need to return only connected account list
154
+ accounts: connectedAccounts,
155
+ }
156
+ }, [
157
+ wallet?.adapter.publicKey,
158
+ wagmiAccount.connector?.uid,
159
+ wagmiAccount.connector?.id,
160
+ wagmiAccount.status,
161
+ wagmiAccount.address,
162
+ wagmiAccount.chainId,
163
+ bigmiAccount.connector?.uid,
164
+ bigmiAccount.connector?.id,
165
+ bigmiAccount.status,
166
+ bigmiAccount.address,
167
+ bigmiAccount.chainId,
168
+ args?.chainType,
169
+ lastConnectedAccount,
170
+ ])
171
+ }