Compare commits

...

4 Commits

7 changed files with 7775 additions and 1073 deletions

5731
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -15,9 +15,10 @@
"dependencies": { "dependencies": {
"@isaacs/ttlcache": "^1.4.1", "@isaacs/ttlcache": "^1.4.1",
"@mdi/font": "6.9.96", "@mdi/font": "6.9.96",
"@web3modal/ethers": "^5.1.11",
"color": "^4.2.3", "color": "^4.2.3",
"core-js": "^3.29.0", "core-js": "^3.29.0",
"ethers": "^6.7.1", "ethers": "^6.16.0",
"flexsearch": "^0.7.43", "flexsearch": "^0.7.43",
"lru-cache": "^11.0.2", "lru-cache": "^11.0.2",
"luxon": "^3.4.4", "luxon": "^3.4.4",

View File

@@ -9,6 +9,7 @@ import {metadataMap, version} from "@/version.js";
import {TransactionState, TransactionType} from "@/blockchain/transactionDecl.js"; import {TransactionState, TransactionType} from "@/blockchain/transactionDecl.js";
import {track} from "@/track.js"; import {track} from "@/track.js";
import {socket} from "@/socket.js"; import {socket} from "@/socket.js";
import {web3modal} from "@/blockchain/web3modal.js";
export const useWalletStore = defineStore('wallet', ()=>{ export const useWalletStore = defineStore('wallet', ()=>{
@@ -131,7 +132,8 @@ export function detectChain() {
} }
} }
detectChain() // Commented out - Web3Modal handles wallet detection now
// detectChain()
const errorHandlingProxy = { const errorHandlingProxy = {
get(target, prop, proxy) { get(target, prop, proxy) {
@@ -166,29 +168,123 @@ const errorHandlingProxy = {
export async function connectWallet(chainId) { export async function connectWallet(chainId) {
console.log('connectWallet', chainId) console.log('connectWallet via Web3Modal', chainId)
try {
await switchChain(chainId) // Return a promise that resolves when connection is complete
console.log('getSigner') return new Promise((resolve, reject) => {
const p = new BrowserProvider(window.ethereum, chainId) let resolved = false
await p.getSigner() let unsubscribeProvider = null
await updateAccounts(chainId, p) let unsubscribeState = null
}
catch (e) { // Subscribe to provider changes (fires when wallet connects)
console.log('connectWallet error', e.reason, e) unsubscribeProvider = web3modal.subscribeProvider(async (newState) => {
if (e.reason==='rejected') { console.log('Provider state changed:', newState)
const ws = useWalletStore();
const tx = ws.transaction if (newState.provider && !resolved) {
if (tx) { resolved = true
tx.state = TransactionState.Rejected unsubscribeProvider?.()
ws.transaction = null unsubscribeState?.()
try {
const walletProvider = newState.provider
// Create ethers provider from Web3Modal provider
const p = new BrowserProvider(walletProvider)
setProvider(p)
// Get network info from the provider
const network = await p.getNetwork()
const connectedChainId = Number(network.chainId)
console.log('Connected to chain', connectedChainId)
// Update wallet store
const ws = useWalletStore()
ws.chainId = connectedChainId
// Get accounts
await updateAccounts(connectedChainId, p)
// Subscribe to Web3Modal provider events
subscribeToProviderEvents(walletProvider)
resolve()
} catch (e) {
console.error('Error after connection', e)
reject(e)
}
} }
})
// Subscribe to modal state (fires when modal opens/closes)
unsubscribeState = web3modal.subscribeState((state) => {
// If modal closes without connection, resolve the promise
if (state.open === false && !resolved) {
console.log('Modal closed without connection')
resolved = true
unsubscribeProvider?.()
unsubscribeState?.()
resolve() // Resolve (not reject) so the button re-enables
}
})
// Open the modal
web3modal.open().catch((e) => {
if (!resolved) {
resolved = true
unsubscribeProvider?.()
unsubscribeState?.()
if (e.reason === 'rejected' || e.message?.includes('rejected')) {
const ws = useWalletStore();
const tx = ws.transaction
if (tx) {
tx.state = TransactionState.Rejected
ws.transaction = null
}
resolve() // Don't reject on user cancellation
} else {
reject(e)
}
}
})
// Timeout after 60 seconds
setTimeout(() => {
if (!resolved) {
resolved = true
unsubscribeProvider?.()
unsubscribeState?.()
console.log('Connection timeout')
resolve() // Resolve instead of reject so button re-enables
}
}, 60000)
})
}
// Subscribe to provider events from Web3Modal
function subscribeToProviderEvents(walletProvider) {
// Handle account changes
walletProvider.on('accountsChanged', (accounts) => {
console.log('accountsChanged from Web3Modal', accounts)
if (accounts.length === 0) {
disconnectWallet()
} else {
onAccountsChanged(accounts)
} }
else { })
console.error(e, e.reason)
throw e // Handle chain changes
} walletProvider.on('chainChanged', (chainId) => {
} console.log('chainChanged from Web3Modal', chainId)
onChainChanged(chainId)
})
// Handle disconnect
walletProvider.on('disconnect', () => {
console.log('Provider disconnected from Web3Modal')
disconnectWallet()
})
} }
@@ -637,21 +733,7 @@ export async function addNetwork(chainId) {
} }
export async function addNetworkAndConnectWallet(chainId) { export async function addNetworkAndConnectWallet(chainId) {
try {
await switchChain(chainId)
} catch (e) {
if (e.code === 4001) {
// explicit user rejection
return
} else if (e.code === 4902) {
try {
await addNetwork(chainId)
} catch (e) {
console.log(`Could not add network ${chainId}`)
}
} else
console.log('switchChain() failure', e)
}
try { try {
await connectWallet(chainId) await connectWallet(chainId)
} catch (e) { } catch (e) {
@@ -659,3 +741,44 @@ export async function addNetworkAndConnectWallet(chainId) {
console.log('connectWallet() failed', e) console.log('connectWallet() failed', e)
} }
} }
export async function disconnectWallet() {
console.log('disconnectWallet')
const store = useStore()
const ws = useWalletStore()
// Disconnect from Web3Modal
try {
await web3modal.disconnect()
} catch (e) {
console.log('Web3Modal disconnect error (ignoring)', e)
}
// Clear provider
setProvider(null)
// Clear account and vaults
store.account = null
store.vaults = []
store.vaultVersions = []
// Clear any pending transactions
if (ws.transaction !== null) {
ws.transaction = null
}
ws.pendingOrders = []
// Clear transaction senders
store.transactionSenders = []
// Emit socket disconnect
socket.emit('address', ws.chainId, null)
track('logout', {chainId: ws.chainId})
console.log('Wallet disconnected')
}
// Make it globally accessible from console
if (typeof window !== 'undefined') {
window.disconnectWallet = disconnectWallet
}

View File

@@ -0,0 +1,53 @@
// src/blockchain/web3modal.js
import { createWeb3Modal, defaultConfig } from '@web3modal/ethers'
const projectId = 'a2302c95fedb32f4c64672a41159df37' // Get from https://cloud.walletconnect.com
const chains = [
{
chainId: 42161,
name: 'Arbitrum One',
currency: 'ETH',
explorerUrl: 'https://arbiscan.io',
rpcUrl: 'https://arbitrum-mainnet.infura.io'
},
{
chainId: 1337,
name: 'Dexorder Alpha Testnet',
currency: 'TETH',
explorerUrl: '',
rpcUrl: 'https://rpc.alpha.dexorder.com'
},
{
chainId: 31337,
name: 'Mockchain',
currency: 'TETH',
explorerUrl: '',
rpcUrl: 'http://localhost:8545'
}
]
const ethersConfig = defaultConfig({
metadata: {
name: 'Dexorder',
description: 'Dexorder Trading Platform',
url: window.location.origin,
icons: ['https://your-icon-url.com']
},
defaultChainId: 42161,
enableEIP6963: false, // Disable to prevent wallets from auto-announcing
enableInjected: true,
enableCoinbase: true,
rpcUrl: 'https://arbitrum-mainnet.infura.io'
})
export const web3modal = createWeb3Modal({
ethersConfig,
chains,
projectId,
enableAnalytics: false,
themeMode: 'dark',
featuredWalletIds: [
'c57ca95b47569778a828d19178114f4db188b89b763c899ba0be274e97267d96' // MetaMask
],
})

View File

@@ -28,8 +28,8 @@
</div> </div>
<v-card-actions v-if="status>Status.NEEDS_PLUGIN"> <v-card-actions v-if="status>Status.NEEDS_PLUGIN">
<btn v-if="pluginOk" icon="mdi-wallet-outline" color="warning" variant="outlined" <btn v-if="pluginOk" icon="mdi-wallet-outline" color="green-accent-4" variant="flat"
@click="connect" :disabled="disabled" text="Connect Wallet"/> @click="connect" :disabled="disabled" text="Connect Wallet" class="connect-wallet-btn"/>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
@@ -87,4 +87,16 @@ async function connect() {
#manualsetup tr td:last-child { #manualsetup tr td:last-child {
padding-left: 1em; padding-left: 1em;
} }
:deep(.connect-wallet-btn) {
background-color: #00ff41 !important;
color: #000 !important;
font-weight: 600;
box-shadow: 0 0 8px rgba(0, 255, 65, 0.3) !important;
}
:deep(.connect-wallet-btn:hover) {
background-color: #00cc34 !important;
box-shadow: 0 0 12px rgba(0, 255, 65, 0.4) !important;
}
</style> </style>

View File

@@ -15,6 +15,11 @@ import { registerPlugins } from '@/plugins'
import '@/styles/style.scss' import '@/styles/style.scss'
import "./socketInit.js" import "./socketInit.js"
import "./version.js" import "./version.js"
import { web3modal } from '@/blockchain/web3modal.js'
import { BrowserProvider } from 'ethers'
import { setProvider } from '@/blockchain/provider.js'
import { updateAccounts } from '@/blockchain/wallet.js'
import { useWalletStore } from '@/blockchain/wallet.js'
BigInt.prototype.toJSON = function() { return this.toString() } BigInt.prototype.toJSON = function() { return this.toString() }
@@ -22,3 +27,24 @@ const app = createApp(App)
registerPlugins(app) registerPlugins(app)
app.mount('#app') app.mount('#app')
window.$vuetify = app window.$vuetify = app
// Check if Web3Modal has an existing connection on app start
web3modal.subscribeProvider(async (state) => {
if (state.isConnected && state.provider) {
try {
console.log('Restoring existing Web3Modal connection')
const p = new BrowserProvider(state.provider)
setProvider(p)
const network = await p.getNetwork()
const chainId = Number(network.chainId)
const ws = useWalletStore()
ws.chainId = chainId
await updateAccounts(chainId, p)
} catch (e) {
console.log('Error restoring connection', e)
}
}
})

2822
yarn.lock

File diff suppressed because it is too large Load Diff