transaction placement dialog
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import {uint32max, uint64max} from "@/misc.js";
|
||||
import {decodeIEE754, encodeIEE754} from "@/common.js";
|
||||
import order from "@/components/Order.vue";
|
||||
import {encodeIEE754} from "@/common.js";
|
||||
|
||||
export const MAX_FRACTION = 65535;
|
||||
export const NO_CONDITIONAL_ORDER = uint64max;
|
||||
|
||||
279
src/blockchain/transaction.js
Normal file
279
src/blockchain/transaction.js
Normal file
@@ -0,0 +1,279 @@
|
||||
import {nav, timestamp, uuid} from "@/misc.js";
|
||||
import {newContract, vaultContract} from "@/blockchain/contract.js";
|
||||
import {ensureVault, provider, switchChain, useWalletStore} from "@/blockchain/wallet.js";
|
||||
import {toRaw} from "vue";
|
||||
import {useChartOrderStore} from "@/orderbuild.js";
|
||||
|
||||
export const TransactionState = {
|
||||
Created: 0, // user requested a transaction
|
||||
Proposed: 1, // tx is sent to the wallet
|
||||
Signed: 2, // tx is awaiting blockchain mining
|
||||
Rejected: 3, // user refused to sign the tx
|
||||
Error: 3, // unknown error sending the tx to the wallet
|
||||
Mined: 4, // transaction has been confirmed on-chain
|
||||
}
|
||||
|
||||
export const TransactionType = {
|
||||
PlaceOrder: 1,
|
||||
CancelOrder: 2,
|
||||
CancelAll: 3,
|
||||
Wrap: 4,
|
||||
Unwrap: 5,
|
||||
WithdrawNative: 6,
|
||||
Withdraw: 7,
|
||||
}
|
||||
|
||||
export class Transaction {
|
||||
constructor(chainId, type) {
|
||||
this.id = uuid()
|
||||
this.type = type
|
||||
this.state = TransactionState.Created
|
||||
this.tx = null
|
||||
this.chainId = chainId
|
||||
this.owner = null
|
||||
this.vault = null
|
||||
this.error = null
|
||||
}
|
||||
|
||||
submit() {
|
||||
useWalletStore().transaction = this
|
||||
ensureVault()
|
||||
}
|
||||
|
||||
propose(owner, vault) {
|
||||
if (this.vault !== null && this.vault !== vault) {
|
||||
this.failed('proposed vault did not match withdrawl vault', vault, this.vault)
|
||||
return
|
||||
}
|
||||
this.owner = owner
|
||||
this.vault = vault
|
||||
this.send().catch(this.catchSend.bind(this))
|
||||
this.state = TransactionState.Proposed
|
||||
}
|
||||
|
||||
async createTx(vaultContract) {
|
||||
throw Error('unimplemented')
|
||||
}
|
||||
|
||||
signed(tx) {
|
||||
this.tx = tx
|
||||
this.state = TransactionState.Signed
|
||||
}
|
||||
|
||||
rejected() {
|
||||
this.tx = null
|
||||
this.chainId = null
|
||||
this.owner = null
|
||||
this.vault = null
|
||||
this.end(TransactionState.Rejected)
|
||||
console.log('transaction rejected', this.id)
|
||||
}
|
||||
|
||||
failed(e) {
|
||||
this.error = e
|
||||
this.end(TransactionState.Error)
|
||||
console.log('transaction failed', this.id, e)
|
||||
}
|
||||
|
||||
mined(receipt) {
|
||||
this.receipt = receipt
|
||||
this.end(TransactionState.Mined)
|
||||
console.log('mined transaction', this.id, receipt)
|
||||
}
|
||||
|
||||
isOpen() {
|
||||
return this.state >= TransactionState.Rejected
|
||||
}
|
||||
|
||||
isClosed() {
|
||||
return this.state < TransactionState.Rejected
|
||||
}
|
||||
|
||||
|
||||
end(state) {
|
||||
this.state = state
|
||||
useWalletStore().transaction = null
|
||||
}
|
||||
|
||||
|
||||
async send() {
|
||||
console.log('sendTransaction', this)
|
||||
try {
|
||||
await switchChain(this.chainId)
|
||||
} catch (e) {
|
||||
if (e.code === 4001) {
|
||||
this.rejected()
|
||||
return null
|
||||
} else {
|
||||
this.failed(e)
|
||||
return null
|
||||
}
|
||||
}
|
||||
let signer
|
||||
try {
|
||||
signer = await provider.getSigner();
|
||||
} catch (e) {
|
||||
// {
|
||||
// "code": -32002,
|
||||
// "message": "Already processing eth_requestAccounts. Please wait."
|
||||
// }
|
||||
this.rejected()
|
||||
return null
|
||||
}
|
||||
let contract
|
||||
try {
|
||||
contract = await vaultContract(this.vault, signer)
|
||||
} catch (e) {
|
||||
this.failed('vault contract was null while sending order transaction')
|
||||
return null
|
||||
}
|
||||
const tx = toRaw(await this.createTx(contract))
|
||||
this.signed(tx)
|
||||
console.log(`sent transaction`, tx)
|
||||
tx.wait().then(this.mined.bind(this)).catch(this.failed.bind(this))
|
||||
return this.tx
|
||||
}
|
||||
|
||||
|
||||
catchSend(e) {
|
||||
this.error = e
|
||||
if (e.info?.error?.code === 4001) {
|
||||
console.log(`wallet refused transaction`, this.id)
|
||||
this.rejected()
|
||||
} else {
|
||||
this.failed(e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export class PlaceOrderTransaction extends Transaction {
|
||||
constructor(chainId, order) {
|
||||
super(chainId, TransactionType.PlaceOrder)
|
||||
this.order = order
|
||||
this.placementTime = Date.now()/1000
|
||||
this.fee = null // dexorder place and gas fee total
|
||||
}
|
||||
|
||||
|
||||
async createTx(vaultContract) {
|
||||
this.fee = await placementFee(this.vault, this.order)
|
||||
console.log('placing order', this.id, this.fee, this.order)
|
||||
return await vaultContract.placeDexorder(this.order, {value: this.fee.reduce((a, b) => a + b)})
|
||||
}
|
||||
|
||||
|
||||
end(state) {
|
||||
super.end(state)
|
||||
if (state === TransactionState.Mined) {
|
||||
useChartOrderStore().resetOrders()
|
||||
nav('Status')
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// todo move to orderlib
|
||||
async function placementFee(vault, order, window = 300) {
|
||||
// If the fees are about to change within `window` seconds of now, we send the higher native amount of the two fees.
|
||||
// If the fees sent are too much, the vault will refund the sender.
|
||||
const v = await vaultContract(vault, provider)
|
||||
const feeManagerAddr = await v.feeManager()
|
||||
const feeManager = await newContract(feeManagerAddr, 'IFeeManager', provider)
|
||||
const [sched, changeTimestamp] = await Promise.all([feeManager.fees(), feeManager.proposedFeeActivationTime()])
|
||||
console.log('sched', order, sched)
|
||||
// single order placement selector
|
||||
const placementFeeSelector = 'placementFee((address,address,(uint8,uint24),uint256,uint256,bool,bool,bool,uint64,(uint16,bool,bool,bool,bool,bool,bool,bool,bool,uint16,uint24,uint32,uint32,(uint32,uint32),(uint32,uint32))[]),(uint8,uint8,uint8,uint8,uint8))'
|
||||
let [orderFee, gasFee] = await v[placementFeeSelector](order, [...sched])
|
||||
console.log('placementFee', orderFee, gasFee)
|
||||
if (Number(changeTimestamp) - timestamp() < window) {
|
||||
const nextSched = await feeManager.proposedFees()
|
||||
const [nextOrderFee, nextGasFee] = await v[placementFeeSelector](order, [...nextSched])
|
||||
if (nextOrderFee + nextGasFee > orderFee + gasFee)
|
||||
[orderFee, gasFee] = [nextOrderFee, nextGasFee]
|
||||
}
|
||||
return [orderFee, gasFee]
|
||||
}
|
||||
|
||||
|
||||
export class CancelOrderTransaction extends Transaction {
|
||||
constructor(chainId, index) {
|
||||
super(chainId, TransactionType.CancelOrder)
|
||||
this.index = index
|
||||
}
|
||||
|
||||
|
||||
async createTx(vaultContract) {
|
||||
return await vaultContract.cancelDexorder(this.index)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class CancelAllTransaction extends Transaction {
|
||||
constructor(chainId, vault) {
|
||||
super(chainId, TransactionType.CancelAll)
|
||||
this.vault = vault
|
||||
}
|
||||
|
||||
|
||||
async createTx(vaultContract) {
|
||||
return await vaultContract.cancelAllDexorders()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class WithdrawTransaction extends Transaction {
|
||||
constructor(chainId, vault, token, amount) {
|
||||
super(chainId, TransactionType.Withdraw)
|
||||
this.token = token
|
||||
this.amount = amount
|
||||
this.vault = vault
|
||||
}
|
||||
|
||||
|
||||
async createTx(vaultContract) {
|
||||
return await vaultContract['withdraw(address,uint256)'](this.token.a, this.amount)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class WithdrawNativeTransaction extends Transaction {
|
||||
constructor(chainId, vault, amount) {
|
||||
super(chainId, TransactionType.WithdrawNative)
|
||||
this.amount = amount
|
||||
this.vault = vault
|
||||
}
|
||||
|
||||
|
||||
async createTx(vaultContract) {
|
||||
return await vaultContract['withdraw(uint256)'](this.amount)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class WrapTransaction extends Transaction {
|
||||
constructor(chainId, vault, amount) {
|
||||
super(chainId, TransactionType.Wrap)
|
||||
this.vault = vault
|
||||
this.amount = amount
|
||||
}
|
||||
|
||||
async createTx(vaultContract) {
|
||||
return await vaultContract.wrap(this.amount)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class UnwrapTransaction extends Transaction {
|
||||
constructor(chainId, vault, amount) {
|
||||
super(chainId, TransactionType.Unwrap)
|
||||
this.amount = amount
|
||||
}
|
||||
|
||||
async createTx(vaultContract) {
|
||||
return await vaultContract.unwrap(this.amount)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
import {BrowserProvider, ethers} from "ethers";
|
||||
import {useStore} from "@/store/store";
|
||||
import {socket} from "@/socket.js";
|
||||
import {SingletonCoroutine, timestamp, uuid} from "@/misc.js";
|
||||
import {SingletonCoroutine, uuid} from "@/misc.js";
|
||||
import {newContract, vaultAddress, vaultContract} from "@/blockchain/contract.js";
|
||||
import {defineStore} from "pinia";
|
||||
import {ref} from "vue";
|
||||
import {metadataMap, version} from "@/version.js";
|
||||
import {CancelAllTransaction, TransactionState} from "@/blockchain/transaction.js";
|
||||
|
||||
|
||||
export let provider = null
|
||||
|
||||
|
||||
// DEPRECATED
|
||||
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)
|
||||
|
||||
// Pending Order Format
|
||||
// OLD Pending Order Format
|
||||
// {
|
||||
// chainId: 31337, // must never be null, even if no wallet plugin exists. chosen by app, not wallet.
|
||||
// placementTime: Date.now(),
|
||||
@@ -26,8 +28,11 @@ export const useWalletStore = defineStore('wallet', ()=>{
|
||||
// }
|
||||
const pendingOrders = ref([])
|
||||
|
||||
// NEW Format is a single Transaction class
|
||||
const transaction = ref(null)
|
||||
|
||||
return {
|
||||
chainId, pendingOrders,
|
||||
chainId, pendingOrders, transaction,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -165,7 +170,7 @@ function discoverVaults(owner) {
|
||||
doDiscoverVaults.invoke(owner)
|
||||
}
|
||||
|
||||
const doDiscoverVaults = new SingletonCoroutine(_discoverVaults, 50, false)
|
||||
const doDiscoverVaults = new SingletonCoroutine(_discoverVaults, 50)
|
||||
async function _discoverVaults(owner) {
|
||||
const result = []
|
||||
const versions = []
|
||||
@@ -204,11 +209,12 @@ async function _discoverVaults(owner) {
|
||||
if( s.account === owner ) { // double-check the account since it could have changed during our await
|
||||
s.vaults = result
|
||||
s.vaultVersions = versions
|
||||
if( useWalletStore().pendingOrders.length ) {
|
||||
if( useWalletStore().transaction ) {
|
||||
const num = 0 // todo multiple vaults
|
||||
if (result.length)
|
||||
flushOrders(result[0])
|
||||
flushOrders(s.chainId, owner, num, result[0])
|
||||
else
|
||||
ensureVault2(s.chainId, owner, 0)
|
||||
ensureVault2(s.chainId, owner, num)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,7 +254,7 @@ async function doEnsureVault(chainId, owner, num) {
|
||||
if (s.vaults.length <= num)
|
||||
await _discoverVaults(owner)
|
||||
if( s.vaults[num] )
|
||||
flushOrders(s.vaults[num])
|
||||
flushOrders(chainId, owner, num, s.vaults[num])
|
||||
else {
|
||||
console.log(`requesting vault ${owner} ${num}`)
|
||||
socket.emit('ensureVault', chainId, owner, num)
|
||||
@@ -258,53 +264,6 @@ async function doEnsureVault(chainId, owner, num) {
|
||||
const ensureVaultRoutine = new SingletonCoroutine(doEnsureVault, 100)
|
||||
|
||||
|
||||
export const PendingOrderState = {
|
||||
Submitted: -100, // user clicked Place Order but the tx isn't sent to the wallet yet
|
||||
Signing: 0, // tx is sent to the wallet
|
||||
Rejected: -101, // user refused to sign the tx
|
||||
Sent: -102, // tx is awaiting blockchain mining
|
||||
}
|
||||
|
||||
// single order placement selector
|
||||
const placementFeeSelector = 'placementFee((address,address,(uint8,uint24),uint256,uint256,bool,bool,bool,uint64,(uint16,bool,bool,bool,bool,bool,bool,bool,bool,uint16,uint24,uint32,uint32,(uint32,uint32),(uint32,uint32))[]),(uint8,uint8,uint8,uint8,uint8))'
|
||||
|
||||
export async function placementFee(vault, order, window=300) {
|
||||
// If the fees are about to change within `window` seconds of now, we send the higher native amount of the two fees.
|
||||
// If the fees sent are too much, the vault will refund the sender.
|
||||
const v = await vaultContract(vault, provider)
|
||||
const feeManagerAddr = await v.feeManager()
|
||||
const feeManager = await newContract(feeManagerAddr, 'IFeeManager', provider)
|
||||
const [sched, changeTimestamp] = await Promise.all([feeManager.fees(), feeManager.proposedFeeActivationTime()])
|
||||
console.log('sched', order, sched)
|
||||
let [orderFee, gasFee] = await v[placementFeeSelector](order, [...sched])
|
||||
console.log('placementFee', orderFee, gasFee)
|
||||
if (Number(changeTimestamp) - timestamp() < window) {
|
||||
const nextSched = await feeManager.proposedFees()
|
||||
const [nextOrderFee, nextGasFee] = await v[placementFeeSelector](order, [...nextSched])
|
||||
if (nextOrderFee + nextGasFee > orderFee + gasFee)
|
||||
[orderFee, gasFee] = [nextOrderFee, nextGasFee]
|
||||
}
|
||||
return [orderFee, gasFee]
|
||||
}
|
||||
|
||||
|
||||
export async function pendOrder(order, fee=null) {
|
||||
const s = useStore()
|
||||
const pend = {
|
||||
id: uuid(),
|
||||
chainId: s.chainId,
|
||||
placementTime: Date.now()/1000,
|
||||
fee: fee, // dexorder place and gas fee total
|
||||
vault: s.vaults.length ? s.vaults[0] : null,
|
||||
state: PendingOrderState.Submitted,
|
||||
order
|
||||
};
|
||||
useWalletStore().pendingOrders.splice(0,0, pend)
|
||||
console.log('pended order', pend.id, JSON.stringify(order))
|
||||
ensureVault()
|
||||
}
|
||||
|
||||
|
||||
export async function cancelOrder(vault, orderIndex) {
|
||||
console.log('cancel order', vault, orderIndex)
|
||||
pendTransaction(async (signer)=> {
|
||||
@@ -318,18 +277,13 @@ export async function cancelOrder(vault, orderIndex) {
|
||||
}
|
||||
|
||||
export async function cancelAll(vault) {
|
||||
pendTransaction(async (signer)=> {
|
||||
const contract = await vaultContract(vault, signer)
|
||||
if( contract === null ) {
|
||||
console.error('vault contract was null while canceling order', vault)
|
||||
return null
|
||||
}
|
||||
return await contract.cancelAllDexorders()
|
||||
})
|
||||
new CancelAllTransaction(useStore().chainId, vault).submit()
|
||||
}
|
||||
|
||||
export function flushOrders(vault) {
|
||||
export function flushOrders(chainId, owner, num, vault) {
|
||||
const ws = useWalletStore();
|
||||
if (ws.transaction!==null && ws.transaction.state < TransactionState.Proposed)
|
||||
ws.transaction.propose(owner, vault)
|
||||
let needsFlush = false
|
||||
for( const pend of ws.pendingOrders ) {
|
||||
if (pend.vault === null)
|
||||
@@ -337,7 +291,7 @@ export function flushOrders(vault) {
|
||||
if (pend.state === PendingOrderState.Submitted) {
|
||||
console.log('flushing order', pend.id)
|
||||
pendOrderAsTransaction(pend)
|
||||
pend.state = PendingOrderState.Signing
|
||||
setPendState(pend, PendingOrderState.Signing)
|
||||
needsFlush = true
|
||||
}
|
||||
}
|
||||
@@ -363,7 +317,7 @@ function pendOrderAsTransaction(pend) {
|
||||
catch (e) {
|
||||
if(e.code===4001) {
|
||||
console.log('user refused chain switch')
|
||||
pend.state = PendingOrderState.Rejected
|
||||
setPendState(pend, PendingOrderState.Rejected)
|
||||
return null
|
||||
}
|
||||
else {
|
||||
@@ -378,7 +332,7 @@ function pendOrderAsTransaction(pend) {
|
||||
console.log('placing order', pend.id, pend.fee, pend.order)
|
||||
const tx = await contract.placeDexorder(pend.order, {value:pend.fee})
|
||||
pend.tx = tx
|
||||
pend.state = PendingOrderState.Sent
|
||||
setPendState(pend, PendingOrderState.Sent)
|
||||
console.log(`order ${pend.id} sent transaction`, tx)
|
||||
tx.wait().then((txReceipt)=>{
|
||||
console.log('mined order', pend.id, txReceipt)
|
||||
@@ -391,7 +345,7 @@ function pendOrderAsTransaction(pend) {
|
||||
(e) => {
|
||||
if( e.info?.error?.code === 4001 ) {
|
||||
console.log(`wallet refused order`, pend.id)
|
||||
pend.state = PendingOrderState.Rejected
|
||||
setPendState(pend, PendingOrderState.Rejected)
|
||||
return true // returning true means we handled the error. any other return value will dump to console.
|
||||
}
|
||||
})
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
<script setup>
|
||||
|
||||
import PairPrice from "@/components/PairPrice.vue";
|
||||
import {computed} from "vue";
|
||||
import {computed, defineAsyncComponent} from "vue";
|
||||
import {useStore} from "@/store/store.js";
|
||||
const PairPrice = defineAsyncComponent(()=>import("@/components/PairPrice.vue"))
|
||||
|
||||
const props = defineProps(['base', 'quote', 'm', 'b', 'isBreakout', 'showBtn', 'buy'])
|
||||
const s = useStore()
|
||||
|
||||
@@ -26,9 +26,8 @@
|
||||
<script setup>
|
||||
import {useStore} from "@/store/store";
|
||||
import {computed, ref} from "vue";
|
||||
import {vaultContract} from "@/blockchain/contract.js"
|
||||
import {pendTransaction} from "@/blockchain/wallet.js";
|
||||
import {FixedNumber} from "ethers";
|
||||
import {WrapTransaction} from "@/blockchain/transaction.js";
|
||||
|
||||
const s = useStore()
|
||||
const props = defineProps(['modelValue', 'vault', 'maxAmount'])
|
||||
@@ -45,10 +44,7 @@ function wrapNative() {
|
||||
if( amount === 0n )
|
||||
return
|
||||
console.log('pending wrap', valueStr, amount)
|
||||
pendTransaction(async (signer)=>{
|
||||
const vault = await vaultContract(vaultAddr, signer)
|
||||
return await vault.wrap(amount)
|
||||
})
|
||||
new WrapTransaction(s.chainId, vaultAddr, amount).submit()
|
||||
floatAmount.value = 0
|
||||
emit('update:modelValue', false)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import Amount from "@/components/Amount.vue"
|
||||
import {nav, SingletonCoroutine, vAutoSelect} from "@/misc.js";
|
||||
import {newOrder} from "@/blockchain/orderlib.js";
|
||||
import {FixedNumber} from "ethers";
|
||||
import {pendOrder} from "@/blockchain/wallet.js";
|
||||
import PairChoice from "@/components/PairChoice.vue";
|
||||
import NeedsSigner from "@/components/NeedsSigner.vue";
|
||||
import {useChartOrderStore} from "@/orderbuild.js";
|
||||
|
||||
@@ -18,7 +18,6 @@ import {flipInversionPreference, inversionPreference} from "@/misc.js";
|
||||
const props = defineProps(['value', 'base', 'quote', 'showBtn'])
|
||||
|
||||
const s = useStore()
|
||||
const prefs = usePrefStore()
|
||||
|
||||
async function token(obj) {
|
||||
if (!obj) return null
|
||||
|
||||
@@ -71,10 +71,12 @@
|
||||
</suspense>
|
||||
</template>
|
||||
<template v-slot:item.state="{ item }">
|
||||
<!--
|
||||
<v-chip v-if="item.state===PendingOrderState.Submitted || item.state===PendingOrderState.Signing"
|
||||
prepend-icon="mdi-signature">Wallet Signing</v-chip>
|
||||
<v-chip v-if="item.state===PendingOrderState.Rejected" prepend-icon="mdi-cancel">Rejected</v-chip>
|
||||
<v-chip v-if="item.state===PendingOrderState.Sent" prepend-icon="mdi-send">Sent</v-chip>
|
||||
-->
|
||||
<v-chip v-if="item.state===OrderState.Open" class="d-none d-lg-inline-flex" prepend-icon="mdi-dots-horizontal"
|
||||
color="green">Open
|
||||
</v-chip>
|
||||
@@ -176,7 +178,7 @@ import LinePrice from "@/components/LinePrice.vue";
|
||||
import {useStore} from "@/store/store";
|
||||
import {computed, defineAsyncComponent, onUnmounted, ref, watch} from "vue";
|
||||
import Btn from "@/components/Btn.vue"
|
||||
import {cancelOrder, PendingOrderState, useWalletStore} from "@/blockchain/wallet.js";
|
||||
import {cancelOrder, useWalletStore} from "@/blockchain/wallet.js";
|
||||
import {DISTANT_FUTURE, isOpen, OrderState} from "@/blockchain/orderlib.js";
|
||||
import Pulse from "@/components/Pulse.vue";
|
||||
import {OrderShapes} from "@/charts/ordershapes.js";
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<v-list v-if="token">
|
||||
<v-list-subheader :title="token.s"/>
|
||||
<v-list-item title="Withdraw" key="withdraw" value="withdraw" prepend-icon="mdi-arrow-down-bold"
|
||||
@click="()=>onWithdraw(token.a)"/>
|
||||
@click="()=>onWithdraw(token)"/>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</td>
|
||||
|
||||
@@ -34,10 +34,8 @@
|
||||
<v-card-item v-if="!empty">
|
||||
<v-table>
|
||||
<tbody>
|
||||
<suspense>
|
||||
<native-row v-if="nativeBalance" :chain-id="s.chainId" :addr="s.vault" :amount="nativeBalance"
|
||||
:on-withdraw="onWithdrawNative" :on-wrap="()=>wrapShow=true"/>
|
||||
</suspense>
|
||||
<native-row v-if="nativeBalance" :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"/>
|
||||
</suspense>
|
||||
@@ -65,7 +63,6 @@ import {vaultAddress} from "@/blockchain/contract.js";
|
||||
import {ensureVault, provider} from "@/blockchain/wallet.js";
|
||||
import CopyButton from "@/components/CopyButton.vue";
|
||||
import Withdraw from "@/components/Withdraw.vue";
|
||||
import {getToken} from "@/blockchain/token.js";
|
||||
import NativeRow from "@/components/NativeRow.vue";
|
||||
import NativeWrap from "@/components/NativeWrap.vue";
|
||||
import WithdrawNative from "@/components/WithdrawNative.vue";
|
||||
@@ -91,8 +88,7 @@ const hasVault = computed(()=>s.vault!==null)
|
||||
|
||||
const withdrawToken = ref(null)
|
||||
const withdrawShow = ref(false)
|
||||
async function onWithdraw(addr) {
|
||||
const token = await getToken(s.chainId, addr)
|
||||
async function onWithdraw(token) {
|
||||
console.log('withdraw', addr, token)
|
||||
withdrawToken.value = token
|
||||
withdrawShow.value = true
|
||||
|
||||
@@ -30,6 +30,7 @@ import {tokenFloat} from "@/misc.js";
|
||||
import {vaultContract} from "@/blockchain/contract.js"
|
||||
import {pendTransaction} from "@/blockchain/wallet.js";
|
||||
import {FixedNumber} from "ethers";
|
||||
import {WithdrawTransaction} from "@/blockchain/transaction.js";
|
||||
|
||||
const s = useStore()
|
||||
const props = defineProps(['modelValue', 'vault', 'token'])
|
||||
@@ -50,10 +51,7 @@ function withdraw() {
|
||||
if( amount === 0n )
|
||||
return
|
||||
console.log('pending withdrawal', valueStr, amount, props.token.s)
|
||||
pendTransaction(async (signer)=>{
|
||||
const vault = await vaultContract(vaultAddr, signer)
|
||||
return await vault['withdraw(address,uint256)'](props.token.a, amount)
|
||||
})
|
||||
new WithdrawTransaction(s.chainId, vaultAddr, props.token, amount).submit()
|
||||
floatAmount.value = 0
|
||||
emit('update:modelValue', false)
|
||||
}
|
||||
|
||||
@@ -26,9 +26,8 @@
|
||||
<script setup>
|
||||
import {useStore} from "@/store/store";
|
||||
import {computed, ref} from "vue";
|
||||
import {vaultContract} from "@/blockchain/contract.js"
|
||||
import {pendTransaction} from "@/blockchain/wallet.js";
|
||||
import {FixedNumber} from "ethers";
|
||||
import {WithdrawNativeTransaction} from "@/blockchain/transaction.js";
|
||||
|
||||
const s = useStore()
|
||||
const props = defineProps(['modelValue', 'vault', 'balance'])
|
||||
@@ -44,11 +43,7 @@ function withdraw() {
|
||||
console.log('pending native withdrawal', valueStr, amount)
|
||||
if( amount === 0n )
|
||||
return
|
||||
pendTransaction(async (signer)=>{
|
||||
const vault = await vaultContract(vaultAddr, signer)
|
||||
console.log('invoking withdraw', vaultAddr, amount)
|
||||
return await vault['withdraw(uint256)'](amount)
|
||||
})
|
||||
new WithdrawNativeTransaction(s.chainId, vaultAddr, amount).submit()
|
||||
floatAmount.value = 0
|
||||
emit('update:modelValue', false)
|
||||
}
|
||||
|
||||
@@ -29,20 +29,21 @@
|
||||
<script setup>
|
||||
import {orderFuncs, useChartOrderStore} from "@/orderbuild.js";
|
||||
import {addSymbolChangedCallback, removeSymbolChangedCallback} from "@/charts/chart.js";
|
||||
import {computed, onBeforeUnmount, ref} from "vue";
|
||||
import {computed, onBeforeUnmount, ref, toRaw, watchEffect} from "vue";
|
||||
import {useOrderStore, useStore} from "@/store/store.js";
|
||||
|
||||
import {routeFinder} from "@/blockchain/route.js";
|
||||
import ChartOrder from "@/components/chart/ChartOrder.vue";
|
||||
import {useTheme} from "vuetify";
|
||||
import {pendOrder} from "@/blockchain/wallet.js";
|
||||
import {useWalletStore} from "@/blockchain/wallet.js";
|
||||
import ToolbarPane from "@/components/chart/ToolbarPane.vue";
|
||||
import NeedsChart from "@/components/NeedsChart.vue";
|
||||
import {nav} from "@/misc.js";
|
||||
import {PlaceOrderTransaction} from "@/blockchain/transaction.js";
|
||||
|
||||
const s = useStore()
|
||||
const co = useChartOrderStore()
|
||||
const os = useOrderStore()
|
||||
const ws = useWalletStore()
|
||||
|
||||
function changeSymbol(symbol) {
|
||||
console.log('changeSymbol', symbol)
|
||||
@@ -79,6 +80,32 @@ function cancelOrder() {
|
||||
showResetDialog.value = true
|
||||
}
|
||||
|
||||
watchEffect(()=>{
|
||||
const removable = []
|
||||
for (const order of ws.pendingOrders) {
|
||||
console.log('pend state', order.state)
|
||||
switch (order.state) {
|
||||
case PendingOrderState.Sent:
|
||||
break
|
||||
case PendingOrderState.Rejected:
|
||||
removable.push(order)
|
||||
break
|
||||
case PendingOrderState.Signing:
|
||||
break
|
||||
case PendingOrderState.Submitted:
|
||||
removable.push(order)
|
||||
break
|
||||
default:
|
||||
console.error('unknown pend state', order.state)
|
||||
}
|
||||
}
|
||||
if (removable.length>0) {
|
||||
if (ws.pendingOrders.length!==removable.length)
|
||||
console.error('Not all orders were rejected') // todo multiple orders / order group
|
||||
ws.pendingOrders = []
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
async function placeOrder() {
|
||||
const chartOrders = co.orders;
|
||||
@@ -90,13 +117,11 @@ async function placeOrder() {
|
||||
built.push(order)
|
||||
}
|
||||
console.log('place orders', built)
|
||||
if (built.length !== 1) {
|
||||
console.error('Multiple orders not supported')
|
||||
if (ws.transaction!==null) {
|
||||
console.error('Transaction already in progress')
|
||||
}
|
||||
else {
|
||||
await pendOrder(built[0])
|
||||
co.resetOrders()
|
||||
nav('Status')
|
||||
new PlaceOrderTransaction(s.chainId, toRaw(built[0])).submit()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,27 +9,18 @@
|
||||
<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"/>
|
||||
<v-btn variant="text" icon="mdi-help-circle-outline" text="Info" @click="showCorp"></v-btn>
|
||||
<v-btn variant="text" icon="mdi-information-outline" text="Info" @click="showCorp"></v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {useStore} from "@/store/store.js";
|
||||
import {useChartOrderStore} from "@/orderbuild.js";
|
||||
import {useTheme} from "vuetify";
|
||||
import ToolbarButton from "@/components/chart/ToolbarButton.vue";
|
||||
import beta from "@/components/Beta.vue";
|
||||
import Logo from "@/components/Logo.vue";
|
||||
import {nav} from "@/misc.js";
|
||||
|
||||
const props = defineProps(['title', 'icon'])
|
||||
|
||||
const s = useStore()
|
||||
const co = useChartOrderStore()
|
||||
|
||||
const theme = useTheme().current
|
||||
|
||||
function showCorp() {
|
||||
window.open('https://dexorder.trade/', 'dexorder')
|
||||
}
|
||||
|
||||
@@ -1,12 +1,95 @@
|
||||
<template>
|
||||
<v-app>
|
||||
<main-view/>
|
||||
<v-dialog v-model="showTransactionDialog" max-width="300">
|
||||
<v-card :title="title">
|
||||
<v-card-text v-if="description!==null">{{description}}</v-card-text>
|
||||
<v-card-text>Confirm this {{noun}} in your wallet.</v-card-text>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import MainView from './MainView.vue'
|
||||
import {useStore} from "@/store/store.js";
|
||||
import {computed} from "vue";
|
||||
import {useWalletStore} from "@/blockchain/wallet.js";
|
||||
import {TransactionType} from "@/blockchain/transaction.js";
|
||||
import {FixedNumber} from "ethers";
|
||||
|
||||
const s = useStore()
|
||||
const ws = useWalletStore()
|
||||
const showTransactionDialog = computed(()=>ws.transaction!==null)
|
||||
const title = computed(()=>{
|
||||
switch (ws.transaction?.type) {
|
||||
case TransactionType.PlaceOrder:
|
||||
return "Placing Order"
|
||||
case TransactionType.CancelOrder:
|
||||
return "Canceling Order"
|
||||
case TransactionType.CancelAll:
|
||||
return "Cancel All Orders"
|
||||
case TransactionType.Wrap:
|
||||
return "Wrap"
|
||||
case TransactionType.Unwrap:
|
||||
return "Unwrap"
|
||||
case TransactionType.WithdrawNative:
|
||||
case TransactionType.Withdraw:
|
||||
return "Withdraw"
|
||||
default:
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
||||
const description = computed(()=>{
|
||||
const tx = ws.transaction
|
||||
switch (tx?.type) {
|
||||
case TransactionType.PlaceOrder:
|
||||
return describeOrder(tx.order)
|
||||
case TransactionType.CancelOrder:
|
||||
return null // todo fetch the order status and describe it
|
||||
case TransactionType.CancelAll:
|
||||
return null
|
||||
case TransactionType.Wrap:
|
||||
return `Wrap ${FixedNumber.fromValue(tx.amount,18)} ETH` // todo native token symbol and decimals
|
||||
case TransactionType.Unwrap:
|
||||
return `Unwrap ${FixedNumber.fromValue(tx.amount,18)} WETH` // todo wrapped token symbol and decimals
|
||||
case TransactionType.WithdrawNative:
|
||||
return `Withdraw ${FixedNumber.fromValue(tx.amount,18)} ETH` // todo native token symbol and decimals
|
||||
case TransactionType.Withdraw:
|
||||
return `Withdraw ${FixedNumber.fromValue(tx.amount,tx.token.d)} ${tx.token.s}`
|
||||
default:
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const noun = computed(()=>{
|
||||
const tx = ws.transaction
|
||||
switch (tx?.type) {
|
||||
case TransactionType.PlaceOrder:
|
||||
return 'order'
|
||||
case TransactionType.CancelOrder:
|
||||
return 'cancelation'
|
||||
case TransactionType.CancelAll:
|
||||
return 'cancelation'
|
||||
case TransactionType.Wrap:
|
||||
return 'wrapping'
|
||||
case TransactionType.Unwrap:
|
||||
return 'unwrapping'
|
||||
case TransactionType.WithdrawNative:
|
||||
return 'withdrawal'
|
||||
case TransactionType.Withdraw:
|
||||
return 'withdrawal'
|
||||
default:
|
||||
return null
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
function describeOrder(order) {
|
||||
return null // todo
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@@ -144,7 +144,7 @@ export function inversionPreference(chainId, base, quote) {
|
||||
const inputInverted = base.a > quote.a
|
||||
const token0 = !inputInverted ? base.a : quote.a
|
||||
const token1 = inputInverted ? base.a : quote.a
|
||||
const key = [chainId, token0, token1];
|
||||
const key = [chainId, token0, token1]; // todo chainId shouldn't matter
|
||||
const prefs = usePrefStore()
|
||||
if (!(key in prefs.inverted)) {
|
||||
// todo prefer stablecoins as the quote asset
|
||||
@@ -157,6 +157,7 @@ export function inversionPreference(chainId, base, quote) {
|
||||
break // definitely inverted
|
||||
}
|
||||
}
|
||||
console.log('inverted?', base, quote, preferInverted)
|
||||
prefs.inverted[key] = preferInverted
|
||||
}
|
||||
// console.log('inversion preference', base, quote, prefs.inverted[key], inputInverted)
|
||||
|
||||
@@ -40,8 +40,8 @@ export async function notifyFillEvent(chainId, status, trancheIndex, fill) {
|
||||
const quoteAddr = status.order.inverted ? low : high
|
||||
const buy = status.order.tokenIn === quoteAddr
|
||||
const [base, quote] = await Promise.all([getToken(chainId, baseAddr), getToken(chainId, quoteAddr)]);
|
||||
const baseAmount = (buy ? fill.filledOut : fill.filledIn) * 10**-base.d
|
||||
const quoteAmount = (buy ? fill.filledIn : fill.filledOut) * 10**-quote.d
|
||||
const baseAmount = Number(buy ? fill.filledOut : fill.filledIn) * 10**-base.d
|
||||
const quoteAmount = Number(buy ? fill.filledIn : fill.filledOut) * 10**-quote.d
|
||||
const average = quoteAmount / baseAmount
|
||||
const title = `${buy?"Bought":"Sold"} ${baseAmount.toPrecision(5)} ${base.s}`;
|
||||
const msg = title +
|
||||
|
||||
@@ -53,7 +53,7 @@ socket.on('vaults', (chainId, owner, vaults)=>{
|
||||
s.vaults = vaults
|
||||
if( vaults.length ) {
|
||||
const vault = vaults[0]
|
||||
flushOrders(vault)
|
||||
flushOrders(chainId, owner, 0, vault)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user