Compare commits

...

10 Commits

Author SHA1 Message Date
tim
19a8ffbbd4 MaxMind IP database & region approvals 2024-12-19 20:18:56 -04:00
tim
a689766f37 ToS; persistent pref store; package upgrade 2024-11-19 21:23:00 -04:00
tim
bb4f7d4607 OHLC load fixes; package updates 2024-11-16 19:30:02 -04:00
tim
a9bf23ddbb transaction placement dialog 2024-11-11 20:55:28 -04:00
tim
43891434c5 language touchup 2024-11-06 16:50:39 -04:00
tim
99a6cc1742 chart config tweak 2024-11-05 16:58:57 -04:00
tim
28dd64b1cf post-order line draw improvements 2024-11-04 18:39:09 -04:00
tim
cfcba95445 buy/sell color change fix 2024-11-04 14:39:43 -04:00
tim
61101fcf0a updated Home features 2024-10-31 20:12:13 -04:00
tim
a7a1628f3c updated Home features 2024-10-31 20:10:08 -04:00
49 changed files with 2514 additions and 621 deletions

View File

@@ -18,8 +18,10 @@
"core-js": "^3.29.0",
"ethers": "^6.7.1",
"flexsearch": "^0.7.43",
"lru-cache": "^11.0.2",
"luxon": "^3.4.4",
"pinia": "2.1.6",
"pinia-plugin-persistedstate": "^4.1.3",
"roboto-fontface": "*",
"socket.io-client": "^4.7.2",
"vue": "^3.2.0",

View File

