From db2feb88424d071a61f2c70caf090702bbe17e41 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 11 Apr 2024 19:50:28 -0400 Subject: [PATCH] wallet connection fixes --- src/blockchain/prices.js | 2 +- src/blockchain/route.js | 3 +- src/blockchain/token.js | 5 +- src/blockchain/wallet.js | 100 +++++++++++++++++++------------ src/components/CopyButton.vue | 2 +- src/components/NeedsProvider.vue | 72 ++++++++++------------ src/components/NeedsSigner.vue | 89 ++++++++++++++++++++++++--- src/components/Status.vue | 1 + src/store/store.js | 28 ++------- 9 files changed, 188 insertions(+), 114 deletions(-) diff --git a/src/blockchain/prices.js b/src/blockchain/prices.js index 8273d07..bb76c25 100644 --- a/src/blockchain/prices.js +++ b/src/blockchain/prices.js @@ -5,6 +5,7 @@ import {uniswapV3PoolAddress} from "@/blockchain/uniswap.js"; import {ethers, FixedNumber} from "ethers"; import {uniswapV3PoolAbi} from "@/blockchain/abi.js"; import {subOHLCs} from "@/blockchain/ohlcs.js"; +import {provider} from "@/blockchain/wallet.js"; const subscriptionCounts = {} // key is route and value is a subscription counter export const WIDE_PRICE_FORMAT = {decimals:38, width:512, signed:false}; // 38 decimals is 127 bits @@ -79,7 +80,6 @@ async function getPriceForRoute(route) { if( route.exchange === Exchange.UniswapV3 ) { const addr = uniswapV3PoolAddress(route.chainId, route.token0.address, route.token1.address, route.fee) const store = useStore(); - const provider = store.provider; if( provider === null ) { console.error('provider was null during getPriceForRoute') return null diff --git a/src/blockchain/route.js b/src/blockchain/route.js index 21d127f..0f1a36f 100644 --- a/src/blockchain/route.js +++ b/src/blockchain/route.js @@ -2,6 +2,7 @@ import {Exchange} from "@/blockchain/orderlib.js"; import {useOrderStore, useStore} from "@/store/store.js"; import {queryHelperContract} from "@/blockchain/contract.js"; import {SingletonCoroutine} from "@/misc.js"; +import {provider} from "@/blockchain/wallet.js"; export async function findRoute(helper, chainId, tokenA, tokenB) { @@ -40,7 +41,7 @@ async function componentFindRoute() { os.routesPending = true try { console.log('getting query helper') - const helper = await queryHelperContract(s.helper, s.provider) + const helper = await queryHelperContract(s.helper, provider) if (!helper) { console.log('no helper') } else { diff --git a/src/blockchain/token.js b/src/blockchain/token.js index ac3370e..702205d 100644 --- a/src/blockchain/token.js +++ b/src/blockchain/token.js @@ -3,6 +3,7 @@ import {useStore} from "@/store/store.js"; import {erc20Abi} from "@/blockchain/abi.js"; import {ethers} from "ethers"; import {metadata, metadataMap} from "@/version.js"; +import {provider} from "@/blockchain/wallet.js"; // synchronous version may return null but will trigger a lookup @@ -58,12 +59,12 @@ export async function addExtraToken(chainId, addr) { resolve(info) } else { - if( s.provider===null ) { + if( provider===null ) { console.log('warning: token lookup cancelled due to null provider', addr) resolve(null) } else { - const token = new ethers.Contract(addr, erc20Abi, s.provider) + const token = new ethers.Contract(addr, erc20Abi, provider) Promise.all( [token.name(), token.symbol(), token.decimals()] ).then((name,symbol,decimals)=>{ info = { a: addr, diff --git a/src/blockchain/wallet.js b/src/blockchain/wallet.js index 0eedf98..3da7735 100644 --- a/src/blockchain/wallet.js +++ b/src/blockchain/wallet.js @@ -1,4 +1,4 @@ -import {ethers} from "ethers"; +import {BrowserProvider, ethers} from "ethers"; import {useStore} from "@/store/store"; import {socket} from "@/socket.js"; import {contractOrNull, vaultAddress} from "@/blockchain/contract.js"; @@ -9,6 +9,9 @@ import {ref} from "vue"; import {metadataMap} from "@/version.js"; +export let provider = null + + export const useWalletStore = defineStore('wallet', ()=>{ // this is what the wallet is logged into. it could be different than the application's store.chainId. const chainId = ref(0) @@ -31,6 +34,7 @@ export const useWalletStore = defineStore('wallet', ()=>{ export function onChainChanged(chainId) { + console.log('onChainChanged', chainId) chainId = Number(chainId) const store = useStore() const ws = useWalletStore() @@ -41,6 +45,8 @@ export function onChainChanged(chainId) { console.log('app chain changed', chainId) store.chainId = chainId store.account = null + provider = new BrowserProvider(window.ethereum, chainId) + updateAccounts(chainId, provider) } else { console.log('app chain NOT changed') @@ -77,6 +83,7 @@ function changeAccounts(chainId, accounts) { } function onAccountsChanged(accounts) { + console.log('onAccountsChanged', accounts) const store = useStore() const ws = useWalletStore() if (accounts.length === 0 || accounts[0] !== store.account) @@ -84,11 +91,17 @@ function onAccountsChanged(accounts) { } export function detectChain() { + try { + window.ethereum.on('chainChanged', onChainChanged); + window.ethereum.on('accountsChanged', onAccountsChanged); + } + catch (e) { + console.log('Could not connect change hooks to wallet', e) + return + } new ethers.BrowserProvider(window.ethereum).getNetwork().then((network)=>{ const chainId = network.chainId onChainChanged(chainId) - window.ethereum.on('chainChanged', onChainChanged); - window.ethereum.on('accountsChanged', onAccountsChanged); }) } @@ -125,50 +138,50 @@ const errorHandlingProxy = { } -export async function connectProvider(chainId) { - console.log('connectProvider', chainId) - try { - return new ethers.BrowserProvider(window.ethereum, chainId) - } - catch (e) { - console.log('provider error', e) - } - return null -} - - export async function connectWallet(chainId) { console.log('connectWallet', chainId) - const ws = useWalletStore() - if (ws.chainId !== chainId && !await switchChain(chainId)) - return null - const p = await connectProvider(chainId) - if (p!==null) { + await switchChain(chainId) + if (provider!==null) { try { console.log('getSigner') - return await p.getSigner(); + await provider.getSigner() + await updateAccounts(chainId, provider) } catch (e) { if (e.reason!=='rejected') console.error(e, e.reason) - return null } } + else + console.error('provider was null after chain switch') } export async function switchChain(chainId) { if (useWalletStore().chainId === chainId) - return true - try { - await window.ethereum.request({ - "method": "wallet_switchEthereumChain", - "params": [{"chainId": '0x' + chainId.toString(16)}] - }) - return true - } catch (e) { - return false - } + return + await window.ethereum.request({ + "method": "wallet_switchEthereumChain", + "params": [{"chainId": '0x' + chainId.toString(16)}] + }) +} + + +export async function addTestnet() { + const info = { + "chainId": "0x539", + "chainName": "Dexorder Alpha Testnet", + "rpcUrls": ["https://rpc.alpha.dexorder.trade"], + "nativeCurrency": { + "name": "Test Ethereum", + "symbol": "TETH", + "decimals": 18 + } + }; + await window.ethereum.request({ + "method": "wallet_addEthereumChain", + "params": [info] + }); } @@ -198,7 +211,7 @@ async function _discoverVaults(owner) { s.vaults = [] return } - const provider = s.provider; + console.log('provider', provider) if (!provider) { console.log('No provider') return // do not change whatever was already found @@ -350,10 +363,19 @@ function pendOrderAsTransaction(pend) { console.error('vault contract was null while sending order transaction', pend.vault) return null } - if (!await switchChain(pend.chainId)) { - console.log('user refused chain switch') - pend.state = PendingOrderState.Rejected - return null + try { + await switchChain(pend.chainId) + } + catch (e) { + if(e.code===4001) { + console.log('user refused chain switch') + pend.state = PendingOrderState.Rejected + return null + } + else { + console.error('Unknown error while switching chain to pend order', e) + return null + } } console.log('placing order', pend.id) const tx = await contract.placeDexorder(pend.order) // todo update status @@ -393,7 +415,7 @@ export function flushTransactions() { async function asyncFlushTransactions() { const s = useStore() - if( s.provider === null ) { + if( provider === null ) { console.log('warning: asyncFlushOrders() cancelled due to null provider') return } @@ -403,7 +425,7 @@ async function asyncFlushTransactions() { console.log(`flushing ${senders.length} transactions`) let signer try { - signer = await s.provider.getSigner(); + signer = await provider.getSigner(); } catch (e) { // { // "code": -32002, diff --git a/src/components/CopyButton.vue b/src/components/CopyButton.vue index 7ea4c6b..4b9345e 100644 --- a/src/components/CopyButton.vue +++ b/src/components/CopyButton.vue @@ -7,7 +7,7 @@ :icon="error?'mdi-close-box-outline':copied?'mdi-check-circle-outline':'mdi-content-copy'" :text="showText?text:''" /> - + {{text}} Copied! diff --git a/src/components/NeedsProvider.vue b/src/components/NeedsProvider.vue index 7720ce2..eee2cc1 100644 --- a/src/components/NeedsProvider.vue +++ b/src/components/NeedsProvider.vue @@ -10,20 +10,24 @@

