Compare commits
11 Commits
f0f431b34e
...
stuff
| Author | SHA1 | Date | |
|---|---|---|---|
| 2bda184bba | |||
| 069fb31f82 | |||
| 7965eab85b | |||
| 321b250de0 | |||
| ed03740852 | |||
| a3c1dfad2d | |||
| 9b410ace09 | |||
| 72b061749d | |||
| a42f228984 | |||
| 47b33a152d | |||
| ecffd976ac |
@@ -1,2 +1,2 @@
|
||||
VITE_WS_URL=wss://ws.dexorder.com
|
||||
VITE_SHARE_URL=https://dexorder.com
|
||||
VITE_SHARE_URL=https://app.dexorder.com
|
||||
|
||||
5731
package-lock.json
generated
Normal file
5731
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -15,9 +15,10 @@
|
||||
"dependencies": {
|
||||
"@isaacs/ttlcache": "^1.4.1",
|
||||
"@mdi/font": "6.9.96",
|
||||
"@web3modal/ethers": "^5.1.11",
|
||||
"color": "^4.2.3",
|
||||
"core-js": "^3.29.0",
|
||||
"ethers": "^6.7.1",
|
||||
"ethers": "^6.16.0",
|
||||
"flexsearch": "^0.7.43",
|
||||
"lru-cache": "^11.0.2",
|
||||
"luxon": "^3.4.4",
|
||||
|
||||
@@ -22,6 +22,7 @@ export class Transaction {
|
||||
}
|
||||
|
||||
submit() {
|
||||
console.log('submitting transaction', this.type)
|
||||
const ws = useWalletStore();
|
||||
if ( ws.transaction !== null ) {
|
||||
console.error('Transaction already in progress', ws.transaction)
|
||||
@@ -32,6 +33,7 @@ export class Transaction {
|
||||
|
||||
// "propose" means attach the transaction to a specific vault
|
||||
propose(owner, vault) {
|
||||
console.log('transaction bind', owner, vault)
|
||||
if (this.vault !== null && this.vault !== vault) {
|
||||
this.failed('proposed vault did not match withdrawl vault', vault, this.vault)
|
||||
return
|
||||
|
||||
@@ -9,6 +9,7 @@ import {metadataMap, version} from "@/version.js";
|
||||
import {TransactionState, TransactionType} from "@/blockchain/transactionDecl.js";
|
||||
import {track} from "@/track.js";
|
||||
import {socket} from "@/socket.js";
|
||||
import {web3modal} from "@/blockchain/web3modal.js";
|
||||
|
||||
|
||||
export const useWalletStore = defineStore('wallet', ()=>{
|
||||
@@ -33,12 +34,14 @@ export const useWalletStore = defineStore('wallet', ()=>{
|
||||
set(v) {
|
||||
_tx.value = v;
|
||||
if (v===null) {
|
||||
console.log('clear transaction')
|
||||
if (progressionInvoker!==null) {
|
||||
clearTimeout(progressionInvoker)
|
||||
progressionInvoker = null
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log('set transaction', v)
|
||||
transactionProgressor.invoke();
|
||||
if (progressionInvoker===null)
|
||||
progressionInvoker = setInterval(()=>transactionProgressor.invoke(), 1000)
|
||||
@@ -129,7 +132,8 @@ export function detectChain() {
|
||||
}
|
||||
}
|
||||
|
||||
detectChain()
|
||||
// Commented out - Web3Modal handles wallet detection now
|
||||
// detectChain()
|
||||
|
||||
const errorHandlingProxy = {
|
||||
get(target, prop, proxy) {
|
||||
@@ -164,29 +168,123 @@ const errorHandlingProxy = {
|
||||
|
||||
|
||||
export async function connectWallet(chainId) {
|
||||
console.log('connectWallet', chainId)
|
||||
console.log('connectWallet via Web3Modal', chainId)
|
||||
|
||||
// Return a promise that resolves when connection is complete
|
||||
return new Promise((resolve, reject) => {
|
||||
let resolved = false
|
||||
let unsubscribeProvider = null
|
||||
let unsubscribeState = null
|
||||
|
||||
// Subscribe to provider changes (fires when wallet connects)
|
||||
unsubscribeProvider = web3modal.subscribeProvider(async (newState) => {
|
||||
console.log('Provider state changed:', newState)
|
||||
|
||||
if (newState.provider && !resolved) {
|
||||
resolved = true
|
||||
unsubscribeProvider?.()
|
||||
unsubscribeState?.()
|
||||
|
||||
try {
|
||||
await switchChain(chainId)
|
||||
console.log('getSigner')
|
||||
const p = new BrowserProvider(window.ethereum, chainId)
|
||||
await p.getSigner()
|
||||
await updateAccounts(chainId, p)
|
||||
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)
|
||||
}
|
||||
catch (e) {
|
||||
console.log('connectWallet error', e.reason, e)
|
||||
if (e.reason==='rejected') {
|
||||
}
|
||||
})
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.error(e, e.reason)
|
||||
throw e
|
||||
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)
|
||||
}
|
||||
})
|
||||
|
||||
// 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()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -242,7 +340,7 @@ async function _discoverVaults(owner) {
|
||||
if( useWalletStore().transaction ) {
|
||||
const num = 0 // todo multiple vaults
|
||||
if (result.length)
|
||||
flushOrders(s.chainId, owner, num, result[0])
|
||||
flushWalletTransactions(s.chainId, owner, num, result[0])
|
||||
else
|
||||
ensureVault2(s.chainId, owner, num)
|
||||
}
|
||||
@@ -284,7 +382,7 @@ async function doEnsureVault(chainId, owner, num) {
|
||||
if (s.vaults.length <= num)
|
||||
await _discoverVaults(owner)
|
||||
if( s.vaults[num] )
|
||||
flushOrders(chainId, owner, num, s.vaults[num])
|
||||
flushWalletTransactions(chainId, owner, num, s.vaults[num])
|
||||
else {
|
||||
console.log(`requesting vault ${owner} ${num}`)
|
||||
socket.emit('ensureVault', chainId, owner, num)
|
||||
@@ -309,11 +407,13 @@ export async function cancelOrder(vault, orderIndex) {
|
||||
async function progressTransactions() {
|
||||
const s = useStore()
|
||||
const ws = useWalletStore();
|
||||
console.log('progressTransactions', ws.transaction)
|
||||
if( ws.transaction===null )
|
||||
return
|
||||
if( s.account === null ) {
|
||||
let signer = null
|
||||
try {
|
||||
console.log('account is null. requesting sign-in.')
|
||||
signer = await provider.getSigner()
|
||||
}
|
||||
catch (e) {
|
||||
@@ -333,11 +433,27 @@ async function progressTransactions() {
|
||||
}
|
||||
}
|
||||
if( s.vault === null ) {
|
||||
console.log('vault is null. requesting vault creation.')
|
||||
ensureVault()
|
||||
return
|
||||
}
|
||||
if( ws.transaction.state < TransactionState.Proposed )
|
||||
ws.transaction.propose(s.account, s.vault)
|
||||
if( ws.transaction.type === TransactionType.PlaceOrder ) {
|
||||
flushOrders(s.chainId, s.account, 0, s.vault)
|
||||
flushWalletTransactions(s.chainId, s.account, 0, s.vault)
|
||||
}
|
||||
else {
|
||||
console.log('flushing transaction', ws.transaction.type)
|
||||
if (ws.transaction.state < TransactionState.Proposed) {
|
||||
pendTransaction(async (signer) => {
|
||||
if (signer.address !== ws.transaction.owner) {
|
||||
console.error('signer address does not match transaction owner', signer.address, ws.transaction.owner)
|
||||
return
|
||||
}
|
||||
const contract = await vaultContract(ws.transaction.vault, signer)
|
||||
return await ws.transaction.createTx(contract)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,12 +462,10 @@ const transactionProgressor = new SingletonCoroutine(progressTransactions, 10)
|
||||
let progressionInvoker = null
|
||||
|
||||
|
||||
export function flushOrders(chainId, owner, num, vault) {
|
||||
export function flushWalletTransactions(chainId, owner, num, vault) {
|
||||
const ws = useWalletStore();
|
||||
console.log('flushOrders', chainId, owner, num, vault)
|
||||
if (ws.transaction!==null && ws.transaction.type === TransactionType.PlaceOrder && ws.transaction.state < TransactionState.Proposed)
|
||||
ws.transaction.propose(owner, vault)
|
||||
let needsFlush = false
|
||||
console.log('flushWalletTransactions', chainId, owner, num, vault)
|
||||
let needsFlush = ws.transaction !== null && ws.transaction.type !== TransactionType.PlaceOrder
|
||||
for( const pend of ws.pendingOrders ) {
|
||||
if (pend.vault === null)
|
||||
pend.vault = vault
|
||||
@@ -420,6 +534,7 @@ function pendOrderAsTransaction(pend) {
|
||||
|
||||
|
||||
export function pendTransaction(sender, errHandler) {
|
||||
console.log('pendTransaction')
|
||||
const s = useStore()
|
||||
s.transactionSenders.push([sender,errHandler])
|
||||
flushTransactions()
|
||||
@@ -438,6 +553,7 @@ async function asyncFlushTransactions() {
|
||||
console.log('flushTransactions', ws.transaction, s.vault)
|
||||
if (ws.transaction !== null) {
|
||||
if (s.vault === null) {
|
||||
console.log('transaction doesn\'t have a vault. creating one.')
|
||||
await ensureVault()
|
||||
if (s.vault === null) {
|
||||
console.error('vault could not be created')
|
||||
@@ -455,8 +571,10 @@ async function asyncFlushTransactions() {
|
||||
return
|
||||
}
|
||||
const senders = s.transactionSenders
|
||||
if (!senders.length)
|
||||
if (!senders.length) {
|
||||
console.log('no transactionSenders!')
|
||||
return
|
||||
}
|
||||
console.log(`flushing ${senders.length} transactions`)
|
||||
let signer
|
||||
try {
|
||||
@@ -615,21 +733,7 @@ export async function addNetwork(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 {
|
||||
await connectWallet(chainId)
|
||||
} catch (e) {
|
||||
@@ -637,3 +741,44 @@ export async function addNetworkAndConnectWallet(chainId) {
|
||||
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
|
||||
}
|
||||
|
||||
53
src/blockchain/web3modal.js
Normal file
53
src/blockchain/web3modal.js
Normal 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
|
||||
],
|
||||
})
|
||||
@@ -158,6 +158,7 @@ export function initTVButtons() {
|
||||
}
|
||||
|
||||
export function initWidget(el) {
|
||||
getAllSymbols()
|
||||
const symbol = prefs.selectedTicker === null ? 'default' : prefs.selectedTicker
|
||||
const interval = prefs.selectedTimeframe === null ? '15' : prefs.selectedTimeframe
|
||||
widget = window.tvWidget = new TradingView.widget({
|
||||
|
||||
@@ -6,7 +6,7 @@ import {useChartOrderStore} from "@/orderbuild.js";
|
||||
import {useStore} from "@/store/store.js";
|
||||
import {subOHLC, unsubOHLC} from "@/blockchain/ohlcs.js";
|
||||
import {ohlcStart} from "@/charts/chart-misc.js";
|
||||
import {timestamp} from "@/common.js";
|
||||
import {timestamp, withTimeout} from "@/common.js";
|
||||
import {erc20Contract} from "@/blockchain/contract.js";
|
||||
import {track} from "@/track.js";
|
||||
|
||||
@@ -140,7 +140,7 @@ function addSymbol(chainId, p, base, quote, inverted) {
|
||||
// console.log(`invertedDefault(${symbolInfo.base.s}, ${symbolInfo.quote.s})`,invertedDefault(symbolInfo.base.a, symbolInfo.quote.a))
|
||||
// }
|
||||
if (defaultSymbol===null && !invertedDefault(symbolInfo.base.a, symbolInfo.quote.a)) {
|
||||
// console.log('setting default symbol', symbolInfo.base.s, symbolInfo.quote.s, symbolInfo.base.a, symbolInfo.quote.a)
|
||||
console.log('setting default symbol', symbolInfo.base.s, symbolInfo.quote.s, symbolInfo.base.a, symbolInfo.quote.a)
|
||||
defaultSymbol = _symbols[ticker]
|
||||
}
|
||||
log('new symbol', ticker, _symbols[ticker])
|
||||
@@ -335,6 +335,14 @@ class RealtimeSubscription {
|
||||
}
|
||||
|
||||
|
||||
async function getLiquidities(markToken, symbolItem) {
|
||||
const token = await erc20Contract(markToken.a, provider)
|
||||
const liquidities = await Promise.all(symbolItem.feeGroup.map(
|
||||
async ([addr, fee]) => await token.balanceOf(addr)
|
||||
))
|
||||
return liquidities;
|
||||
}
|
||||
|
||||
export const DataFeed = {
|
||||
onReady(callback) {
|
||||
log('[onReady]: Method call');
|
||||
@@ -381,9 +389,12 @@ export const DataFeed = {
|
||||
onResolveErrorCallback,
|
||||
extension
|
||||
) {
|
||||
// console.log('[resolveSymbol]: Method call', symbolName);
|
||||
console.log('resolveSymbol', symbolName);
|
||||
const symbols = getAllSymbols();
|
||||
const symbolItem = symbolName === 'default' ? defaultSymbol : symbols[symbolName]
|
||||
if (symbolName==='default') {
|
||||
console.log('using default symbol', defaultSymbol)
|
||||
}
|
||||
if (!symbolItem) {
|
||||
console.log('[resolveSymbol]: Cannot resolve symbol', symbolName);
|
||||
onResolveErrorCallback('cannot resolve symbol');
|
||||
@@ -399,10 +410,11 @@ export const DataFeed = {
|
||||
const inv = invertedDefault(symbolItem.base.a, symbolItem.quote.a)
|
||||
const markToken = inv ? symbolItem.base : symbolItem.quote
|
||||
const mark = useStore().markPrice(markToken.a)
|
||||
const token = await erc20Contract(markToken.a, provider)
|
||||
const liquidities = await Promise.all(symbolItem.feeGroup.map(
|
||||
async ([addr, fee]) => await token.balanceOf(addr)
|
||||
))
|
||||
const liquidities = await withTimeout(
|
||||
getLiquidities(markToken, symbolItem),
|
||||
3000,
|
||||
'liquidity fetch timeout'
|
||||
)
|
||||
symbolItem.liquidities = liquidities.map(l => Number(l / 10n ** BigInt(markToken.d)))
|
||||
if (mark) {
|
||||
symbolItem.liquidities = symbolItem.liquidities.map(l => l * mark)
|
||||
|
||||
@@ -178,3 +178,13 @@ export function decodeBase62(str) {
|
||||
return str.split('').reverse().reduce((acc, char, i) =>
|
||||
acc + base62charset.indexOf(char) * Math.pow(62, i), 0);
|
||||
}
|
||||
|
||||
|
||||
export function withTimeout(promise, timeoutDuration, fallbackErrorMessage) {
|
||||
return Promise.race([
|
||||
promise,
|
||||
new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error(fallbackErrorMessage)), timeoutDuration)
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<template>
|
||||
<v-alert class="d-sm-none" type="info" title="Mobile Screen" text="Dexorder is designed for desktop. Mobile coming soon!" rounded="0"/>
|
||||
<v-alert v-if='!s.connected' icon="mdi-wifi-off" type="error" title="Not Connected" class="mb-3" rounded="0" density="compact"/>
|
||||
<v-alert v-for="e in s.errors" icon="mdi-alert" type="error" :title="e.title" :text="e.text" class="mb-3" :closable="e.closeable" rounded="0"/>
|
||||
</template>
|
||||
|
||||
142
src/components/FloatingDiv.vue
Normal file
142
src/components/FloatingDiv.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<div
|
||||
ref="floatingDiv"
|
||||
:style="divStyle"
|
||||
@mousedown="startDrag"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
required: false,
|
||||
}
|
||||
});
|
||||
|
||||
const floatingDiv = ref(null);
|
||||
const position = reactive({ x: 0, y: 0 });
|
||||
const isDragging = ref(false);
|
||||
const isFloating = ref(false);
|
||||
const dragStartOffset = reactive({ x: 0, y: 0 });
|
||||
|
||||
const divStyle = reactive({
|
||||
position: "",
|
||||
top: "",
|
||||
left: "",
|
||||
zIndex: "",
|
||||
cursor: "default",
|
||||
});
|
||||
|
||||
let activeComponent = null;
|
||||
|
||||
function positionKey() {
|
||||
return props.id ? `floating-div-pos:${props.id}` : null;
|
||||
}
|
||||
|
||||
function savePosition() {
|
||||
if (props.id) {
|
||||
localStorage.setItem(
|
||||
positionKey(),
|
||||
JSON.stringify({ x: position.x, y: position.y })
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function loadPosition() {
|
||||
if (props.id) {
|
||||
const data = localStorage.getItem(positionKey());
|
||||
if (data) {
|
||||
try {
|
||||
const { x, y } = JSON.parse(data);
|
||||
position.x = x;
|
||||
position.y = y;
|
||||
divStyle.position = "fixed";
|
||||
divStyle.top = `${position.y}px`;
|
||||
divStyle.left = `${position.x}px`;
|
||||
divStyle.zIndex = 9999;
|
||||
isFloating.value = true;
|
||||
} catch {
|
||||
// Ignore corrupted data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const startDrag = (event) => {
|
||||
if (event.shiftKey || event.ctrlKey) {
|
||||
if (!isFloating.value) {
|
||||
const rect = floatingDiv.value.getBoundingClientRect();
|
||||
position.x = rect.left;
|
||||
position.y = rect.top;
|
||||
divStyle.position = "fixed";
|
||||
divStyle.top = `${position.y}px`;
|
||||
divStyle.left = `${position.x}px`;
|
||||
divStyle.zIndex = 9999;
|
||||
isFloating.value = true;
|
||||
}
|
||||
|
||||
isDragging.value = true;
|
||||
dragStartOffset.x = event.clientX - position.x;
|
||||
dragStartOffset.y = event.clientY - position.y;
|
||||
divStyle.cursor = "move";
|
||||
document.body.style.userSelect = "none";
|
||||
|
||||
activeComponent = floatingDiv;
|
||||
|
||||
window.addEventListener("mousemove", handleDrag);
|
||||
window.addEventListener("mouseup", stopDrag);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDrag = (event) => {
|
||||
if (isDragging.value && activeComponent === floatingDiv) {
|
||||
position.x = event.clientX - dragStartOffset.x;
|
||||
position.y = event.clientY - dragStartOffset.y;
|
||||
divStyle.top = `${position.y}px`;
|
||||
divStyle.left = `${position.x}px`;
|
||||
}
|
||||
};
|
||||
|
||||
const stopDrag = () => {
|
||||
if (isDragging.value && activeComponent === floatingDiv) {
|
||||
isDragging.value = false;
|
||||
divStyle.cursor = "default";
|
||||
document.body.style.userSelect = "auto";
|
||||
activeComponent = null;
|
||||
|
||||
savePosition();
|
||||
|
||||
window.removeEventListener("mousemove", handleDrag);
|
||||
window.removeEventListener("mouseup", stopDrag);
|
||||
}
|
||||
};
|
||||
|
||||
const handleOutsideDrag = (event) => {
|
||||
if (event.key === "Shift" || event.key === "Control") {
|
||||
stopDrag();
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
document.addEventListener("keyup", handleOutsideDrag);
|
||||
loadPosition();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
document.removeEventListener("keyup", handleOutsideDrag);
|
||||
window.removeEventListener("mousemove", handleDrag);
|
||||
window.removeEventListener("mouseup", stopDrag);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
div[ref="floatingDiv"] {
|
||||
background: rgba(255, 255, 255, 0.8);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
|
||||
}
|
||||
</style>
|
||||
@@ -28,8 +28,8 @@
|
||||
</div>
|
||||
|
||||
<v-card-actions v-if="status>Status.NEEDS_PLUGIN">
|
||||
<btn v-if="pluginOk" icon="mdi-wallet-outline" color="warning" variant="outlined"
|
||||
@click="connect" :disabled="disabled" text="Connect Wallet"/>
|
||||
<btn v-if="pluginOk" icon="mdi-wallet-outline" color="green-accent-4" variant="flat"
|
||||
@click="connect" :disabled="disabled" text="Connect Wallet" class="connect-wallet-btn"/>
|
||||
</v-card-actions>
|
||||
|
||||
</v-card>
|
||||
@@ -87,4 +87,16 @@ async function connect() {
|
||||
#manualsetup tr td:last-child {
|
||||
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>
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
<script setup>
|
||||
if(window.location.hostname !== 'localhost') {
|
||||
window.$crisp = [];window.CRISP_WEBSITE_ID = "b153f30a-4b0b-49cc-8a38-989409a73acb";(function () {const d = document;const s = d.createElement("script");s.src = "https://client.crisp.chat/l.js";s.async = 1;d.getElementsByTagName("head")[0].appendChild(s);})();
|
||||
window.$crisp=[];window.CRISP_WEBSITE_ID="a88f707f-adee-4960-b6de-c328c9d86945";(function(){const d=document;const s=d.createElement("script");s.src="https://client.crisp.chat/l.js";s.async=1;d.getElementsByTagName("head")[0].appendChild(s);})();
|
||||
}
|
||||
</script>
|
||||
@@ -5,7 +5,7 @@
|
||||
<v-card-text class="text-center">Last Updated November 18, 2024</v-card-text>
|
||||
|
||||
<v-card-text>
|
||||
Please read these Terms of Service (the “<b>Terms</b>”) and our <a href="https://www.dexorder.com/privacy-policy" target="dexorder">Privacy Policy</a> carefully because they govern your
|
||||
Please read these Terms of Service (the “<b>Terms</b>”) and our <a href="https://dexorder.com/privacy-policy" target="dexorder">Privacy Policy</a> carefully because they govern your
|
||||
use of the
|
||||
website (and all subdomains and subpages thereon) located at dexorder.com, including without limitation the
|
||||
subdomains app.dexorder.com and www.dexorder.com (collectively, the “<b>Site</b>”), and the Dexorder web
|
||||
@@ -205,7 +205,7 @@
|
||||
(i) Subject to your compliance with these Terms, Dexorder will use its commercially
|
||||
reasonable efforts to provide you with access to the Dexorder Service and to cause your Interactions to be
|
||||
executed on the applicable DEX in accordance with Dexorder’s Execution Policy located at
|
||||
<a href="https://www.dexorder.com/execution-policy">https://www.dexorder.com/execution-policy</a>
|
||||
<a href="https://dexorder.com/execution-policy">https://dexorder.com/execution-policy</a>
|
||||
(“<b>Execution Policy</b>”), however from time to time the Site and the Dexorder Service may be inaccessible or
|
||||
inoperable for any
|
||||
reason, including, without limitation: (a) if an Interaction repeatedly fails to be executed (such as due to an
|
||||
|
||||
@@ -34,10 +34,10 @@
|
||||
<v-card-item v-if="!empty">
|
||||
<v-table>
|
||||
<tbody>
|
||||
<native-row v-if="nativeBalance" :chain-id="s.chainId" :addr="s.vault" :amount="nativeBalance"
|
||||
<native-row v-if="nativeBalance && BigInt(nativeBalance)>0n" :chain-id="s.chainId" :addr="s.vault" :amount="nativeBalance"
|
||||
:on-withdraw="onWithdrawNative" :on-wrap="()=>wrapShow=true"/>
|
||||
<suspense v-for="(amount,addr) of balances">
|
||||
<token-row v-if="BigInt(amount)>0n" :chain-id="s.chainId" :addr="addr" :amount="amount" :onWithdraw="onWithdraw"/>
|
||||
<token-row v-if="amount && BigInt(amount)>0n" :chain-id="s.chainId" :addr="addr" :amount="amount" :onWithdraw="onWithdraw"/>
|
||||
</suspense>
|
||||
</tbody>
|
||||
</v-table>
|
||||
@@ -90,7 +90,7 @@ const hasVault = computed(()=>s.vault!==null)
|
||||
const withdrawToken = ref(null)
|
||||
const withdrawShow = ref(false)
|
||||
async function onWithdraw(token) {
|
||||
console.log('withdraw', addr, token)
|
||||
console.log('withdraw', addr.value, token)
|
||||
withdrawToken.value = token
|
||||
withdrawShow.value = true
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ function tryIt() {
|
||||
|
||||
function learnMore() {
|
||||
track('learn-more')
|
||||
window.open('https://www.dexorder.com/introduction.html', 'dexorderwww')
|
||||
window.open('https://dexorder.com/introduction.html', 'dexorderwww')
|
||||
modelValue.value = false
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<v-btn variant="text" text="max" @click="floatAmount=balanceFloat"/>
|
||||
</template>
|
||||
<template v-slot:append-inner>
|
||||
<span>{{ token.s }}</span>
|
||||
<span style="max-width: 6em">{{ token.s }}</span>
|
||||
</template>
|
||||
</v-text-field>
|
||||
<v-card-actions>
|
||||
@@ -36,11 +36,17 @@ const s = useStore()
|
||||
const props = defineProps(['modelValue', 'vault', 'token'])
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const balance = computed(() => {
|
||||
console.log('balance', props.vault, props.token, s.vaultBalances)
|
||||
const b = s.vaultBalances[props.vault][props.token.address];
|
||||
const b = s.getBalance(props.token?.a)
|
||||
console.log('balance', b)
|
||||
// const b = s.vaultBalances[props.vault][props.token.address];
|
||||
return b === undefined ? 0n : BigInt(b)
|
||||
})
|
||||
const balanceFloat = computed(() => tokenFloat(props.token, balance.value))
|
||||
const balanceFloat = computed(() => {
|
||||
let balance = tokenFloat(props.token, s.getBalance(props.token?.a))
|
||||
balance /= 10**props.token.d
|
||||
console.log('balanceFloat', balance, s.getBalance(props.token?.a), props.token)
|
||||
return balance
|
||||
})
|
||||
const floatAmount = ref(0)
|
||||
|
||||
function withdraw() {
|
||||
|
||||
@@ -132,7 +132,7 @@ const flippedSign = computed(()=>props.flip?-1:1)
|
||||
const balance100 = computed( {
|
||||
get() {return flippedSign.value*props.builder.balance*100},
|
||||
set(v) {
|
||||
if (v<-60) v = -60;
|
||||
// if (v<-60) v = -60;
|
||||
props.builder.balance = flippedSign.value*v/100; }
|
||||
} )
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<toolbar-button tooltip="Assets" icon="mdi-currency-btc" route="Assets"/>
|
||||
<!-- mdi-format-list-checks mdi-format-list-bulleted-square -->
|
||||
<toolbar-button tooltip="Status" icon="mdi-format-list-checks" route="Status"/>
|
||||
<toolbar-button tooltip="About" icon="mdi-information-outline" href="https://www.dexorder.com/" target="dexorderwww"/>
|
||||
<toolbar-button tooltip="About" icon="mdi-information-outline" href="https://dexorder.com/" target="dexorderwww"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<script setup>
|
||||
function openApp() {
|
||||
window.open('https://dexorder.com/', 'dexorderapp')
|
||||
window.open('https://app.dexorder.com/', 'dexorderapp')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import {router} from "@/router/router.js";
|
||||
const theme = useTheme().current
|
||||
|
||||
function openApp() {
|
||||
window.open('https://dexorder.com/', 'dexorderapp')
|
||||
window.open('https://app.dexorder.com/', 'dexorderapp')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
26
src/main.js
26
src/main.js
@@ -15,6 +15,11 @@ import { registerPlugins } from '@/plugins'
|
||||
import '@/styles/style.scss'
|
||||
import "./socketInit.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() }
|
||||
|
||||
@@ -22,3 +27,24 @@ const app = createApp(App)
|
||||
registerPlugins(app)
|
||||
app.mount('#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)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -66,7 +66,9 @@ export const uint32max = 4294967295
|
||||
export const uint64max = 18446744073709551615n
|
||||
|
||||
export function tokenNumber(token, balance) {
|
||||
return FixedNumber.fromValue(balance, token.decimals, {decimals: token.decimals, width: 256})
|
||||
const dec = token ? token.decimals : 0
|
||||
console.log('token dec', dec, balance)
|
||||
return FixedNumber.fromValue(balance, dec, {decimals: dec, width: 256})
|
||||
}
|
||||
|
||||
export function tokenFloat(token, balance) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {socket} from "@/socket.js";
|
||||
import {useStore} from "@/store/store.js";
|
||||
import {flushOrders} from "@/blockchain/wallet.js";
|
||||
import {flushWalletTransactions} from "@/blockchain/wallet.js";
|
||||
import {parseElaboratedOrderStatus} from "@/blockchain/orderlib.js";
|
||||
import {DataFeed} from "./charts/datafeed";
|
||||
import {notifyFillEvent} from "@/notify.js";
|
||||
@@ -76,7 +76,7 @@ socket.on('vaults', (chainId, owner, vaults)=>{
|
||||
s.vaults = vaults
|
||||
if( vaults.length ) {
|
||||
const vault = vaults[0]
|
||||
flushOrders(chainId, owner, 0, vault)
|
||||
flushWalletTransactions(chainId, owner, 0, vault)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user