@@ -31,7 +31,7 @@ export async function queryHelperContract(helper, provider) {
// use newContract(addr, 'IVaultImpl', provider, 'IVault') to get the ABI from IVault.sol/IVaultImpl.json
export async function newContract(addr, name, provider) {
const abi = await abiCache.get(name)
console.log(`${name} ABI`, abi)
// console.log(`${name} ABI`, abi)
return new ethers.Contract(addr, abi, provider)
}

View File

@@ -1,5 +1,5 @@
import {uint32max, uint64max} from "@/misc.js";
import {decodeIEE754, encodeIEE754} from "@/common.js";
import {encodeIEE754} from "@/common.js";
export const MAX_FRACTION = 65535;
export const NO_CONDITIONAL_ORDER = uint64max;
@@ -151,10 +151,11 @@ export function parseOrderStatus(chainId, status) {
order = parseOrder(order)
filledIn = BigInt(filledIn)
filledOut = BigInt(filledOut)
trancheStatus = trancheStatus.map((obj)=>parseTrancheStatus(obj))
const filled = order.amountIsInput ? filledIn : filledOut
trancheStatus = trancheStatus.map((obj)=>parseTrancheStatus(obj, order.amountIsInput))
const result = {
chainId, order, fillFeeHalfBps, state, startTime, startPrice, ocoGroup,
filledIn, filledOut, trancheStatus,
filledIn, filledOut, filled, trancheStatus,
};
console.log('SwapOrderStatus', result)
return result
@@ -162,20 +163,23 @@ export function parseOrderStatus(chainId, status) {
function parseFill(obj) {
let [tx, time, filledIn, filledOut, fee] = obj
time = new Date(time * 1000)
filledIn = BigInt(filledIn)
filledOut = BigInt(filledOut)
const filled = obj.amountIsInput ? filledIn : filledOut
fee = BigInt(fee)
return {tx, time, filledIn, filledOut, fee}
return {tx, time, filledIn, filledOut, filled, fee}
}
function parseTrancheStatus(obj) {
function parseTrancheStatus(obj, amountIsInput) {
let [filledIn, filledOut, activationTime, startTime, endTime, rawFills,] = obj
filledIn = BigInt(filledIn)
filledOut = BigInt(filledOut)
const fills = []
for (const fill of rawFills)
fills.push(parseFill(fill))
return {filledIn, filledOut, activationTime, startTime, endTime, fills}
fills.push(parseFill(fill, amountIsInput))
const filled = amountIsInput ? filledIn : filledOut
return {filledIn, filledOut, filled, activationTime, startTime, endTime, fills}
}
export function parseOrder(order) {

View File

@@ -61,21 +61,28 @@ export async function addExtraToken(chainId, addr) {
}
else {
if( provider===null ) {
console.log('warning: token lookup cancelled due to null provider', addr)
console.warn('warning: token lookup cancelled due to null provider', addr)
resolve(null)
}
else {
const token = await newContract(addr, 'IERC20Metadata', provider)
Promise.all( [token.name(), token.symbol(), token.decimals()] ).then((name,symbol,decimals)=>{
info = {
a: addr,
n: name,
s: symbol,
d: decimals,
for( let tries=1; tries<=5; tries++ ) {
try {
const token = await newContract(addr, 'IERC20Metadata', provider)
const [name, symbol, decimals] = await Promise.all([token.name(), token.symbol(), token.decimals()])
info = {
a: addr,
n: name,
s: symbol,
d: decimals,
}
s.addToken(chainId, info)
resolve(info)
break
}
s.addToken(chainId, info)
resolve(info)
})
catch (e) {
console.warn(`Could not lookup token ${addr}`, e)
}
}
}
}
})

View 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)
}
}

View File

@@ -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} 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.
}
})
@@ -464,18 +418,18 @@ function doSendTransaction(sender, signer, errHandler) {
export async function detectUpgrade() {
if (!provider) {
console.log('no provider!')
return 0
return null
}
const s = useStore()
if (!s.vault) {
console.log('no vault logged in')
return 0
return null
}
const info = version.chainInfo[s.chainId]
if (!info) {
console.log(`couldn't get chainInfo for ${s.chainId}`)
return 0
return null
}
try {
console.log('factory', info.factory)
@@ -497,7 +451,7 @@ export async function detectUpgrade() {
catch (e) {
console.log('ignorable error while querying for an upgrade', e)
}
return 0
return null
}

View File

@@ -23,14 +23,11 @@ export function removeSymbolChangedCallback(cb) {
}
function symbolChanged(symbol) {
if (symbol===null)
co.selectedSymbol = null
else {
const info = lookupSymbol(symbol.ticker)
symbolChangedCbs.forEach((cb) => cb(info))
co.selectedSymbol = info
}
const info = symbol===null ? null : lookupSymbol(symbol.ticker)
co.selectedSymbol = info
symbolChangedCbs.forEach((cb) => cb(info))
updateFeeDropdown()
console.log('symbol changed', info)
}
@@ -131,6 +128,9 @@ function selectPool(fee) {
export function initWidget(el) {
widget = window.tvWidget = new TradingView.widget({
// Widget Options
// https://www.tradingview.com/charting-library-docs/latest/api/interfaces/Charting_Library.ChartingLibraryWidgetOptions
library_path: "/charting_library/",
// debug: true,
autosize: true,
@@ -144,6 +144,13 @@ export function initWidget(el) {
drawings_access: {type: 'white', tools: [],}, // show no tools
custom_themes: tvCustomThemes,
theme: useStore().theme,
// Chart Overrides
// https://www.tradingview.com/charting-library-docs/latest/customization/overrides/chart-overrides
overrides: {
// "mainSeriesProperties.priceAxisProperties.log": false,
}
});
// debug dump all events

View File

@@ -240,7 +240,6 @@ function invertTicker(ticker) {
}
export function lookupSymbol(ticker) { // lookup by ticker which is "0xbaseAddress/0xquoteAddress"
// todo tim lookup default base/quote pool
const symbols = getAllSymbols();
if (!(ticker in symbols)) {
// check the inverted symbol
@@ -411,7 +410,7 @@ export const DataFeed = {
async getBars(symbolInfo, resolution, periodParams, onHistoryCallback, onErrorCallback) {
const { from, to, firstDataRequest } = periodParams;
log('[getBars]: Method call', symbolInfo, resolution, from, to);
log('[getBars]: Method call', symbolInfo, resolution, new Date(from*1000), new Date(to*1000));
try {
// todo need to consider the selected fee tier
await getAllSymbols()

View File

@@ -1,5 +1,6 @@
import {useStore} from "@/store/store.js";
import {ohlcStart} from "@/charts/chart-misc.js";
import {LRUCache} from "lru-cache";
// support for Dexorder OHLC data files
@@ -43,19 +44,36 @@ function singleFile(resName) {
}
function nextDay(timestamp) {
function addDay(timestamp) {
const date = new Date(timestamp*1000)
return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + 1) / 1000
}
function addMonth(timestamp) {
const date = new Date(timestamp*1000)
const result = Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate()) / 1000
console.log('addMonth', timestamp, result, new Date(timestamp*1000), new Date(result*1000))
return result
}
function addYear(timestamp) {
const date = new Date(timestamp*1000)
return Date.UTC(date.getUTCFullYear() + 1, date.getUTCMonth(), date.getUTCDate()) / 1000
}
function nextDay(timestamp) {
const date = new Date(timestamp*1000)
return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + 1, 0, 0, 0) / 1000
}
function nextMonth(timestamp) {
const date = new Date(timestamp*1000)
return Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate()) / 1000
return Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 1, 0, 0, 0) / 1000
}
function nextYear(timestamp) {
const date = new Date(timestamp*1000)
return Date.UTC(date.getUTCFullYear() + 1, date.getUTCMonth(), date.getUTCDate()) / 1000
return Date.UTC(date.getUTCFullYear() + 1, 1, 1, 0, 0, 0) / 1000
}
@@ -66,21 +84,21 @@ function never(_timestamp) {
// noinspection PointlessArithmeticExpressionJS
const resolutions = [
{ seconds: 1 * 60, name: '1m', tvRes: '1', filename: dailyFile( '1m'), nextStart: nextDay, },
{ seconds: 3 * 60, name: '3m', tvRes: '3', filename: dailyFile( '3m'), nextStart: nextDay, },
{ seconds: 5 * 60, name: '5m', tvRes: '5', filename: dailyFile( '5m'), nextStart: nextDay, },
{ seconds: 10 * 60, name: '10m', tvRes: '10', filename: dailyFile('10m'), nextStart: nextDay, },
{ seconds: 15 * 60, name: '15m', tvRes: '15', filename: dailyFile('15m'), nextStart: nextDay, },
{ seconds: 30 * 60, name: '30m', tvRes: '30', filename: dailyFile('30m'), nextStart: nextDay, },
{ seconds: 60 * 60, name: '1H', tvRes: '60', filename: monthlyFile( '1H'), nextStart: nextMonth, },
{ seconds: 120 * 60, name: '2H', tvRes: '120', filename: monthlyFile( '2H'), nextStart: nextMonth, },
{ seconds: 240 * 60, name: '4H', tvRes: '240', filename: monthlyFile( '4H'), nextStart: nextMonth, },
{ seconds: 480 * 60, name: '8H', tvRes: '480', filename: monthlyFile( '8H'), nextStart: nextMonth, },
{ seconds: 720 * 60, name: '12H', tvRes: '720', filename: monthlyFile('12H'), nextStart: nextMonth, },
{ seconds: 1440 * 60, name: '1D', tvRes: '1D', filename: yearlyFile( '1D'), nextStart: nextYear, },
{ seconds: 2880 * 60, name: '2D', tvRes: '2D', filename: yearlyFile( '2D'), nextStart: nextYear, },
{ seconds: 4320 * 60, name: '3D', tvRes: '3D', filename: yearlyFile( '3D'), nextStart: nextYear, },
{ seconds: 10080 * 60, name: '1W', tvRes: '1W', filename: singleFile( '1W'), nextStart: never, },
{ seconds: 1 * 60, name: '1m', tvRes: '1', filename: dailyFile( '1m'), add: addDay, nextStart: nextDay, },
{ seconds: 3 * 60, name: '3m', tvRes: '3', filename: dailyFile( '3m'), add: addDay, nextStart: nextDay, },
{ seconds: 5 * 60, name: '5m', tvRes: '5', filename: dailyFile( '5m'), add: addDay, nextStart: nextDay, },
{ seconds: 10 * 60, name: '10m', tvRes: '10', filename: dailyFile('10m'), add: addDay, nextStart: nextDay, },
{ seconds: 15 * 60, name: '15m', tvRes: '15', filename: dailyFile('15m'), add: addDay, nextStart: nextDay, },
{ seconds: 30 * 60, name: '30m', tvRes: '30', filename: dailyFile('30m'), add: addDay, nextStart: nextDay, },
{ seconds: 60 * 60, name: '1H', tvRes: '60', filename: monthlyFile( '1H'), add: addMonth, nextStart: nextMonth, },
{ seconds: 120 * 60, name: '2H', tvRes: '120', filename: monthlyFile( '2H'), add: addMonth, nextStart: nextMonth, },
{ seconds: 240 * 60, name: '4H', tvRes: '240', filename: monthlyFile( '4H'), add: addMonth, nextStart: nextMonth, },
{ seconds: 480 * 60, name: '8H', tvRes: '480', filename: monthlyFile( '8H'), add: addMonth, nextStart: nextMonth, },
{ seconds: 720 * 60, name: '12H', tvRes: '720', filename: monthlyFile('12H'), add: addMonth, nextStart: nextMonth, },
{ seconds: 1440 * 60, name: '1D', tvRes: '1D', filename: yearlyFile( '1D'), add: addYear, nextStart: nextYear, },
{ seconds: 2880 * 60, name: '2D', tvRes: '2D', filename: yearlyFile( '2D'), add: addYear, nextStart: nextYear, },
{ seconds: 4320 * 60, name: '3D', tvRes: '3D', filename: yearlyFile( '3D'), add: addYear, nextStart: nextYear, },
{ seconds: 10080 * 60, name: '1W', tvRes: '1W', filename: singleFile( '1W'), add: (x)=>x, nextStart: never, },
]
const tvResMap = {}
@@ -93,14 +111,21 @@ for (const res of resolutions)
const seriesStarts = {}
const ohlcCache = new LRUCache({max:20,ttl:3600*1000,})
async function getUrl(url) {
let result = ohlcCache[url]
if (result)
return result
try {
const response = await fetch(url)
// console.log('got response', response)
if (response.ok)
return await response.text()
if (response.ok) {
result = await response.text()
ohlcCache[url] = result
return result
}
else
console.error(`could not fetch ${url}: status ${response.statusText}`)
}
@@ -112,7 +137,7 @@ async function getUrl(url) {
export async function loadOHLC (symbol, contract, from, to, tvRes) {
// console.log('loadOHLC', tvRes, new Date(1000*from), new Date(1000*to), symbol, contract);
console.log('loadOHLC', tvRes, new Date(1000*from), new Date(1000*to), symbol, contract);
let chainId
let bars = [];
let inverted = false;
@@ -123,8 +148,10 @@ export async function loadOHLC (symbol, contract, from, to, tvRes) {
if (latest===null) return
const [latestTime, price] = latest
end = ohlcStart(end, period)
const start = ohlcStart(latestTime+period, period);
for (let now= start; now < end; now += period ) {
const start = ohlcStart(latestTime+period, period)
// if (start<end)
// console.log('filling', latestTime, price, new Date(start*1000), new Date(end*1000))
for (let now=start; now < end; now += period ) {
bars.push({time:now * 1000, open:price, high:price, low:price, close:price})
latest = [now, price]
}
@@ -144,14 +171,14 @@ export async function loadOHLC (symbol, contract, from, to, tvRes) {
const res = tvResMap[tvRes]
const fetches = []
let start = from
if (!(baseUrl in seriesStarts)) {
try {
// console.log('getting quote', baseUrl+'quote.csv')
const response = await getUrl(baseUrl+'quote.csv')
if (response.length) {
seriesStarts[baseUrl] = parseInt(response.split(',')[0])
// console.log(`Series ${baseUrl} starts at ${new Date(start*1000)}`)
const [start,end,price] = response.split(',')
seriesStarts[baseUrl] = parseInt(start)
console.log(`Series ${baseUrl} starts at ${new Date(start*1000)}`)
}
else {
console.error(`Bad response while fetching ${baseUrl+'quote.csv'}`)
@@ -161,85 +188,93 @@ export async function loadOHLC (symbol, contract, from, to, tvRes) {
console.error(e)
}
}
let start = from
if (baseUrl in seriesStarts)
start = Math.max(start, seriesStarts[baseUrl])
for(let now = start; now < to; now = res.nextStart(now)) {
const end = res.nextStart(to)
for(let now = start; now < end; now = res.nextStart(now)) {
const url = baseUrl + res.filename(contract, now);
const prom = getUrl(url)
fetches.push(prom);
}
const responses = await Promise.all(fetches)
for (const response of responses) {
if (response.length) {
let lineNum = 0
response.split('\n').forEach((line) => {
lineNum++
const row = line.split(',')
let time, open, high, low, close=null
switch (row.length) {
case 1:
if (row[0].length !== 0)
console.log(`Warning: weird nonempty row at OHLC line ${lineNum}: "${line}"`)
let finished = false
for( let ri=0; !finished && ri<responses.length; ri++ ) {
let lineNum = 0
const rows = responses[ri].split('\n')
for( let rj=0; rj<rows.length; rj++) {
const line = rows[rj];
const row = line.split(',')
let time, open, high, low, close=null
switch (row.length) {
case 1:
if (row[0].length !== 0)
console.log(`Warning: weird nonempty row at OHLC line ${lineNum}: "${line}"`)
break
case 2:
time = parseInt(row[0])
let price = parseFloat(row[1])
if (inverted)
price = 1/price
open = latest === null ? price : latest[1]
high = low = close = price
break
case 3:
time = parseInt(row[0])
if (time < from || time >= to)
break
case 2:
time = parseInt(row[0])
if (time < start || time >= to)
break
let price = parseFloat(row[1])
if (inverted)
price = 1/price
open = latest === null ? price : latest[1]
high = low = close = price
break
case 3:
time = parseInt(row[0])
if (time < start || time >= to)
break
open = parseFloat(row[1])
close = parseFloat(row[2])
if (inverted) {
open = 1/open
close = 1/close
}
high = Math.max(open, close)
low = Math.min(open,close)
if (latest!==null)
open = latest[1]
break
case 5:
time = parseInt(row[0])
if (time < start || time >= to)
break
open = parseFloat(row[1])
high = parseFloat(row[2])
low = parseFloat(row[3])
close = parseFloat(row[4])
if (inverted) {
open = 1/open
const h = high
high = 1/low
low = 1/h
close = 1/close
}
break
default:
console.log(`Warning: could not parse line ${lineNum} of OHLC file:\n${line}`)
open = parseFloat(row[1])
close = parseFloat(row[2])
if (inverted) {
open = 1/open
close = 1/close
}
high = Math.max(open, close)
low = Math.min(open,close)
if (latest!==null)
open = latest[1]
break
case 5:
time = parseInt(row[0])
if (time < from || time >= to)
break
open = parseFloat(row[1])
high = parseFloat(row[2])
low = parseFloat(row[3])
close = parseFloat(row[4])
if (inverted) {
open = 1/open
const h = high
high = 1/low
low = 1/h
close = 1/close
}
break
default:
console.log(`Warning: could not parse line ${lineNum} of OHLC file:\n${line}`)
break
}
if (time!==null) {
if (time >= to) {
console.log('time is past end of request:', time)
finished = true
break
}
if (close!==null) {
if (time >= from) {
fill(time, res.seconds)
const bar = {time:time*1000, open, high, low, close};
const bar = {time: time * 1000, open, high, low, close};
bars.push(bar)
latest = [time, close]
}
})
// console.log(`processed ${lineNum} lines`)
}
}
// else { console.log('response was empty') }
console.log(`processed ${lineNum} lines`)
}
// console.log('loadOHLC prefill bars', bars)
fill(to, res.seconds)
// console.log('loadOHLC bars', bars)
return bars
}

View File

@@ -1,7 +1,7 @@
import {DISTANT_FUTURE, DISTANT_PAST} from "@/blockchain/orderlib.js";
import {DISTANT_FUTURE, DISTANT_PAST, MAX_FRACTION} from "@/blockchain/orderlib.js";
import {allocationText, DLine, HLine} from "@/charts/shape.js";
import {createShape, deleteShapeId} from "@/charts/chart.js";
import {timestamp} from "@/misc.js";
import {sideColor, timestamp} from "@/misc.js";
import {useChartOrderStore} from "@/orderbuild.js";
export class OrderShapes {
@@ -16,9 +16,11 @@ export class OrderShapes {
for (const old of this.trancheShapes)
old.delete()
this.status = orderStatus
this.trancheShapes = [];
for (let i = 0; i < orderStatus.trancheStatus.length; i++)
this.trancheShapes.push(new TrancheShapes(this.symbol, this.status, i));
this.trancheShapes = []
const maxAllocation = Math.max(...orderStatus.order.tranches.map((ts)=>ts.fraction)) / MAX_FRACTION
if (orderStatus.trancheStatus !== undefined)
for (let i = 0; i < orderStatus.trancheStatus.length; i++)
this.trancheShapes.push(new TrancheShapes(this.symbol, this.status, i, maxAllocation));
}
show() {for (const t of this.trancheShapes) t.show();}
@@ -28,8 +30,7 @@ export class OrderShapes {
class TrancheShapes {
constructor(symbol, orderStatus, trancheIndex) {
// todo validate base/quote
constructor(symbol, orderStatus, trancheIndex, maxAllocation) {
if (symbol.inverted !== orderStatus.order.inverted) {
console.log('OrderShapes.createLine(): symbol has wrong inverson for this order')
return
@@ -38,14 +39,16 @@ class TrancheShapes {
this.status = orderStatus
this.trancheIndex = trancheIndex
this.tranche = orderStatus.order.tranches[trancheIndex]
this.trancheStatus = orderStatus.trancheStatus[trancheIndex]
this.shapes = []
this.fills = []
this.createShapes();
this.maxAllocation = maxAllocation
this.createShapes()
}
createShapes() {
// todo amounts
const t = this.tranche
// console.log('create tranche shapes', t)
if (t.marketOrder) {
if (t.startTime !== DISTANT_PAST) {
@@ -53,8 +56,10 @@ class TrancheShapes {
}
} else {
// check lines
this.createLine(t.minLine.slope, t.minLine.intercept);
this.createLine(t.maxLine.slope, t.maxLine.intercept);
const amount = this.status.order.amount * BigInt(t.fraction) / BigInt(MAX_FRACTION)
const buy = this.status.order.tokenIn === this.symbol.quote.a
this.createLine(t.minLine.slope, t.minLine.intercept, amount, buy);
this.createLine(t.maxLine.slope, t.maxLine.intercept, amount, !buy);
}
for (const f of this.status.trancheStatus[this.trancheIndex].fills)
this.createFillPoint(f)
@@ -72,67 +77,78 @@ class TrancheShapes {
* 10 ** -(amountIsBase ? this.symbol.base.d : this.symbol.quote.d)
const weight = Number(filledAmount) / Number(this.status.order.amount)
const amountSymbol = amountIsBase ? this.symbol.base.s : this.symbol.quote.s
console.log('fillpoint', buy, filledAmount, this.status.order, this.symbol)
// console.log('fillpoint', buy, filledAmount, this.status.order, this.symbol)
const time = f.time
const out = Number(f.filledOut) / (1-this.status.order.route.fee/1000000)
let price = out / Number(f.filledIn)
if (buy)
price = 1/price
price *= scale
console.log('price', price)
// console.log('price', price)
const channel = buy?'low':'high';
const text = (buy ? 'Buy ' : 'Sell ') + allocationText(weight, amount, amountSymbol, '\n')
const s = createShape(buy?'arrow_up':'arrow_down', {time, price}, {channel,text,lock:true})
console.log('created fill shape at', time, price)
// console.log('created fill shape at', time, price)
this.fills.push(s)
}
createLine(slope, intercept, amount) {
createLine(slope, intercept, amountBigInt, breakout) {
if (intercept === 0 && slope === 0) return
const t = this.tranche
const status = this.status
const symbol = this.symbol
const scale = 10**symbol.decimals;
const buy = status.order.tokenIn === this.symbol.quote.a
amount = Number(amount)
* 10 ** -(buy ? this.symbol.base.d : this.symbol.quote.d)
const decimals = buy ? this.symbol.base.d : this.symbol.quote.d;
amountBigInt = BigInt(amountBigInt)
const amount = Number(amountBigInt) * 10 ** - decimals
const amountSymbol = buy ? this.symbol.base.s : this.symbol.quote.s
const color = buy ? 'green' : 'red'
if (intercept !== 0 || slope !== 0) {
// console.log('tranche line', intercept, slope)
// line active
if (slope === 0) {
let price = intercept
price *= scale
// horizontal line
// console.log('hline', price)
const model = {price, color, maxAllocation: status.order.amount, amount, amountSymbol};
const s = new HLine(model, null, null, null, true)
this.shapes.push(s)
} else {
// diagonal line
let startTime = t.startTime
if (startTime === DISTANT_PAST)
startTime = timestamp() - useChartOrderStore().intervalSecs * 20 // 20 bars ago
let endTime = t.endTime
if (endTime === DISTANT_FUTURE)
endTime = timestamp() // use "now" as the drawing point's time
let startPrice = (intercept + slope * startTime);
let endPrice = (intercept + slope * endTime);
startPrice *= scale
endPrice *= scale
// console.log('dline', startTime, endTime, DISTANT_FUTURE, startPrice, endPrice)
// noinspection EqualityComparisonWithCoercionJS
const model = {
pointA: {time: startTime, price: startPrice},
pointB: {time: endTime, price: endPrice},
extendLeft: t.startTime === DISTANT_PAST,
extendRight: t.endTime === DISTANT_FUTURE,
color,
maxAllocation: status.order.amount, amount, amountSymbol,
};
const s = new DLine(model, null, null, null, true)
this.shapes.push(s)
const color = sideColor(buy)
const maxAllocation = this.maxAllocation
const allocation = t.fraction / MAX_FRACTION
const ts = this.trancheStatus
let sum = 0n
for (let i=0; i<ts.fills.length; i++)
sum += ts.fills[i].filled
const completed = (amountBigInt - sum) < status.order.minFillAmount
const extraText = completed ? '✓' : null
const textLocation = breakout === buy ? 'above' : 'below'
// line active
if (slope === 0) {
let price = intercept
price *= scale
// horizontal line
// console.log('hline', price)
const model = {
price, breakout, color, extraText, textLocation,
allocation, maxAllocation, amount, amountSymbol,
}
const s = new HLine(model, null, null, null, true)
this.shapes.push(s)
} else {
// diagonal line
let startTime = t.startTime
if (startTime === DISTANT_PAST)
startTime = timestamp() - useChartOrderStore().intervalSecs * 20 // 20 bars ago
let endTime = t.endTime
if (endTime === DISTANT_FUTURE)
endTime = timestamp() // use "now" as the drawing point's time
let startPrice = (intercept + slope * startTime);
let endPrice = (intercept + slope * endTime);
startPrice *= scale
endPrice *= scale
// console.log('dline', startTime, endTime, DISTANT_FUTURE, startPrice, endPrice)
// noinspection EqualityComparisonWithCoercionJS
const model = {
pointA: {time: startTime, price: startPrice},
pointB: {time: endTime, price: endPrice},
extendLeft: t.startTime === DISTANT_PAST,
extendRight: t.endTime === DISTANT_FUTURE,
breakout, color, extraText, textLocation,
allocation, maxAllocation, amount, amountSymbol,
}
const s = new DLine(model, null, null, null, true)
this.shapes.push(s)
}
}

View File

@@ -4,7 +4,7 @@ import {invokeCallback, mixin} from "@/common.js";
import {chart, createShape, deleteShapeId, dragging, draggingShapeIds, drawShape, widget} from "@/charts/chart.js";
import Color from "color";
import {dirtyItems, dirtyPoints, nearestOhlcStart} from "@/charts/chart-misc.js";
import {computeInterceptSlope} from "@/misc.js";
import {defined} from "@/misc.js";
//
@@ -40,6 +40,7 @@ export const ShapeType = {
export function allocationText(weight, amount, symbol, separator = ' ') {
// set breakout=true for a buy breakout and breakout=false for a sell breakout
const hasAmount = amount !== null && amount !== undefined && amount > 0
if (hasAmount)
amount = Number(amount)
@@ -109,7 +110,7 @@ export class Shape {
this.model.amount = null
this.model.amountSymbol = null
this.model.extraText = null
this.model.textLocation = 'above'
this.model.textLocation = null // defaults to 'above' if not set
// LEAF SUBCLASSES MUST CALL setModel(model) AFTER ALL CONSTRUCTION.
}
@@ -119,19 +120,21 @@ export class Shape {
//
setModel(model) {
if (model.color)
if (defined(model.color))
this.model.color = model.color
if (model.allocation !== null && model.allocation !== undefined)
if (defined(model.allocation))
this.model.allocation = model.allocation
if (model.maxAllocation !== null && model.maxAllocation !== undefined)
if (defined(model.maxAllocation))
this.model.maxAllocation = model.maxAllocation
if (model.amount !== null && model.amount !== undefined)
if (defined(model.amount))
this.model.amount = model.amount
if (model.amountSymbol)
if (defined(model.amountSymbol))
this.model.amountSymbol = model.amountSymbol
if (model.extraText)
if (defined(model.extraText))
this.model.extraText = model.extraText
if (model.textLocation)
if (defined(model.breakout))
this.model.breakout = model.breakout
if (defined(model.textLocation))
this.model.textLocation = model.textLocation
const newProps = {}
@@ -141,7 +144,7 @@ export class Shape {
newProps.textcolor = color
// line color
if (this.model.allocation && this.model.maxAllocation) {
if (defined(this.model.allocation) && defined(this.model.maxAllocation)) {
const w = this.model.allocation / this.model.maxAllocation
if (!w)
newProps.linecolor = 'rgba(0,0,0,0)'
@@ -158,6 +161,8 @@ export class Shape {
// text label
let text = allocationText(this.model.allocation, this.model.amount, this.model.amountSymbol)
if (this.model.breakout)
text += ' ' + (this.model.textLocation==='above' ? '▲Breakout▲' : '▼Breakout▼')
if (this.model.extraText)
text += ' '+this.model.extraText
if (this.debug) text = `${this.id} ` + text
@@ -199,10 +204,13 @@ export class Shape {
const p = this.type.drawingProp
const lc = this.model.lineColor ? this.model.lineColor : this.model.color;
const tc = this.model.textColor ? this.model.textColor : this.model.color;
const tl = this.model.textLocation ? this.model.textLocation : 'above';
if (lc)
o[p+".linecolor"] = lc
if (tc)
o[p+".textcolor"] = tc
if (tl)
o[p+".textlocation"] = tl
return o
}

View File

@@ -133,3 +133,11 @@ export function abiPath(name) {
}
export function parseFill(obj) {
let [tx, time, filledIn, filledOut, fee] = obj
time = new Date(time * 1000)
filledIn = BigInt(filledIn)
filledOut = BigInt(filledOut)
fee = BigInt(fee)
return {tx, time, filledIn, filledOut, fee}
}

View File

@@ -0,0 +1,38 @@
<template>
<slot v-if="s.regionApproved"/>
<v-card v-if="s.regionApproved===null" title="Loading..." prepend-icon="mdi-clock-outline"
text="If loading takes more than a second, please refresh your browser or contact support@dexorder.trade"/>
<v-card v-if="s.regionApproved===false" title="Restricted" prepend-icon="mdi-alert"
text="Dexorder is not available in your region."/>
</template>
<script setup>
import {useStore} from "@/store/store";
import {socket} from "@/socket.js";
import {useRoute} from "vue-router";
const s = useStore()
let timer = null
const bypass = useRoute().query.approval
function tryApproval() {
console.log('approval query', bypass)
if (timer!==null) {
clearTimeout(timer)
timer = null
}
if (s.regionApproved===null) {
socket.emit('approveRegion', bypass)
timer = setTimeout(tryApproval, 1000)
}
}
tryApproval()
</script>
<style scoped lang="scss">
</style>

View File

@@ -1,35 +0,0 @@
<template>
<slot v-if="s.allowed"/>
<v-card v-if="!s.allowed" rounded="0" title="Dexorder Closed Beta">
<v-card-item><v-text-field v-model="password" label="Beta Password" class="maxw"/></v-card-item>
<v-card-text>
Follow our social media for public release updates!
</v-card-text>
<v-card-item><social/></v-card-item>
</v-card>
</template>
<script setup>
import {useStore} from "@/store/store";
import Social from "@/components/Social.vue";
import {ref, watchEffect} from "vue";
import {hashMessage} from "ethers";
const s = useStore()
const password = ref(null)
const passHash = '0x3e6e96bd824dd0a5e5361853719ef051e939b91f3fc6fd0f685b4c414c7ba89e'
watchEffect(()=>{
if (!password.value) return
const canonical = password.value.replace(/[^a-zA-Z]/g, '').toLowerCase();
const hash = hashMessage(canonical);
if (hash===passHash)
s.allowed = true
})
</script>
<style scoped lang="scss">
</style>

View File

@@ -17,12 +17,12 @@
<script setup>
import {useOrderStore, useStore} from "@/store/store";
import {routeInverted} from "@/misc.js";
import RoutePrice from "@/components/RoutePrice.vue";
import {validateAmount, validateRequired} from "@/validate.js";
import {computed} from "vue";
// noinspection ES6UnusedImports
import {vAutoSelect} from "@/misc.js";
import {routeInverted} from "@/misc.js";
const os = useOrderStore()
const props = defineProps({

View File

@@ -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()

View File

@@ -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)
}

View File

@@ -1,5 +1,5 @@
<template>
<beta-signin>
<approve-region>
<slot v-if="status===Status.OK" v-bind="$props"/>
<v-card v-if="status!==Status.OK" rounded="0">
<v-card-title>
@@ -33,7 +33,8 @@
</v-card-actions>
</v-card>
</beta-signin>
<terms-of-service v-if="status===Status.OK"/>
</approve-region>
</template>
<script setup>
@@ -42,7 +43,8 @@ import {computed, ref} from "vue";
import {addNetwork, connectWallet, switchChain} from "@/blockchain/wallet.js";
import Btn from "@/components/Btn.vue";
import Logo from "@/components/Logo.vue";
import BetaSignin from "@/components/BetaSignin.vue";
import ApproveRegion from "@/components/ApproveRegion.vue";
import TermsOfService from "@/components/TermsOfService.vue";
const s = useStore()
const disabled = ref(false)

View File

@@ -23,11 +23,9 @@ import {useOrderStore, useStore} from "@/store/store";
import PhoneCard from "@/components/PhoneCard.vue";
import Amount from "@/components/Amount.vue"
// noinspection ES6UnusedImports
import {nav, routeInverted, SingletonCoroutine, vAutoSelect} from "@/misc.js";
import {nav, SingletonCoroutine, vAutoSelect} from "@/misc.js";
import {newOrder} from "@/blockchain/orderlib.js";
import {FixedNumber} from "ethers";
import {pendOrder} from "@/blockchain/wallet.js";
import router from "@/router/index.js";
import PairChoice from "@/components/PairChoice.vue";
import NeedsSigner from "@/components/NeedsSigner.vue";
import {useChartOrderStore} from "@/orderbuild.js";

View File

@@ -33,10 +33,9 @@
import TokenChoice from "@/components/TokenChoice.vue"
import {useOrderStore, useStore} from "@/store/store";
import RoutePrice from "@/components/RoutePrice.vue";
import {findRoute, routeFinder} from "@/blockchain/route.js";
import {SingletonCoroutine, routeInverted} from "@/misc.js";
import {computed, ref} from "vue";
import {queryHelperContract} from "@/blockchain/contract.js";
import {routeFinder} from "@/blockchain/route.js";
import {computed} from "vue";
import {routeInverted} from "@/misc.js";
const s = useStore()
const os = useOrderStore()

View File

@@ -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

View File

@@ -7,8 +7,8 @@ import {useOrderStore, useStore} from "@/store/store";
import {subPrices, unsubPrices, WIDE_PRICE_FORMAT} from "@/blockchain/prices.js";
import {computed, onBeforeUnmount} from "vue";
import {FixedNumber} from "ethers";
import {routeInverted} from "@/misc.js";
import {subOHLCs} from "@/blockchain/ohlcs.js";
import {routeInverted} from "@/misc.js";
const s = useStore()
const os = useOrderStore()

View File

@@ -142,5 +142,6 @@ body {
flex: 1;
width: 100%;
min-height: 5em;
max-height: 100%;
}
</style>

View File

@@ -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,8 +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 {timestampString} from "@/misc.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";
@@ -185,6 +186,7 @@ import {useChartOrderStore} from "@/orderbuild.js";
import {lookupSymbol, tickerForOrder} from "@/charts/datafeed.js";
import {setSymbol} from "@/charts/chart.js";
import {uniswapV3AveragePrice} from "@/blockchain/uniswap.js";
import {timestampString} from "@/misc.js";
const PairPrice = defineAsyncComponent(()=>import("@/components/PairPrice.vue"))
const TokenAmount = defineAsyncComponent(()=>import('./TokenAmount.vue'))
@@ -214,9 +216,7 @@ watch(selected, async ()=>{
// switch symbol
deleteOrderShapes()
await setSymbol(symbol)
console.log('change symbol completed')
}
console.log('creating order shape', id)
orderShapes[id] = new OrderShapes(symbol, status)
}
}
@@ -228,14 +228,12 @@ function deleteOrderShapes(keepSet={}) {
const keys = [...Object.keys(orderShapes)]
for (const id of keys) {
if (!(id in keepSet)) {
console.log('deleting order shape', id)
orderShapes[id].delete()
delete orderShapes[id]
}
}
}
const orderShapes = {}
onUnmounted(()=>{

View File

@@ -0,0 +1,700 @@
<template>
<v-dialog v-model="show" max-width="500px" persistent>
<v-card>
<v-card-title class="text-center">Dexorder Terms of Service</v-card-title>
<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 Privacy Policy carefully because they govern your use of the
website (and all subdomains and subpages thereon) located at dexorder.trade, including without limitation the
subdomains app.dexorder.trade and www.dexorder.trade (collectively, the <b>Site</b>), and the Dexorder web
application graphical user interface and any other services accessible via the Site (together with the Site, web
application, and other services, collectively, the <b>Dexorder Service</b>) offered by Dexorder Trading Services Ltd.
(<b>Dexorder</b>, <b>we</b>, <b>our</b>, or <b>us</b>).
</v-card-text>
<v-card-text>
<b>
BY USING THE DEXORDER SERVICE, YOU REPRESENT THAT (I) YOU ARE NOT LOCATED WITHIN THE UNITED
STATES; AND (II) YOU ARE NOT A PERSON OR ENTITY WHO IS RESIDENT IN, A CITIZEN OF, IS LOCATED IN, IS
INCORPORATED IN, OR HAS A REGISTERED OFFICE IN ANY RESTRICTED TERRITORY, AS DEFINED BELOW (ANY
SUCH PERSON OR ENTITY FROM WITHIN THE UNITED STATES OR A RESTRICTED TERRITORY, IS REFERRED TO
HEREIN AS A RESTRICTED PERSON).
</b>
</v-card-text>
<v-card-text>
WHEN YOU AGREE TO THESE TERMS, YOU ARE AGREEING (WITH LIMITED EXCEPTION) TO RESOLVE ANY DISPUTE
BETWEEN YOU AND DEXORDER THROUGH BINDING, INDIVIDUAL ARBITRATION RATHER THAN IN COURT. PLEASE
REVIEW CAREFULLY SECTION 16 (DISPUTE RESOLUTION) BELOW FOR DETAILS REGARDING ARBITRATION. HOWEVER, IF
YOU ARE A RESIDENT OF A JURISDICTION WHERE APPLICABLE LAW PROHIBITS ARBITRATION OF DISPUTES, THE
AGREEMENT TO ARBITRATE IN SECTION 16 WILL NOT APPLY TO YOU, BUT THE PROVISIONS OF SECTION 15
(GOVERNING LAW) WILL APPLY INSTEAD.
</v-card-text>
<v-card-title>1. Description of Dexorder Service</v-card-title>
<v-card-text>
(a) The Dexorder Service allows you to access an online web application graphical user
interface (the <b>App</b>) which enables you to interact with a protocol consisting of a set of smart contracts (the
<b>Smart Contracts</b>) and to create and interact with a user controlled smart contract involving digital assets over
which only you have upgrade authority (a <b>Vault</b> and together with the Smart Contracts, the <b>Protocol</b>). You
may use your Vault to send signals to, interact with, and initiate actions on third party smart contract blockchain
protocols (<b>Interactions</b>) operating on decentralized exchanges (e.g., Uniswap) (<b>DEXs</b>). Certain Interactions
may require threshold parameters to be met and that a third party transmit an oracle related activation signal
(the <b>Activation Signal</b>) to the Vault in order to effectuate your commands (such party being an <b>Oracle</b>).
Dexorder may in the ordinary course of events be an Oracle (<b>Dexorder Oracle</b>), but bears no obligation nor
promise to do so on an ongoing basis, and you may send such Activation Signal yourself or utilize a third-party
Oracle to do so. Further, Dexorder is not and does not offer a digital wallet, and has no custody or control over
your digital wallet, which is never accessible by Dexorder, and only users, and not Dexorder, may provide or
withdraw tokens to be held by Vault. From time to time, the Services may include making recommendations
with respect to technical changes that only you may accept and implement.
</v-card-text>
<v-card-text>
(b) <b>Interface</b>. The Dexorder Service provides you with access to the Protocol, which is a user
controlled, non-custodial protocol, upgradeable only by your actions and consent, deployed on the blockchains
indicated on our Site, and provides information and interaction capabilities with other blockchain related service
providers. All information provided in connection with your access and use of the Dexorder Service is for
informational purposes only. You should not take, or refrain from taking, any action based on any information
contained on the Dexorder Service or any other information that we make available at any time, including blog
posts, data, articles, links to third-party content, Discord content, news feeds, tutorials, tweets, and videos.
Before you make any financial, legal, technical, or other decisions involving the Dexorder Service, you should
seek independent professional advice from a licensed and qualified individual in the area for which such advice
would be appropriate. Because the Dexorder Service provides information about the Protocol, these Terms also
provide some information about the use of the Protocol. This information is not intended to be comprehensive
or address all aspects of the Protocol.
</v-card-text>
<v-card-text>
(c) <b>Our Relationship</b>. You acknowledge and agree that Dexorder is an online platform
provider and not a financial institution, broker dealer, exchange or money services business. Dexorder does not
direct or control the day-to-day activities of users accessing the Dexorder Service. Neither we nor any affiliated
entity is a party to any transaction on the blockchain network underlying the Protocol; we do not have
possession, custody or control over any cryptoassets appearing on the Dexorder Service or on the Protocol; and
we do not have possession, custody, or control over any users funds or cryptoassets. Further, we do not store,
send, or receive any funds or cryptoassets on your behalf. You understand that when you interact with any
Protocol smart contracts, you retain control over your cryptoassets at all times. You are solely responsible for
evaluating any proposed technical changes and how such changes may alter current or future Interactions.
Furthermore, you understand and acknowledge that only you have absolute and ultimate authority over the
implementation of any such changes and the responsibility therefor. The private key associated with your Vault
is the only private key that can control the cryptoassets in the Vault. You alone are responsible for securing your
private keys. We do not have access to your private keys. Because the Protocol is non-custodial, we are not
intermediaries, agents, advisors, or custodians, and we do not have a fiduciary relationship or obligation to you
regarding any other decisions or activities that you affect when using the Dexorder Service or interacting with
the Protocol. You acknowledge that we, for the avoidance of doubt, do not have any information regarding any
users, users identities, or services beyond what is available, obtainable publicly via the blockchain, or shared by
you when you access the Dexorder Service. We are not responsible for any activities you engage in when using
the Dexorder Service, and you should understand the risks associated with cryptoassets, blockchain technology
generally, and the Interface.
</v-card-text>
<v-card-title>
2. Agreement to Terms
</v-card-title>
<v-card-text>
By using our Dexorder Service, you agree to be bound by these Terms. If you dont agree to be bound by these Terms,
do not use the Dexorder Service.
</v-card-text>
<v-card-title>3. Changes to these Terms or the Dexorder Service</v-card-title>
<v-card-text>
We may update the Terms, including any addendum terms, from time to time in our sole discretion. If we do, well let
you know by posting the updated Terms on the Site and/or may also send other communications. Its important that
you review the Terms whenever we update them or you use the Dexorder Service. If you continue to use the Dexorder
Service after we have posted updated Terms it means that you accept and agree to the changes. If you dont agree to
be bound by the changes, you may not use the Dexorder Service anymore. Because our Dexorder Service is evolving
over time we may change or discontinue all or any part of the Dexorder Service, at any time and without notice, at our
sole discretion.
</v-card-text>
<v-card-title>4. Who May Use the Dexorder Service?</v-card-title>
<v-card-text>
(a) <u>Eligibility</u>. The Dexorder Service is only available to users in certain jurisdictions outside
of the United States and that are at least 18 years old, capable of forming a binding contract with the Dexorder
and not otherwise barred from using the Dexorder Service under Applicable Law. You may not attempt to access
or use the Dexorder Service if you are not permitted to do so (including without limitation if you are a Restricted
Person).
</v-card-text>
<v-card-text>
(b) <u>Compliance</u>. You certify that you will comply with all Applicable Law when using the
Dexorder Service. You are solely responsible for ensuring that your access and use of the Dexorder Service in
such country, territory, or jurisdiction does not violate any Applicable Laws. You must not use any software or
networking techniques, including use of a virtual private network (<b>VPN</b>) to circumvent or attempt to
circumvent this prohibition. We reserve the right to monitor the locations from which our Dexorder Service is
accessed. Furthermore, we reserve the right, at any time, in our sole discretion, to block access to the Dexorder
Service, in whole or in part, from any geographic location, IP addresses, and unique device identifiers
</v-card-text>
<v-card-title>5. Use of the Dexorder Service</v-card-title>
<v-card-text>
(a) <u>User Representations and Warranties</u>. As a condition to accessing or using the Dexorder
Service, you represent and warrant to Dexorder that:
</v-card-text>
<v-card-text class="ii">
(i) if you are entering into these Terms as an individual, then you are of legal age in
the jurisdiction in which you reside and you have the legal capacity to enter into these Terms and be bound by
them and if you are entering into these Terms as an entity, then you must have the legal authority to accept
these Terms on that entitys behalf, in which case you (except as used in this paragraph) will mean that entity;
</v-card-text>
<v-card-text class="ii">
(ii) you are not in or residing in the United States;
</v-card-text>
<v-card-text class="ii">
(iii) you are not in or residing in Cuba, Iran, North Korea, Syria, Belarus, Russia, and
the Crimea, Luhansk, Donetsk, Zaporizhzhia, and Kherson regions of Ukraine, or any other country or jurisdiction
to which the Cayman Islands, the United Kingdom, United States, the United Nations Security Council, or the
European Union embargoes goods or imposes similar sanctions (collectively, <b>Restricted Territories</b>);
</v-card-text>
<v-card-text class="ii">
(iv) you are not on any sanctions list or equivalent maintained by the Cayman
Islands, the United Kingdom, United States, the United Nations Security Council, or the European Union
(collectively, <b>Sanctions Lists Persons</b>) and you do not intend to transact with any Restricted Person or
Sanctions List Person;
</v-card-text>
<v-card-text class="ii">
(v) you do not, and will not, use VPN software or any other privacy or
anonymization tools or techniques to circumvent, or attempt to circumvent, any restrictions that apply to the
Dexorder Service;
</v-card-text>
<v-card-text class="ii">
(vi) you have obtained all required consents from any individual whose personal
information you transfer to us in connection with your use of the Dexorder Service; and
</v-card-text>
<v-card-text class="ii">
(vii) all information that you provide through the Dexorder Service is current,
complete, true, and accurate and you will maintain the security and confidentiality of your private keys
associated with your public wallet address, passwords, API keys, passwords or other information associated with
your Vault or otherwise, as applicable.
</v-card-text>
<v-card-text class="ii">
(viii) your access to the Dexorder Service is not: (a) prohibited by and does not
otherwise violate or assist you to violate any domestic or foreign law, rule, statute, regulation, by-law, order,
protocol, code, decree, or another directive, requirement, or guideline, published or in force that applies to or is
otherwise intended to govern or regulate any person, property, transaction, activity, event or other matter,
including any rule, order, judgment, directive or other requirement or guideline issued by any domestic or
foreign federal, provincial or state, municipal, local or other governmental, regulatory, judicial or administrative
authority having jurisdiction over Dexorder, you, the Site or the Dexorder Service, or as otherwise duly enacted,
enforceable by law, the common law or equity (collectively, <b>Applicable Laws</b>); or (b) contribute to or facilitate
any illegal activity.
</v-card-text>
<v-card-text>
(b) <u>Limitations</u>. As a condition to accessing or using the Dexorder Service or the Site, you
acknowledge, understand, and agree to the following:
</v-card-text>
<v-card-text class="ii">
(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 Dexorders Execution Policy located at
<a href="https://dexorder.trade/home/execution_policy">https://dexorder.trade/home/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 error
in Interaction execution or a malfunction in the Dexorder Service); (b) equipment malfunctions; (c) periodic
maintenance procedures or repairs that Dexorder or any of its suppliers or contractors may undertake from time
to time; (d) causes beyond Dexorders control or that Dexorder could not reasonably foresee; (e) disruptions and
temporary or permanent unavailability of underlying blockchain infrastructure; (f) unavailability of third-party
service providers or external partners for any reason; or (g) an Activation Signal not being sent.
</v-card-text>
<v-card-text class="ii">
(ii) the Site and the Dexorder Service may evolve, which means Dexorder may apply
changes, replace, or discontinue (temporarily or permanently) the Dexorder Service at any time in its sole
discretion;
</v-card-text>
<v-card-text class="ii">
(iii) Dexorder does not act as an agent for you or any other user of the Site or the Dexorder Service;
</v-card-text>
<v-card-text class="ii">
(iv) you are solely responsible for your use of the Dexorder Service; and
</v-card-text>
<v-card-text class="ii">
(v) we owe no fiduciary duties or liabilities to you or any other party, and that to
the extent any such duties or liabilities may exist at law or in equity, you hereby irrevocably disclaim, waive, and
eliminate those duties and liabilities.
</v-card-text>
<v-card-title>6. Interactions; Fees</v-card-title>
<v-card-text>
(a) <u>Interactions</u>. In order to effectuate Interactions, you may need to transfer digital assets
(e.g., tokens) to the Vault. You acknowledge that you may use the Dexorder Services to process and cause
Interactions to be operate with an applicable DEX, including without limitation the transfer of digital assets via
the DEX in accordance with the Interaction. For clarity, the Vault is a smart contract automatically controlled by
the blockchain. Dexorder is an interface to that smart contract, and does not offer a digital wallet and has no
custody or control over your digital wallet or any digital assets or cryptocurrency, which is never accessible by
Dexorder.
</v-card-text>
<v-card-text>
(b) <u>Fees</u>.
</v-card-text>
<v-card-text class="ii">
(i) Dexorder charges fees upfront for usage of the Dexorder Services at the time of
user Interactions (<b>Fees</b>). You agree to pay all applicable Fees upfront to Dexorder, in the amounts
communicated or presented to you via the Dexorder Service in connection with usage of the Dexorder Service.
Each party shall be responsible for all Taxes imposed on its income or property.
</v-card-text>
<v-card-text class="ii">
(ii) There may be associated fees in connection with transactions enacted on a
blockchain. All transactions using blockchains require the payment of gas fees, which are essentially transaction
fees paid on every transaction that occurs on the selected blockchain network. We do not collect any such fees.
Please note that accessing the Protocol may result in you incurring gas fees, which are non-refundable, and are
paid by you in all circumstances. You pay all gas fees incurred by you as relating to interacting with the Protocol.
</v-card-text>
<v-card-text>
(c) <u>Tax Records and Reporting</u>. You are solely responsible for all costs incurred by you in
using the Dexorder Service, and for determining, collecting, reporting, and paying all applicable Taxes that you
may be required by law to collect and remit to any governmental or regulatory agencies. As used herein,
<b>Taxes</b> means the taxes, duties, levies, tariffs, and other charges imposed by any federal, state, multinational or
local governmental or regulatory authority. We reserve the right to report any activity occurring using the
Dexorder Service to relevant tax authorities as required under Applicable Law. You are solely responsible for
maintaining all relevant Tax records and complying with any reporting requirements you may have as related to
our Dexorder Service. You are further solely responsible for independently maintaining the accuracy of any
record submitted to any tax authority including any information derived from the Dexorder Service.
</v-card-text>
<v-card-text>
(d) Suspensions or Terminations. In addition to the other suspension and termination rights
in these Terms, we may suspend or terminate your access to the Dexorder Service, or any and all Interactions, at
any time in connection with any Interaction or transaction (i) as required by Applicable Law or any governmental
authority, (ii) if we are unable to process or execute an Interaction or transaction after several attempts (as
described in the Execution Policy or otherwise in Dexorders reasonable discretion), or (iii) if we in our sole and
reasonable discretion determine you are violating the terms of any third-party service provider or these Terms,
including, without limitation, if we reasonably believe any of your representations and warranties may be untrue
or inaccurate or you are violating or have violated any of the geographical restrictions that apply to the
Dexorder Service, and in any case we will not be liable to you for any losses or damages you may suffer as a
result of or in connection with the Dexorder Service being inaccessible to you at any time or for any reason. Such
suspension or termination shall not constitute a breach of these Terms by Dexorder. In accordance with its anti-
money laundering, anti-terrorism, anti-fraud, and other compliance policies and practices, we may impose
limitations and controls on the ability of you or any beneficiary to utilize the Dexorder Service. Such limitations
may include rejecting transaction requests, freezing funds in any case where Dexorder has such ability, or
otherwise restricting you from using the Dexorder Service, all to the extent of our ability to do so.
</v-card-text>
<v-card-title>7. General Prohibitions and Dexorders Enforcement Rights.</v-card-title>
<v-card-text>
You agree not to do any of the
following:
</v-card-text>
<v-card-text>
(a) Engage in or induce others to engage in any form of unauthorized access, hacking, or
social engineering, including without limitation any distributed denial or service or DDoS attack, of Dexorder, the
Dexorder Service, or any users of the foregoing;
</v-card-text>
<v-card-text>
(b) Use, display, mirror or frame the Dexorder Service or any individual element within the
Dexorder Service, Dexorders name, any Dexorder trademark, logo or other proprietary information, or the
layout and design of any page or form contained on a page, without Dexorders express written consent;
</v-card-text>
<v-card-text>
(c) Access, tamper with, or use non-public areas of the Dexorder Service, Dexorders
computer systems, or the technical delivery systems of Dexorders providers;
</v-card-text>
<v-card-text>
(d) Attempt to probe, scan or test the vulnerability of any Dexorder system or network or
breach any security or authentication measures;
</v-card-text>
<v-card-text>
(e) Avoid, bypass, remove, deactivate, impair, descramble or otherwise circumvent any
technological measure implemented by Dexorder or any of Dexorders providers or any other third party
(including another user) to protect the Dexorder Service;
</v-card-text>
<v-card-text>
(f) Attempt to access or search the Dexorder Service or download content from the
Dexorder Service using any engine, software, tool, agent, device or mechanism (including spiders, robots,
crawlers, data mining tools or the like) other than the software and/or search agents provided by Dexorder or
other generally available third-party web browsers;
</v-card-text>
<v-card-text>
(g) Use any meta tags or other hidden text or metadata utilizing a Dexorder trademark,
logo, URL or product name without Dexorders express written consent;
</v-card-text>
<v-card-text>
(h) Forge any TCP/IP packet header or any part of the header information in any email or
newsgroup posting, or in any way use the Dexorder Service to send altered, deceptive or false source-identifying
information;
</v-card-text>
<v-card-text>
(i) Attempt to decipher, decompile, disassemble or reverse engineer any of the software
used to provide the Dexorder Service;
</v-card-text>
<v-card-text>
(j) Interfere with, or attempt to interfere with, the access of any user, host or network,
including, without limitation, sending a virus, exploiting any bug, overloading, flooding, spamming, or mail-
bombing the Dexorder Service;
</v-card-text>
<v-card-text>
(k) Use the Dexorder Service for benchmarking or analysis in a manner that could, directly
or indirectly, interfere with, detract from, or otherwise harm the Dexorder Service or DEX;
</v-card-text>
<v-card-text>
(l) Collect or store any personally identifiable information from the Dexorder Service from
other users of the Dexorder Service without their express permission;
</v-card-text>
<v-card-text>
(m) Impersonate or misrepresent your affiliation with any person or entity;
</v-card-text>
<v-card-text>
(n) Create or list any counterfeit items (including digital assets);
</v-card-text>
<v-card-text>
(o) Fabricate in any way any transaction or process related thereto;
</v-card-text>
<v-card-text>
(p) Engage or assist in any activity that violates any law, statute, ordinance, regulation, or
sanctions program, , or that involves proceeds of any unlawful activity (including but not limited to money
laundering, terrorist financing or deliberately engaging in activities designed to adversely affect the performance
of the Dexorder Service);
</v-card-text>
<v-card-text>
(q) Engage in deceptive or manipulative trading activities;
</v-card-text>
<v-card-text>
(r) Disguise or interfere in any way with the IP address of the computer you are using to
access or use the Dexorder Service or that otherwise prevents us from correctly identifying the IP address of the
computer you are using to access the Dexorder Service;
</v-card-text>
<v-card-text>
(s) Transmit, exchange, or otherwise support the direct or indirect proceeds of criminal or
fraudulent activity;
</v-card-text>
<v-card-text>
(t) Violate any Applicable Law or regulation; or
</v-card-text>
<v-card-text>
(u) Encourage or enable any other individual to do any of the foregoing.
</v-card-text>
<v-card-text>
Dexorder is not obligated to monitor access to or use of the Dexorder Service or to review or edit any content.
However, we have the right to do so for the purpose of operating the Dexorder Service, to ensure compliance with
these Terms and to comply with Applicable Law or other legal requirements. We reserve the right, but are not
obligated, to suspend or terminate access to the Dexorder Service at any time if we believe you are violating these
Terms. We have the right to investigate violations of these Terms or conduct that affects the Dexorder Service. We
may also consult and cooperate with law enforcement authorities to prosecute users who violate the law.
</v-card-text>
<v-card-title>8. Feedback</v-card-title>
<v-card-text>
We appreciate feedback, comments, ideas, proposals and suggestions for improvements to the Dexorder Service
(<b>Feedback</b>). If you choose to submit Feedback, you agree that we are free to use it (and permit others to use it)
without any restriction or compensation to you.
</v-card-text>
<v-card-title>9. Links to Third Party Websites or Resources</v-card-title>
<v-card-text>
The Dexorder Service may allow you to access third-party websites, integrations, or other resources, including the DEX,
services providing Activation Signals, and any bridge between the DEX and any third party protocols (collectively,
<b>Third Party Resources</b>). We provide access only as a convenience and are not responsible for the content, products
or services on or available from those resources or links displayed on such websites. You acknowledge sole
responsibility for and assume all risk arising from, your use of any third-party resources. Our provision of access to
Third Party Resources does not constitute approval, endorsement, or control of such Third Party Resource.
</v-card-text>
<v-card-title>10. Termination</v-card-title>
<v-card-text>
We may suspend or terminate your access to and use of the Dexorder Service, at our sole discretion, at any time and
without notice to you. You acknowledge and agree that we shall have no liability or obligation to you in such event and
that you will not be entitled to a refund of any amounts that you have already paid to us or any third party, to the
fullest extent permitted by Applicable Law. Upon any termination, discontinuation, or cancellation of the Dexorder
Service or your account, the following Sections will survive: 6.(d) , 7 , 8 , 10 , 11 , 13 , 14 , 15 , 16 , and 17 .
</v-card-text>
<v-card-title>11. Warranty Disclaimers</v-card-title>
<v-card-text>
THE DEXORDER SERVICE (INCLUDING WITHOUT LIMITATION THE VAULT) AND ANY CONTENT CONTAINED THEREIN, AS
WELL AS THE PROTOCOL, THE DEXORDER ORACLE, AND ANY ASSOCIATED PROTOCOL OR BLOCKCHAIN MESSAGING
FUNCTIONALITY SUCH AS ACTIVATION SIGNALS UNDERLYING THE DEXORDER SERVICE (TOGETHER, THE <b>UTILITIES</b>),
ARE PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND. WITHOUT LIMITING THE FOREGOING, WE EXPLICITLY
DISCLAIM ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
ENJOYMENT AND NON-INFRINGEMENT, AND ANY WARRANTIES ARISING OUT OF COURSE OF DEALING OR USAGE OF
TRADE. WE MAKE NO WARRANTY THAT THE UTILITIES WILL MEET YOUR REQUIREMENTS, BE AVAILABLE ON AN
UNINTERRUPTED, SECURE, OR ERROR-FREE BASIS. WE MAKE NO WARRANTY REGARDING THE QUALITY, ACCURACY,
TIMELINESS, TRUTHFULNESS, COMPLETENESS OR RELIABILITY OF ANY INFORMATION OR CONTENT ON THE UTILITIES.
DEXORDER FURTHER EXPRESSLY DISCLAIMS ALL LIABILITY OR RESPONSIBILITY IN CONNECTION WITH THIRD PARTY
SERVICES. NOTHING HEREIN NOR ANY USE OF THE UTILITIES IN CONNECTION WITH THIRD PARTY SERVICES
CONSTITUTES OUR ENDORSEMENT, RECOMMENDATION OR ANY OTHER AFFILIATION OF OR WITH ANY THIRD PARTY
SERVICES.
</v-card-text>
<v-card-text>
DEXORDER DOES NOT REPRESENT OR WARRANT THAT ANY CONTENT ON THE UTILITIES IS ACCURATE, COMPLETE,
RELIABLE, CURRENT OR ERROR-FREE. WE WILL NOT BE LIABLE FOR ANY LOSS OF ANY KIND FROM ANY ACTION TAKEN
OR TAKEN IN RELIANCE ON MATERIAL OR INFORMATION CONTAINED ON THE UTILITIES. DEXORDER CANNOT AND
DOES NOT REPRESENT OR WARRANT THAT THE UTILITIES, ANY CONTENT THEREIN, OR OUR SERVERS ARE FREE OF
VIRUSES OR OTHER HARMFUL COMPONENTS.
</v-card-text>
<v-card-text>
WE CANNOT GUARANTEE THE SECURITY OF ANY DATA THAT YOU DISCLOSE ONLINE. YOU ACCEPT THE INHERENT
SECURITY RISKS OF PROVIDING INFORMATION AND DEALING ONLINE OVER THE INTERNET AND WILL NOT HOLD US
RESPONSIBLE FOR ANY BREACH OF SECURITY.
</v-card-text>
<v-card-text>
DEXORDER WILL NOT BE RESPONSIBLE OR LIABLE TO YOU FOR ANY LOSS AND TAKES NO RESPONSIBILITY FOR, AND
WILL NOT BE LIABLE TO YOU FOR, ANY USE OF THE UTILITIES, INCLUDING BUT NOT LIMITED TO ANY LOSSES,
DAMAGES OR CLAIMS ARISING FROM: (I) USER ERROR SUCH AS FORGOTTEN PASSWORDS, INCORRECTLY
CONSTRUCTED TRANSACTIONS, EXCEEDING TRANSFER LIMITS OF THIRD PARTY RESOURCES OR THE DEX, OR
MISTYPED WALLET ADDRESSES; (II) SERVER FAILURE OR DATA LOSS; (III) BLOCKCHAIN NETWORKS, CRYPTOCURRENCY
WALLETS, CORRUPT FILES, SOFTWARE ERRORS, OR BUGS; (IV) UNAUTHORIZED ACCESS TO THE UTILITIES; OR (V) ANY
THIRD PARTY UTILITIES, INCLUDING WITHOUT LIMITATION THE USE OF VIRUSES, PHISHING, BRUTEFORCING OR OTHER
MEANS OF ATTACK AGAINST ANY BLOCKCHAIN NETWORK UNDERLYING THE UTILITIES.
</v-card-text>
<v-card-text>
THE UTILITIES MAY INCLUDE THE PLACEMENT OR EXECUTION OF AN ACTIVATION SIGNAL TO A USER VAULT WITH
RESPECT TO USER DEFINED INTERACTIONS (E.G., VIA TRANSMITTING AN ACTIVATION SIGNAL WHICH TRIGGERS
INTERACTION EXECUTION), HOWEVER, ANYONE, INCLUDING YOU OR ANY THIRD PARTY, MAY CAUSE AN INTERACTION
TO BE EXECUTED (SUCH AS BY TRANSMITTING THE APPLICABLE ACTIVATION SIGNAL), AND NOTWITHSTANDING
ANYTHING TO THE CONTRARY IN THESE TERMS, DEXORDER DOES NOT GUARANTEE THE PLACEMENT OR EXECUTION
OR ANY INTERACTION, INCLUDING WITHOUT LIMITATION THAT DEXORDER WILL TRANSMIT ANY PARTICULAR
ACTIVATION SIGNAL TO TRIGGER EXECUTION OF ANY INTERACTION, OR THAT AN INTERACTION WILL OTHERWISE BE
PROPERLY CARRIED OUT PURSUANT TO A VAULT. YOU ACKNOWLEDGE AND AGREE THAT YOU WILL NOT RELY ON THE
UTILITIES TO CARRY OUT PLACEMENTS OR EXECUTIONS OF INTERACTIONS. IF ANY PARTICULAR INTERACTION THAT IS
PLACED IS NOT EXECUTED BY DEXORDER IN A TIMELY MANNER, YOU MAY CAUSE SUCH INTERACTION TO BE
EXECUTED YOURSELF OR BY ENGAGING A THIRD PARTY SERVICE PROVIDER TO DO SO (E.G., BY TRANSMITTING THE
APPLICABLE ACTIVATION SIGNAL YOURSELF OR ENGAGING A THIRD PARTY TO DO SO). YOU ACCEPT THE INHERENT
RISK THAT ANY PARTICULAR INTERACTION MAY NOT BE EXECUTED, INCLUDING WITHOUT LIMITATION DUE TO BAD
ACTORS OR THE MALFUNCTION OF THE UTILITIES, AND DEXORDER HEREBY DISCLAIMS ANY AND ALL LIABILITY AND
RESPONSIBILITY IN CONNECTION WITH THE PLACEMENT OR EXECUTION OF INTERACTIONS AND THE VAULT.
</v-card-text>
<v-card-text>
THE UTILITIES MAY NOT BE AVAILABLE DUE TO ANY NUMBER OF FACTORS INCLUDING, BUT NOT LIMITED TO,
PERIODIC SYSTEM MAINTENANCE, SCHEDULED OR UNSCHEDULED, ACTS OF GOD, UNAUTHORIZED ACCESS, VIRUSES,
DENIAL OF SERVICE OR OTHER ATTACKS, TECHNICAL FAILURE OF THE UTILITIES AND/OR TELECOMMUNICATIONS
INFRASTRUCTURE OR DISRUPTION, AND THEREFORE WE EXPRESSLY DISCLAIM ANY EXPRESS OR IMPLIED WARRANTY
REGARDING THE USE AND/OR AVAILABILITY, ACCESSIBILITY, SECURITY OR PERFORMANCE OF THE UTILITIES CAUSED
BY SUCH FACTORS. WE DO NOT MAKE ANY REPRESENTATIONS OR WARRANTIES AGAINST THE POSSIBILITY OF
DELETION, MISDELIVERY OR FAILURE TO STORE COMMUNICATIONS, PERSONALIZED SETTINGS OR OTHER DATA.
SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF CERTAIN WARRANTIES. ACCORDINGLY, SOME OF THE
ABOVE DISCLAIMERS OF WARRANTIES MAY NOT APPLY TO YOU BUT OTHERS REMAIN IN EFFECT.
</v-card-text>
<v-card-text>
You understand that your use of the Utilities is entirely at your own risk. You assume all risks associated with
using the Utilities, and digital assets and decentralized systems generally, including but not limited to, that
digital assets are highly volatile; you may not have ready access to assets; and you may lose some or all of your
tokens or other assets, including with respect to an Interaction or the Vault. You agree that you will have no
recourse against Dexorder for any losses due to your use of the Utilities. For example, these losses may arise
from or relate to: (i) lost funds; (ii) server failure or data loss; (iii) corrupted digital wallet files; (iv) unauthorized
access; (v) errors, mistakes, or inaccuracies; or (vi) third-party activities.
</v-card-text>
<v-card-title>12. Assumption of Risk.</v-card-title>
<v-card-text>You accept, acknowledge and assume the following risks:</v-card-text>
<v-card-text>
(a) You are solely responsible for determining what, if any, Taxes apply to your transactions
through the Utilities. Neither Dexorder nor any Dexorder affiliates are responsible for determining the Taxes
that apply to such transactions.
</v-card-text>
<v-card-text>
(b) A lack of use or public interest in the creation and development of distributed
ecosystems could negatively impact the development of those ecosystems and related applications, and could
therefore also negatively impact the potential utility or value of certain digital assets.
</v-card-text>
<v-card-text>
(c) By accessing and using the Utilities, you represent that you understand the inherent
risks associated with using cryptographic and blockchain-based systems, and that you have a working knowledge
of the usage and intricacies of tokens such as, bitcoin (BTC), ether (ETH), and other digital tokens such as those
following the Ethereum Token Standard (ERC-20). You further understand that the markets for tokens can be
highly volatile due to factors including (but not limited to) adoption, speculation, technology, security, and
regulation. You acknowledge that the cost and speed of transacting with cryptographic and blockchain-based
systems are variable and may increase at any time. Accordingly, you understand and agree to assume full
responsibility for all of the risks of accessing and using and engaging with the Utilities.
</v-card-text>
<v-card-title>13. Indemnity</v-card-title>
<v-card-text>
You will indemnify, defend (at Dexorders option) and hold Dexorder and its affiliates and their respective officers,
directors, employees and agents, harmless from and against any claims, disputes, demands, liabilities, damages, losses,
and costs and expenses, including, without limitation, reasonable legal and accounting fees arising out of or in any way
connected with: (a) your access to or use of the Utilities, (b) Interactions and the Vault, (c) your violation of these
Terms, or (d) your negligence, willful misconduct, fraud, or violation of Applicable Laws. You may not settle or
otherwise compromise any claim subject to this Section without Dexorders prior written approval.
</v-card-text>
<v-card-title>14. Limitation of Liability</v-card-title>
<v-card-text>
(a) TO THE MAXIMUM EXTENT PERMITTED BY LAW, NEITHER DEXORDER NOR ITS SERVICE
PROVIDERS INVOLVED IN CREATING, PRODUCING, OR DELIVERING THE UTILITIES WILL BE LIABLE FOR ANY
INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES, OR DAMAGES FOR LOST PROFITS, LOST
REVENUES, LOST SAVINGS, LOST BUSINESS OPPORTUNITY, LOSS OF DATA OR GOODWILL, SERVICE
INTERRUPTION, COMPUTER DAMAGE OR SYSTEM FAILURE OR THE COST OF SUBSTITUTE SERVICES OF ANY KIND
ARISING OUT OF OR IN CONNECTION WITH THESE TERMS OR FROM THE USE OF OR INABILITY TO USE THE
UTILITIES, WHETHER BASED ON WARRANTY, CONTRACT, TORT (INCLUDING NEGLIGENCE), PRODUCT LIABILITY
OR ANY OTHER LEGAL THEORY, AND WHETHER OR NOT DEXORDER OR ITS SERVICE PROVIDERS HAS BEEN
INFORMED OF THE POSSIBILITY OF SUCH DAMAGE, EVEN IF A LIMITED REMEDY SET FORTH HEREIN IS FOUND TO
HAVE FAILED OF ITS ESSENTIAL PURPOSE.
</v-card-text>
<v-card-text>
(b) TO THE MAXIMUM EXTENT PERMITTED BY THE LAW, IN NO EVENT WILL DEXORDERS
TOTAL LIABILITY ARISING OUT OF OR IN CONNECTION WITH THESE TERMS OR FROM THE USE OF OR INABILITY
TO USE THE UTILITIES EXCEED THE TOTAL FEES YOU HAVE PAID OR ARE PAYABLE BY YOU TO DEXORDER FOR USE
OF THE UTILITIES (EXCLUDING GAS FEES), OR ONE HUNDRED DOLLARS ($100) IF YOU HAVE NOT HAD ANY
PAYMENT OBLIGATIONS TO DEXORDER, AS APPLICABLE.
</v-card-text>
<v-card-text>
(c) THE EXCLUSIONS AND LIMITATIONS OF DAMAGES SET FORTH ABOVE ARE
FUNDAMENTAL ELEMENTS OF THE BASIS OF THE BARGAIN BETWEEN DEXORDER AND YOU.
</v-card-text>
<v-card-title>15. Governing Law and Forum Choice</v-card-title>
<v-card-text>
These Terms will be governed by and construed in accordance with the laws of the British Virgin Islands without regard
to its conflict of laws provisions.
</v-card-text>
<v-card-title>16. Dispute Resolution</v-card-title>
<v-card-text>
(a) <u>Mandatory Arbitration of Disputes</u>. We each agree that any dispute, claim or
controversy arising out of or relating to these Terms or the breach, termination, enforcement, interpretation or
validity thereof or the use of the Utilities (collectively, <b>Disputes</b>) will be resolved <b>solely by binding, individual
arbitration and not in a class, representative or consolidated action or proceeding.</b> You and Dexorder agree
that the Cayman Islands Arbitration Law governs the interpretation and enforcement of these Terms, and that
you and Dexorder are each waiving the right to a trial by jury or to participate in a class action. This arbitration
provision shall survive termination of these Terms.
</v-card-text>
<v-card-text>
(b) <u>Exceptions</u>. As limited exceptions to Section 16.(a) above: (i) each party may seek to
resolve a Dispute in small claims court if it qualifies; and (ii) each party retains the right to seek injunctive or
other equitable relief from a court to prevent (or enjoin) the infringement or misappropriation of our intellectual
property rights.
</v-card-text>
<v-card-text>
(c) <u>Conducting Arbitration and Arbitration Rules</u>. The arbitration will be conducted by the
Cayman International Mediation &amp; Arbitration Centre (CI-MAC) in accordance with its arbitration rules in force
at the time of the dispute (<b>CI-MAC Rules</b>), except as modified by these Terms. The CI-MAC Rules are available
at <a href="https://www.caymanarbitration.com/arbitrationrules2023">https://www.caymanarbitration.com/arbitrationrules2023</a>. A party who wishes to start arbitration must
submit a written request for arbitration to CI-MAC and give notice to the other party as specified in the CI-MAC
Rules. CI-MAC provides instructions on submitting a request for arbitration under Section 3 (Request for
arbitration) of the CI-MAC Rules.
</v-card-text>
<v-card-text>
Any arbitration hearings will take place in the county (or parish) where you live, unless the parties agree to a
different location. The parties agree that the arbitrator shall have exclusive authority to decide all issues relating
to the interpretation, applicability, enforceability and scope of this arbitration agreement.
</v-card-text>
<v-card-text>
(d) <u>Arbitration Costs</u>. Payment of all filing, administration and arbitrator fees will be
governed by the JAMS Rules, and we wont seek to recover the administration and arbitrator fees we are
responsible for paying, unless the arbitrator finds your Dispute frivolous. If we prevail in arbitration well pay all
of our attorneys fees and costs and wont seek to recover them from you. If you prevail in arbitration you will
be entitled to an award of attorneys fees and expenses to the extent provided under Applicable Law.
</v-card-text>
<v-card-text>
(e) <u>Injunctive and Declaratory Relief</u>. Except as provided in Section 16.(b) above, the
arbitrator shall determine all issues of liability on the merits of any claim asserted by either party and may award
declaratory or injunctive relief only in favor of the individual party seeking relief and only to the extent
necessary to provide relief warranted by that partys individual claim. To the extent that you or we prevail on a
claim and seek public injunctive relief (that is, injunctive relief that has the primary purpose and effect of
prohibiting unlawful acts that threaten future injury to the public), the entitlement to and extent of such relief
must be litigated in a civil court of competent jurisdiction and not in arbitration. The parties agree that litigation
of any issues of public injunctive relief shall be stayed pending the outcome of the merits of any individual
claims in arbitration.
</v-card-text>
<v-card-text>
(f) <u>Class Action Waiver</u>. <b>YOU AND DEXORDER AGREE THAT EACH MAY BRING CLAIMS
AGAINST THE OTHER ONLY IN YOUR OR ITS INDIVIDUAL CAPACITY, AND NOT AS A PLAINTIFF OR CLASS
MEMBER IN ANY PURPORTED CLASS OR REPRESENTATIVE PROCEEDING.</b> Further, if the parties Dispute is
resolved through arbitration, the arbitrator may not consolidate another persons claims with your claims, and
may not otherwise preside over any form of a representative or class proceeding. If this specific provision is
found to be unenforceable, then the entirety of this Dispute Resolution section shall be null and void.
</v-card-text>
<v-card-text>
(g) <u>Severability</u>. With the exception of any of the provisions in Section 16.(f) of these Terms
(<b>Class Action Waiver</b>), if an arbitrator or court of competent jurisdiction decides that any part of these Terms
is invalid or unenforceable, the other parts of these Terms will still apply.
</v-card-text>
<v-card-title>17. General Terms</v-card-title>
<v-card-text>
(a) <u>Reservation of Rights</u>. Dexorder and its licensors exclusively own all right, title and
interest in and to the Dexorder Service, including all associated intellectual property rights. You acknowledge
that the Dexorder Service is protected by copyright, trademark, and other laws of the United States and foreign
countries. You agree not to remove, alter or obscure any copyright, trademark, service mark or other
proprietary rights notices incorporated in or accompanying the Dexorder Service.
</v-card-text>
<v-card-text>
(b) <u>Entire Agreement</u>. These Terms, including any addendum terms, constitute the entire
and exclusive understanding and agreement between Dexorder and you regarding the Dexorder Service, and
these Terms supersede and replace all prior oral or written understandings or agreements between Dexorder
and you regarding the Dexorder Service. If any provision of these Terms is held invalid or unenforceable by an
arbitrator or a court of competent jurisdiction, that provision will be enforced to the maximum extent
permissible and the other provisions of these Terms will remain in full force and effect. Except where provided
by Applicable Law in your jurisdiction, you may not assign or transfer these Terms, by operation of law or
otherwise, without Dexorders prior written consent. Any attempt by you to assign or transfer these Terms
absent our consent or your statutory right, will be null. Dexorder may freely assign or transfer these Terms
without restriction. Subject to the foregoing, these Terms will bind and inure to the benefit of the parties, their
successors and permitted assigns.
</v-card-text>
<v-card-text>
(c) <u>Notices</u>. Any notices or other communications provided by Dexorder under these Terms
will be given: (i) via email; or (ii) by posting to the Dexorder Service. For notices made by email, the date of
receipt will be deemed the date on which such notice is transmitted.
</v-card-text>
<v-card-text>
(d) <u>Waiver of Rights</u>. Dexorders failure to enforce any right or provision of these Terms will
not be considered a waiver of such right or provision. The waiver of any such right or provision will be effective
only if in writing and signed by a duly authorized representative of Dexorder. Except as expressly set forth in
these Terms, the exercise by either party of any of its remedies under these Terms will be without prejudice to
its other remedies under these Terms or otherwise.
</v-card-text>
<v-card-title>18. Contact Information</v-card-title>
<v-card-text>
If you have any questions about these Terms or the Dexorder Service, please contact Dexorder
at <a href="mailto:legal@dexorder.trade">legal@dexorder.trade</a> or <a href="mailto:support@dexorder.trade">support@dexorder.trade</a>.
</v-card-text>
<v-card-actions class="justify-space-around mb-8">
<v-btn variant="elevated" @click="decline" :disabled="!acceptable" prepend-icon="mdi-cancel">Decline</v-btn>
<v-btn variant="elevated" color="primary" @click="accept" :disabled="!acceptable" prepend-icon="mdi-check">Accept</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script setup>
// tos = {
// version: 1, // Number
// date: 12345678, // Unix timestamp
// ip: '123.231.132.213', // IP when client accepted
// country: 'AD', // https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 Country where the IP is located
// }
import {usePrefStore} from "@/store/store.js";
import {computed, ref, watch} from "vue";
import {timestamp} from "@/misc.js";
// INCREMENT THIS WHEN CHANGING THE TOS
const CURRENT_VERSION=1
const prefs = usePrefStore()
const ok = computed(()=>{
console.log('check ToS', prefs.acceptedTos)
return prefs.acceptedTos!==null&&prefs.acceptedTos.version===CURRENT_VERSION
})
const show = computed(()=>!ok.value)
const acceptable = computed(()=>!inFlight.value)
const inFlight = ref(false)
watch(ok, (newVal, oldVal)=> {console.log('check ToS');if(newVal!==oldVal) console.log('ToS accepted', prefs.acceptedTos.version, prefs.acceptedTos.date) })
function accept() {
prefs.acceptedTos = {
version: CURRENT_VERSION,
date: timestamp(),
// todo IP check
// ip: '127.0.0.1',
// country: 'AD'
}
inFlight.value = false
}
function decline() {
// bounce to top-level non-app domain
window.location.href = 'https://dexorder.trade'
}
</script>
<style scoped lang="scss">
.ii {
margin-left: 2em;
}
</style>

View File

@@ -7,10 +7,10 @@
<script setup>
// noinspection ES6UnusedImports
import {routeInverted, SingletonCoroutine, vAutoSelect} from "@/misc.js";
import {SingletonCoroutine, vAutoSelect} from "@/misc.js";
import Order from "@/components/Order.vue";
import LimitPrice from "@/components/LimitPrice.vue";
import {timesliceTranches, applyLimitOld} from "@/orderbuild.js";
import {applyLimitOld, timesliceTranches} from "@/orderbuild.js";
import Tranches from "@/components/Tranches.vue";
import {useOrderStore} from "@/store/store.js";

View File

@@ -81,13 +81,6 @@ function updateValue(v) {
}
</script>
<script>
import {ethers} from "ethers";
import {useStore} from "@/store/store.js";
const s = useStore()
</script>
<style scoped lang="scss">
@use "src/styles/vars" as *;

View File

@@ -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>

View File

@@ -36,10 +36,10 @@ const showDialog = ref(false)
const upgradeResult = ref(null)
detectUpgrade().then((version)=>{
if (version===0) {
console.log('Vault is the latest version')
if (version===null) {
console.log('detectUpgrade failed')
}
else {
else if (s.version<version) {
upgradeVersion.value = version
console.log(`Vault upgrade available to version ${version}`)
}

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -75,8 +75,7 @@ import {useTheme} from "vuetify";
import RowBar from "@/components/chart/RowBar.vue";
import ColorBand from "@/components/chart/ColorBand.vue";
import Color from "color";
import {Exchange, newOrder} from "@/blockchain/orderlib.js";
import {lookupSymbol} from "@/charts/datafeed.js";
import {newOrder} from "@/blockchain/orderlib.js";
const props = defineProps(['order'])
const s = useStore()

View File

@@ -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()
}
}

View File

@@ -42,7 +42,6 @@
import {builderDefaults, DEFAULT_SLIPPAGE, MIN_EXECUTION_TIME, useChartOrderStore} from "@/orderbuild.js";
import {allocationText, VLine} from "@/charts/shape.js";
import {sideColor} from "@/misc.js";
import {useTheme} from "vuetify";
import {useOrderStore, useStore} from "@/store/store.js";
import {DISTANT_FUTURE, MAX_FRACTION, newTranche} from "@/blockchain/orderlib.js";
import RungBuilder from "@/components/chart/RungBuilder.vue";
@@ -54,7 +53,6 @@ import {DateTime} from "luxon";
const s = useStore()
const os = useOrderStore()
const co = useChartOrderStore()
const theme = useTheme().current
const props = defineProps(['order', 'builder'])
const emit = defineEmits(['update:builder'])

View File

@@ -112,7 +112,6 @@ function computeDefaultColor() {
}
const defaultColor = computeDefaultColor()
const color = computed(()=>props.builder.color ? props.builder.color : defaultColor)
// Fields must be defined in order to be reactive
@@ -399,7 +398,7 @@ function dirtyLine(a, b) {
return result
}
const name = computed(()=>(props.builder.breakout?'Breakout':'Limit')+' Diagonal'+(weights.value.length>1?'s':''))
const name = computed(()=>props.builder.breakout?'Breakout':'Limit')
const description = computed(()=>{
const buy = props.order.buy

View File

@@ -1,5 +1,5 @@
<template>
<rung-builder :name="(builder.breakout?'Breakout':'Limit')+(prices.length>1?' Ladder':'')"
<rung-builder :name="(builder.breakout?'Breakout':'Limit')"
:description="description"
:order="order" :builder="builder"
v-model="priceEndpoints" :mode="0" :flip="flipped"

View File

@@ -4,15 +4,16 @@
<div style="min-width: 4em; font-size: larger" :style="colorStyle"
class="d-flex flex-column align-self-start ml-2">
<div class="flex-row align-items-center">
<v-btn variant="outlined" @click="props.builder.breakout=!props.builder.breakout">{{ name }}</v-btn>
<div class="description">{{description}}</div>
<v-btn variant="outlined" style="width: 8em"
@click="props.builder.breakout=!props.builder.breakout">{{ name }}</v-btn>
<div class="description w-100 text-center">{{description}}</div>
</div>
<v-text-field type="number" v-model="rungs"
density="compact" hide-details class="mx-1 my-2" variant="outlined"
label="Rungs"
:color="color" :base-color="color" min="1" :max="MAX_RUNGS"
:disabled="rungsDisabled"
style="width: 4.5em;"
style="width: 6.6em;"
/>
</div>
@@ -46,11 +47,13 @@ import {cancelDrawing} from "@/charts/chart.js";
import {
devectorize,
vectorAdd,
vectorDiv, vectorEquals,
vectorDiv,
vectorEquals,
vectorIsNull,
vectorIsZero,
vectorize,
vectorMul, vectorNeg,
vectorMul,
vectorNeg,
vectorSub
} from "@/vector.js";
@@ -90,6 +93,13 @@ watchEffect(()=>{
// console.log('valid?', prev, props.builder.valid, rungs, valueA.value, valueB.value)
})
let lastBuy = null
watchEffect(()=>{
if (props.order.buy!==lastBuy) {
lastBuy = props.order.buy
props.builder.color=computeDefaultColor()
}
})
function setEndpoints(a, b) {
// console.log('rb setting endpoints', devectorize(a), devectorize(b))
@@ -322,9 +332,8 @@ function makeModel(index) {
amount: props.order.amount * alloc,
amountSymbol: amountSymbol.value,
textLocation: above ? 'above' : 'below',
extraText: !props.builder.breakout ? ' ' :
// (above ? '↑ Breakout ↑' : '↓ Breakout ↓')
(above ? '▲ Breakout ▲' : '▼ Breakout ▼')
breakout: props.builder.breakout,
extraText: null,
}
setModelValue(result, values.value[index])
return result

View File

@@ -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')
}

View File

@@ -13,7 +13,6 @@ import {useRoute} from "vue-router";
import {nav} from "/src/misc.js"
const props = defineProps(['icon', 'route', 'tooltip'])
console.log('toolbar button props', props.route)
const router = useRoute();
const isCurrent = computed(() => router.name === props.route)
</script>

View File

@@ -4,7 +4,6 @@
<logo class="logo-xl"/>
</v-card-item>
<v-card-subtitle class="pl-8 mx-auto">Advanced DeFi Orders</v-card-subtitle>
<social class="ml-12"/>
<v-card-text>
Dexorder powers up your favorite DeFi exchange with advanced order types!
</v-card-text>
@@ -15,11 +14,12 @@
Supports Uniswap v3 <beta/>
</v-list-item>
<v-list-item><v-icon icon="mdi-ray-vertex" class="mr-2"/> Limit Orders <beta/></v-list-item>
<v-list-item><v-icon icon="mdi-clock-outline" class="mr-2"/> DCA and TWAP Orders <beta/></v-list-item>
<v-list-item><v-icon icon="mdi-vector-line" class="mr-2"/> Diagonal Limit Orders <beta/></v-list-item>
<v-list-item><v-icon icon="mdi-chart-timeline-variant-shimmer" class="mr-2"/> Stop Loss / Take Profit <soon/></v-list-item>
<v-list-item><v-icon icon="mdi-clock-outline" class="mr-2"/> DCA and TWAP Orders <beta/></v-list-item>
<v-list-item><v-icon icon="mdi-chart-line" class="mr-2"/> Breakout Orders <beta/></v-list-item>
<v-list-item><v-icon icon="mdi-plus-minus" class="mr-2"/> Stop Loss / Take Profit <soon/></v-list-item>
<v-list-item><v-icon icon="mdi-format-list-checks" class="mr-2"/> One-Cancels-the-Other (OCO) Groups <soon/></v-list-item>
<v-list-item><v-icon icon="mdi-cancel" class="mr-2"/> Single-transaction Cancel All </v-list-item>
<v-list-item><v-icon icon="mdi-cancel" class="mr-2"/> Single-transaction Cancel All <beta/></v-list-item>
<v-list-item><v-icon icon="mdi-alert-outline" class="mr-2"/> Single-transaction Sell Everything <soon/></v-list-item>
<v-list-item><v-icon icon="mdi-shimmer" class="mr-2"/> Custom Complex Orders <soon/></v-list-item>
</v-list>
@@ -28,17 +28,20 @@
<app-btn/>
<v-btn prepend-icon="mdi-information-outline" variant="flat" text="How It Works" @click="nav('HowItWorks')"/>
</div>
<div class="w-100 d-flex justify-center my-6 actions">
<social class="ml-12"/>
</div>
</v-card>
</template>
<script setup>
import beta from "@/components/Beta.vue";
import Soon from "@/components/Soon.vue";
import HowItWorks from "@/corp/HowItWorks.vue";
import UniswapLogo from "@/corp/UniswapLogo.vue";
import Logo from "@/components/Logo.vue";
import {nav} from "@/misc.js";
import AppBtn from "@/corp/AppBtn.vue";
import Social from "@/components/Social.vue";
</script>

View File

@@ -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>

View File

@@ -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)
@@ -187,7 +188,7 @@ const colorRanges = {
sell: ['#CC0033', '#CCCC33'],
}
export function sideColor(buy, index) {
export function sideColor(buy, index=0) {
const range = buy ? colorRanges.buy : colorRanges.sell
const a = new Color(range[0]).rgb()
const b = new Color(range[1]).rgb()
@@ -232,7 +233,7 @@ export function intervalToSeconds(interval) {
: interval.endsWith('S') ? 1
: 60 // if no unit char, then it's minutes
const result = parseInt(/\d+/.exec(interval)[0]) * unit
console.log('intervalToSeconds', interval, result)
// console.log('intervalToSeconds', interval, result)
return result
}
@@ -252,4 +253,9 @@ export function computeInterceptSlope(time0, price0, time1, price1) {
const slope = (price1 - price0) / (t1 - t0)
const intercept = price1 - slope * t1
return [intercept, slope]
}
}
export function defined(v) {
return v !== undefined && v !== null
}

View File

@@ -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 +

View File

@@ -7,14 +7,14 @@
// Plugins
import { loadFonts } from './webfontloader'
import vuetify from './vuetify'
import pinia from '../store/pinia.js'
import {pinia} from '../store/pinia.js'
import router from '../router'
import vsp from "vue-scroll-picker";
import "vue-scroll-picker/lib/style.css";
export function registerPlugins (app) {
loadFonts()
loadFonts().catch((e)=>console.error('Could not load fonts!',e))
app
.use(vuetify)
.use(router)

View File

@@ -17,6 +17,16 @@ socket.on('disconnect', () => {
useStore().connected = false
})
socket.on('approvedRegion', (approved) => {
console.log('approved region', approved)
useStore().regionApproved = approved
})
socket.on('approvedWallet', (approved) => {
console.log('approved wallet', approved)
useStore().walletApproved = approved
})
socket.on('p', async (chainId, pool, price) => {
console.log('pool price from message', chainId, pool, price)
const s = useStore()
@@ -53,7 +63,7 @@ socket.on('vaults', (chainId, owner, vaults)=>{
s.vaults = vaults
if( vaults.length ) {
const vault = vaults[0]
flushOrders(vault)
flushOrders(chainId, owner, 0, vault)
}
}
})
@@ -95,7 +105,7 @@ socket.on( 'of', (chainId, vault, orderIndex, filled)=>{
}
const status = s.orders[vault][orderIndex]
console.log('apply fills', status, filled)
// console.log('apply fills', status, filled)
let orderIn = 0n
let orderOut = 0n
@@ -107,7 +117,10 @@ socket.on( 'of', (chainId, vault, orderIndex, filled)=>{
const numOld = ts.fills.length;
for (let i=0; i<fills.length; i++) {
const fill = fills[i]
const [tx, time, fi, fo, fee] = fill
let [tx, time, fi, fo, fee] = fill
fi = BigInt(fi)
fo = BigInt(fo)
fee = BigInt(fee)
filledIn += fi
filledOut += fo
if (i<=numOld) {
@@ -124,8 +137,9 @@ socket.on( 'of', (chainId, vault, orderIndex, filled)=>{
orderIn += filledIn
orderOut += filledOut
}
status[7] = orderIn.toString()
status[8] = orderOut.toString()
status.filledIn = orderIn
status.filledOut = orderOut
status.filled = status.order.amountIsInput ? orderIn : orderOut
console.log('apply fills completed', status)
// console.log('apply fills completed', status)
})

View File

@@ -1,4 +1,6 @@
// Utilities
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
export default createPinia()
export const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

View File

@@ -33,7 +33,7 @@ function timestamp() {
const UNKNOWN_PROVIDER = {}
const REQUIRE_AUTH = import.meta.env.VITE_REQUIRE_AUTH !== 'NOAUTH';
const REQUIRE_APPROVAL = import.meta.env.VITE_REQUIRE_APPROVAL !== 'NO';
export const useStore = defineStore('app', ()=> {
const clock = ref(timestamp()) // the clock ticks infrequently enough to be mostly stable for user display
@@ -44,7 +44,8 @@ export const useStore = defineStore('app', ()=> {
const theme = ref('light') // todo 'dark'
const connected = ref(true) // we assume a connection will succeed until socket.io complains otherwise
const allowed = ref(!REQUIRE_AUTH)
const regionApproved = ref(REQUIRE_APPROVAL?null:true)
const walletApproved = ref(REQUIRE_APPROVAL?null:true)
const _chainId = ref(Number(Object.keys(versionMeta.chainInfo)[0]))
const _chainInfo = ref(versionMeta.chainInfo)
@@ -133,11 +134,12 @@ export const useStore = defineStore('app', ()=> {
return {
connected,
allowed, nav, chainId, chainInfo, chain, provider, providerRef, vaultInitCodeHash, account, vaults, vaultVersions,
nav, chainId, chainInfo, chain, provider, providerRef, vaultInitCodeHash, account, vaults, vaultVersions,
transactionSenders, errors, extraTokens, poolPrices, vaultBalances, orders, vault, version, upgrade, vaultOrders,
tokens, factory, helper, theme,
mockenv, mockCoins,
removeTransactionSender, error, closeError, addToken, clock, timeZone, balances,
regionApproved, walletApproved,
}
})
@@ -197,10 +199,14 @@ export const useOrderStore = defineStore('order', ()=> {
})
export const usePrefStore = defineStore('prefs', ()=> {
// user preferences
const inverted = ref({})
return {inverted,}
export const usePrefStore = defineStore({
id: 'pref',
persist: true,
state: ()=> {
// user preferences
const inverted = ref({})
const acceptedTos = ref(null)
return {inverted, acceptedTos,}
},
})

1196
yarn.lock

File diff suppressed because it is too large Load Diff