@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.
- package/package.json +67 -0
- package/src/assets/icons.tsx +16 -0
- package/src/evm/base-provider.tsx +22 -0
- package/src/evm/create-default-evm-config.ts +123 -0
- package/src/evm/external-context.ts +4 -0
- package/src/evm/use-evm-transaction.ts +35 -0
- package/src/evm/use-sign-in-with-evm.ts +54 -0
- package/src/evm/verify-message.ts +3 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/use-account-disconnect.ts +47 -0
- package/src/hooks/use-account.ts +171 -0
- package/src/hooks/use-combined-wallets.ts +165 -0
- package/src/hooks/use-prepare-transaction.ts +32 -0
- package/src/hooks/use-universal-connect.ts +141 -0
- package/src/lib/config/chain.ts +13 -0
- package/src/lib/connectors/coinbase.ts +9 -0
- package/src/lib/connectors/metaMask.ts +6 -0
- package/src/lib/connectors/types.ts +12 -0
- package/src/lib/connectors/utils.ts +23 -0
- package/src/lib/connectors/walletConnect.ts +18 -0
- package/src/lib/utils/connector.ts +22 -0
- package/src/lib/utils/get-connector-icon.ts +13 -0
- package/src/lib/utils/get-wallet-priority.ts +15 -0
- package/src/lib/utils/is-wallet-installed.ts +40 -0
- package/src/lib/utils/message.ts +29 -0
- package/src/solana/base-provider.tsx +29 -0
- package/src/solana/external-context.ts +3 -0
- package/src/solana/get-or-create-ata.ts +85 -0
- package/src/solana/use-solana-transaction.ts +83 -0
- package/src/sui/base-provider.tsx +22 -0
- package/src/sui/client.ts +3 -0
- package/src/sui/constants.ts +5 -0
- package/src/sui/external-context.ts +3 -0
- package/src/sui/use-sign-in-with-sui.ts +55 -0
- package/src/sui/use-sui-transaction.ts +56 -0
- package/src/sui/verify-message.ts +18 -0
- package/src/types/index.ts +29 -0
- package/src/types/sign-in-with.ts +13 -0
- package/src/types/utxo-connector-id.ts +10 -0
- package/src/types/wallet-connector.ts +14 -0
- package/src/types/wallet.ts +55 -0
- package/src/utxo/base-provider.tsx +24 -0
- package/src/utxo/create-default-bigmi-config.ts +69 -0
- package/src/utxo/create-psbt-tx.ts +72 -0
- package/src/utxo/external-context.ts +3 -0
- package/src/utxo/get-address-utxo.ts +36 -0
- package/src/utxo/send-btc.ts +223 -0
- package/src/utxo/use-utxo-transaction.tsx +28 -0
- package/src/utxo/utxo-public-client.ts +60 -0
- 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,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,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
|
+
}
|