From f1bc6320745303490d6319384210cb4938c88ccc Mon Sep 17 00:00:00 2001 From: Tim Olson <> Date: Wed, 8 Nov 2023 23:18:36 -0400 Subject: [PATCH] order status updates working --- package.json | 1 + src/blockchain/common.js | 11 +++ src/blockchain/token.js | 13 ++++ src/blockchain/wallet.js | 19 ++++- src/components/Btn.vue | 20 ++++++ src/components/Orders.vue | 107 +++++++++++++++++++++++++++-- src/components/TimedOrderEntry.vue | 2 +- src/components/Vault.vue | 47 +++++++++++-- src/layouts/default/AppBar.vue | 2 +- src/plugins/vuetify.js | 16 ++++- src/socket.js | 29 +++++++- src/store/store.js | 1 + src/styles/style.scss | 4 ++ src/views/OrdersView.vue | 8 ++- 14 files changed, 259 insertions(+), 21 deletions(-) create mode 100644 src/blockchain/common.js create mode 100644 src/components/Btn.vue diff --git a/package.json b/package.json index b4a84bb..f1b6032 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "dexorder", "version": "0.0.0", "private": true, + "type": "module", "scripts": { "dev": "vite", "build": "vite build", diff --git a/src/blockchain/common.js b/src/blockchain/common.js new file mode 100644 index 0000000..87bc8c2 --- /dev/null +++ b/src/blockchain/common.js @@ -0,0 +1,11 @@ +export function applyFills( orderStatus, filled ) { + console.log('apply fills', orderStatus, filled) + orderStatus[4] = filled[0][0] + orderStatus[5] = filled[0][1] + for( const i in filled[1] ) { + const {filledIn, filledOut} = filled[1][i] + orderStatus[6][i] = filledIn + orderStatus[7][i] = filledOut + } + console.log('applied fills', orderStatus) +} diff --git a/src/blockchain/token.js b/src/blockchain/token.js index d61f1d7..28accd3 100644 --- a/src/blockchain/token.js +++ b/src/blockchain/token.js @@ -3,6 +3,19 @@ import {useStore} from "@/store/store.js"; import {erc20Abi} from "@/blockchain/abi.js"; import {ethers} from "ethers"; + +// synchronous version may return null but will trigger a lookup +export function token(addr) { + const s = useStore() + if( !(addr in s.tokens) ) { + getToken(addr) + return null + } + return s.tokens[addr] +} + + +// async version doesnt return until it has a token value export async function getToken(addr) { const s = useStore() if (!(addr in s.tokens)) diff --git a/src/blockchain/wallet.js b/src/blockchain/wallet.js index 4c0eb9e..a934cbe 100644 --- a/src/blockchain/wallet.js +++ b/src/blockchain/wallet.js @@ -88,14 +88,27 @@ export async function connectWallet() { const pendingOrders = [] + +export function ensureVault() { + const s = useStore() + if( !s.chain ) { + console.log('cannot create vault: no chain selected') + return + } + if( !s.account ) { + console.log('cannot create vault: no account logged in') + return + } + socket.emit('ensureVault', s.chainId, s.account, 0) +} + + export async function pendOrder(order) { console.log('order', JSON.stringify(order)) const s = useStore() - const signer = await s.provider.getSigner() if (!s.vaults.length) { pendingOrders.push(order) - const owner = await signer.getAddress(); - socket.emit('ensureVault', s.chainId, owner, 0) + ensureVault() } else { const vault = s.vaults[0]; diff --git a/src/components/Btn.vue b/src/components/Btn.vue new file mode 100644 index 0000000..ade9d3f --- /dev/null +++ b/src/components/Btn.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/src/components/Orders.vue b/src/components/Orders.vue index da757f2..08e8528 100644 --- a/src/components/Orders.vue +++ b/src/components/Orders.vue @@ -2,22 +2,121 @@ - + # + Buy Token + Sell Token + Amount + Filled + Remaining + Average Price +   - - + + {{parseInt(index)+1}} + {{tokenSymbol(inTokenAddr)}} + {{tokenSymbol(outTokenAddr)}} + {{tokenAmount(amountTokenAddr, amount)}} + {{tokenAmount(amountTokenAddr, filled)}} + {{tokenAmount(amountTokenAddr, amount-filled)}} + + {{pairPrice(inTokenAddr, outTokenAddr, vaultAddr, index, avgPrice)}} + + {{pair(inTokenAddr, outTokenAddr, vaultAddr,index)}} + + diff --git a/src/components/TimedOrderEntry.vue b/src/components/TimedOrderEntry.vue index 05dbe4b..8ec3b28 100644 --- a/src/components/TimedOrderEntry.vue +++ b/src/components/TimedOrderEntry.vue @@ -265,7 +265,7 @@ function placeOrder() { window = duration duration *= n // duration is the total time for all tranches } else { - window = duration / n + window = Math.round(duration / n) } const oneHundredPercent = 65535n // by contract definition of uint16 fraction const ceil = oneHundredPercent % BigInt(n) ? 1n : 0n diff --git a/src/components/Vault.vue b/src/components/Vault.vue index 0097131..eac1873 100644 --- a/src/components/Vault.vue +++ b/src/components/Vault.vue @@ -23,18 +23,40 @@ --> - - No Vault Yet + + Create a Dexorder Vault Multiple vaults are not yet supported + +--> + + + Please wait while your vault is being created. This should only take a few seconds. + + + + My Vault {{s.vaults.length>1?'#'+(num+1):''}} {{addr}} -

There are no funds currently in your vault.

-

Send tokens to the address above to fund your vault.

+

+ Your vault is a smart contract that securely holds your funds plus any orders you place. When your order + conditions are met, Dexorder creates a blockchain transaction for vault.execute(), + asking your vault to the order. Your vault then checks that order against the + current blockchain time and pool price, and only trades if everything looks good. +

+

There are no funds currently in your vault. Send tokens to the address above to fund your vault.

+

There are no funds currently in your vault. Use the faucet below to mint some fake coins into your vault.

@@ -61,9 +83,12 @@ import {useStore} from "@/store/store.js"; import {computed, defineAsyncComponent, ref} from "vue"; import {vaultAddress} from "@/blockchain/contract.js"; +import {ensureVault} from "@/blockchain/wallet.js"; import CopyButton from "@/components/CopyButton.vue"; import NeedsProvider from "@/components/NeedsProvider.vue"; import Withdraw from "@/components/Withdraw.vue"; +import PhoneCard from "@/components/PhoneCard.vue"; +import Btn from "@/components/Btn.vue"; const TokenRow = defineAsyncComponent(()=>import('./TokenRow.vue')) const s = useStore() @@ -86,8 +111,16 @@ function onWithdraw(addr) { withdrawToken.value = token withdrawShow.value = true } + +// todo remove automatic vault creation for Alpha 2 +if(props.num===0 && !s.vault) + ensureVault() + diff --git a/src/layouts/default/AppBar.vue b/src/layouts/default/AppBar.vue index 18a1601..81f8911 100644 --- a/src/layouts/default/AppBar.vue +++ b/src/layouts/default/AppBar.vue @@ -8,7 +8,7 @@ - + diff --git a/src/plugins/vuetify.js b/src/plugins/vuetify.js index 78e82d4..112a548 100644 --- a/src/plugins/vuetify.js +++ b/src/plugins/vuetify.js @@ -12,19 +12,29 @@ import 'vuetify/styles' import { createVuetify } from 'vuetify' // https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides +const black = '#333' export default createVuetify({ theme: { themes: { light: { colors: { - background: '#fffefd', - surface: '#fffefd', - primary: '#1A6CAB', + background: '#fdfffe', + surface: '#fdfffe', + // primary: '#1A6CAB', + primary: '#00CC33', // secondary: '#59B8FF', success: '#00CC33', // info: '#fba92c', warning: '#ffcc00', error: '#CC0033', + "on-background": black, + "on-surface": black, + "on-primary": black, + "on-secondary": black, + "on-success": black, + "on-info": black, + "on-warning": black, + "on-error": black, }, dark: false, variables: {}, diff --git a/src/socket.js b/src/socket.js index d1e10e2..d87f665 100644 --- a/src/socket.js +++ b/src/socket.js @@ -2,6 +2,7 @@ import {io} from "socket.io-client"; import {useStore} from "@/store/store.js"; import {flushOrders, onChainChanged} from "@/blockchain/wallet.js"; import {ethers} from "ethers"; +import {applyFills} from "@/blockchain/common.js"; export const socket = io(import.meta.env.VITE_WS_URL || undefined, {transports: ["websocket"]}) @@ -59,16 +60,42 @@ socket.on('vaults', (chainId, owner, vaults)=>{ } }) -socket.on( 'o', (chainId, vault, orderIndex, status)=>{ + +function handleOrderStatus(chainId, vault, orderIndex, status) { const s = useStore() if( s.chainId !== chainId ) return console.log('o', chainId, vault, orderIndex, status) + const orders = s.orders + if( !(vault in orders) ) + orders[vault] = {} + orders[vault][orderIndex] = status + s.orders = orders +} + +socket.on('os', (chainId, vault, orders) => { + console.log('os', orders) + for( const [orderIndex, status] of orders ) + handleOrderStatus(chainId, vault, orderIndex, status) }) +socket.on( 'o', handleOrderStatus) + socket.on( 'of', (chainId, vault, orderIndex, fills)=>{ const s = useStore() if( s.chainId !== chainId ) return console.log('of', chainId, vault, orderIndex, fills) + const orders = s.orders + if( !(vault in orders) ) { + console.log('warning: got fill on an order in an unknown vault') + return + } + if( !(orderIndex in orders[vault]) ) { + console.log(`warning: orderIndex ${orderIndex} missing from vault ${vault}`) + return + } + const order = orders[vault][orderIndex] + applyFills(order, fills) + orders[vault][orderIndex] = order }) diff --git a/src/store/store.js b/src/store/store.js index 1972d57..bb9c483 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -25,6 +25,7 @@ export const useStore = defineStore('app', { extraTokens: {}, poolPrices: {}, vaultBalances: {}, // indexed by vault addr then by token addr. value is an int + orders: {}, // indexed by vault, value is another dictionary with orderIndex as key and order status values }), getters: { vault: (s)=>s.vaults.length===0 ? null : s.vaults[0], diff --git a/src/styles/style.scss b/src/styles/style.scss index 4c6e991..58bde60 100644 --- a/src/styles/style.scss +++ b/src/styles/style.scss @@ -36,6 +36,10 @@ .v-text-field.text-end input { text-align: end; } + + .maxw { + max-width: v.$card-maxw; + } } .uniswap-color { diff --git a/src/views/OrdersView.vue b/src/views/OrdersView.vue index 62fed4c..2e9f5a5 100644 --- a/src/views/OrdersView.vue +++ b/src/views/OrdersView.vue @@ -1,9 +1,15 @@