+ +
+ TODO + +–>

 Welcome to Dexorder Alpha!

This alpha test runs on the Dexorder Testnet blockchain, which gives you free testnet tokens to trade. @@ -52,54 +56,42 @@ Open Metamask again and select the "Dexorder Alpha" blockchain for use with this website. +-->

diff --git a/src/components/Status.vue b/src/components/Status.vue index 18da8ee..9988965 100644 --- a/src/components/Status.vue +++ b/src/components/Status.vue @@ -266,6 +266,7 @@ const orders = computed(()=>{ st.token1 = o.tokenIn < o.tokenOut ? o.tokenOut : o.tokenIn } } + result.sort((a,b)=>b.start-a.start) console.log('orders', result) return result }) diff --git a/src/store/store.js b/src/store/store.js index 5b9af52..69fe64f 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -3,8 +3,6 @@ import {defineStore} from 'pinia' import {knownTokens} from "@/knownTokens.js"; import {computed, ref} from "vue"; import {version} from "@/version.js"; -import {ethers} from "ethers"; -import {updateAccounts} from "@/blockchain/wallet.js"; // USING THE STORE: // @@ -70,9 +68,9 @@ export const useStore = defineStore('app', ()=> { _chainId.value = v account.value = null } - if (changed || _provider.value === null) { + if (changed || providerRef.value === null) { console.log('invalidating provider') - _provider.value = UNKNOWN_PROVIDER + providerRef.value = UNKNOWN_PROVIDER } } }) @@ -82,22 +80,8 @@ export const useStore = defineStore('app', ()=> { }) const chain = computed(() => !_chainId.value ? null : (_chainInfo.value[_chainId.value] || null)) // this provider is for the app's chainId not the wallet's chainId. - let _provider = UNKNOWN_PROVIDER // null indicates a known-unavailable provider whereas undefined means provider status is unknown - const provider = computed(()=>{ - if (_provider===UNKNOWN_PROVIDER) { - // unknown provider status - try { - _provider = new ethers.BrowserProvider(window.ethereum, _chainId.value); - updateAccounts(_chainId.value, _provider) - } - catch (e) { - console.error('could not get provider', _chainId.value, e) - _provider = null - } - } - // if _provider is null then it is known to be an unavailable chain - return _provider - }) + const providerRef = ref(null) + const provider = computed(()=>providerRef.value) const vaultInitCodeHash = computed(() => !chain.value ? null : chain.value.vaultInitCodeHash) const account = ref(null) const vaults = ref([]) @@ -140,8 +124,8 @@ export const useStore = defineStore('app', ()=> { setInterval(()=>clock.value=timestamp(), 10*1000) return { - nav, chainId, chainInfo, chain, provider, vaultInitCodeHash, account, vaults, transactionSenders, errors, - extraTokens, poolPrices, vaultBalances, orders, vault, tokens, factory, helper, mockenv, mockCoins, + nav, chainId, chainInfo, chain, provider, providerRef, vaultInitCodeHash, account, vaults, transactionSenders, + errors, extraTokens, poolPrices, vaultBalances, orders, vault, tokens, factory, helper, mockenv, mockCoins, removeTransactionSender, error, closeError, addToken, clock, balances, } })