order placement works, including automatic vault creation
This commit is contained in:
@@ -43,32 +43,16 @@ export const erc20Abi = [
|
|||||||
'event Approval(address indexed,address indexed,uint256)',
|
'event Approval(address indexed,address indexed,uint256)',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const Route = '(uint8,uint24)'
|
||||||
|
const Constraint = '(uint8,bytes)'
|
||||||
|
const Tranche = `(uint64,${Constraint}[])`
|
||||||
|
const SwapOrder = `(address,address,${Route},uint256,bool,bool,uint64,${Tranche}[])`
|
||||||
|
|
||||||
const TimedOrderSpec = '(' +
|
export const vaultAbi = [
|
||||||
'address tokenIn,' +
|
'function withdraw(uint256) public',
|
||||||
'address tokenOut,' +
|
'function withdrawTo(address payable,uint256) public',
|
||||||
'uint24 fee,' +
|
'function withdraw(address,uint256) public',
|
||||||
'uint32 deadline,' +
|
'function withdrawTo(address,address,uint256) public',
|
||||||
'uint32 leeway,' +
|
`function placeOrder(${SwapOrder}) public`,
|
||||||
'uint160 minSqrtPriceX96,' +
|
`function placeOrders(${SwapOrder}[],uint8) public`,
|
||||||
'uint160 maxSqrtPriceX96,' +
|
|
||||||
'uint8 numTranches,' +
|
|
||||||
'uint256 amount,' +
|
|
||||||
'bool amountIsInput' +
|
|
||||||
')'
|
|
||||||
|
|
||||||
export const timedOrderAbi = [
|
|
||||||
'event TimedOrderCreated (address owner, uint64 index, Spec spec)',
|
|
||||||
'event TimedOrderFilled (address owner, uint64 index, uint256 amountIn, uint256 amountOut)',
|
|
||||||
'event TimedOrderCompleted (address owner, uint64 index)',
|
|
||||||
'event TimedOrderError (address owner, uint64 index, string reason)',
|
|
||||||
`timedOrder(${TimedOrderSpec}) returns (uint64 index)`,
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
export const abi = {
|
|
||||||
'ERC20': erc20Abi,
|
|
||||||
'TimedOrder': timedOrderAbi,
|
|
||||||
'QueryHelper': queryHelperAbi,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,48 @@
|
|||||||
import {ethers} from "ethers";
|
import {ethers} from "ethers";
|
||||||
import {factoryAbi, queryHelperAbi} from "@/blockchain/abi.js";
|
import {factoryAbi, queryHelperAbi, vaultAbi} from "@/blockchain/abi.js";
|
||||||
import {useStore} from "@/store/store.js";
|
import {useStore} from "@/store/store.js";
|
||||||
import {provider} from "@/blockchain/wallet.js";
|
import {provider} from "@/blockchain/wallet.js";
|
||||||
|
|
||||||
|
|
||||||
|
export function vaultAddress( owner, num ) {
|
||||||
|
const s = useStore()
|
||||||
|
if( s.vaultInitCodeHash === null || s.factory === null )
|
||||||
|
return null
|
||||||
|
const abiCoder = ethers.AbiCoder.defaultAbiCoder();
|
||||||
|
console.log('vaultAddress owner', owner)
|
||||||
|
const salt = ethers.keccak256(abiCoder.encode(['address','uint8'],[owner,num]))
|
||||||
|
const result = ethers.getCreate2Address(s.factory, salt, s.vaultInitCodeHash)
|
||||||
|
console.log('vaultAddress', result, s.factory, salt, s.vaultInitCodeHash)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function contractOrNull(addr,abi,provider) {
|
||||||
|
try {
|
||||||
|
return new ethers.Contract(addr,abi,provider)
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function factoryContract() {
|
export async function factoryContract() {
|
||||||
const s = useStore()
|
const s = useStore()
|
||||||
return new ethers.Contract(s.helper, factoryAbi, provider)
|
return contractOrNull(s.factory, factoryAbi, provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function queryHelperContract() {
|
export async function queryHelperContract() {
|
||||||
const s = useStore()
|
const s = useStore()
|
||||||
return new ethers.Contract(s.helper, queryHelperAbi, provider)
|
return contractOrNull(s.helper, queryHelperAbi, provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function poolContract(addr) {
|
export async function poolContract(addr) {
|
||||||
const s = useStore()
|
return contractOrNull(addr, poolAbi, provider)
|
||||||
return new ethers.Contract(addr, poolAbi, provider)
|
}
|
||||||
|
|
||||||
|
export async function vaultContract(num, signer) {
|
||||||
|
const s = useStore()
|
||||||
|
if( num >= s.vaults.length )
|
||||||
|
return null
|
||||||
|
return contractOrNull(s.vaults[num], vaultAbi, signer)
|
||||||
}
|
}
|
||||||
|
|||||||
114
src/blockchain/orderlib.js
Normal file
114
src/blockchain/orderlib.js
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
|
||||||
|
import {uint32max, uint64max} from "@/misc.js";
|
||||||
|
import {ethers} from "ethers";
|
||||||
|
|
||||||
|
export const NO_CHAIN = uint64max;
|
||||||
|
export const NO_OCO = uint64max;
|
||||||
|
|
||||||
|
// struct SwapOrder {
|
||||||
|
// address tokenIn;
|
||||||
|
// address tokenOut;
|
||||||
|
// Route route;
|
||||||
|
// uint256 amount;
|
||||||
|
// bool amountIsInput;
|
||||||
|
// bool outputDirectlyToOwner;
|
||||||
|
// uint64 chainOrder; // use NO_CHAIN for no chaining. chainOrder index must be < than this order's index for safety (written first) and chainOrder state must be Template
|
||||||
|
// Tranche[] tranches;
|
||||||
|
// }
|
||||||
|
// struct Route {
|
||||||
|
// Exchange exchange;
|
||||||
|
// uint24 fee;
|
||||||
|
// }
|
||||||
|
export function newOrder(tokenIn, tokenOut, exchange, fee, amount, amountIsInput, tranches,
|
||||||
|
outputToOwner=false, chainOrder=NO_CHAIN) {
|
||||||
|
if(!tranches)
|
||||||
|
tranches = [newTranche(1,[])] // todo this is just a swap: issue warning?
|
||||||
|
return [
|
||||||
|
tokenIn, tokenOut, [exchange,fee], amount, amountIsInput, outputToOwner, chainOrder, tranches
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct Tranche {
|
||||||
|
// uint64 fraction; // 18-decimal fraction of the order amount which is available to this tranche. must be <= 1
|
||||||
|
// Constraint[] constraints;
|
||||||
|
// }
|
||||||
|
export function newTranche(amountRatio, constraints) {
|
||||||
|
return [
|
||||||
|
BigInt(Math.ceil(amountRatio * 10**18)), // we use ceil to make sure the sum of tranche fractions doesn't round below 1
|
||||||
|
constraints
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// enum Exchange {
|
||||||
|
// UniswapV2,
|
||||||
|
// UniswapV3
|
||||||
|
// }
|
||||||
|
export const Exchange = {
|
||||||
|
UniswapV2: 0,
|
||||||
|
UniswapV3: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
// enum ConstraintMode {
|
||||||
|
// Time, // 0
|
||||||
|
// Limit, // 1
|
||||||
|
// Trailing, // 2
|
||||||
|
// Barrier, // 3
|
||||||
|
// Line // 4
|
||||||
|
// }
|
||||||
|
export const ConstraintMode = {
|
||||||
|
Time: 0,
|
||||||
|
Limit: 1,
|
||||||
|
Trailing: 2,
|
||||||
|
Barrier: 3,
|
||||||
|
Line: 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct Constraint {
|
||||||
|
// ConstraintMode mode;
|
||||||
|
// bytes constraint; // abi-encoded constraint struct
|
||||||
|
// }
|
||||||
|
|
||||||
|
function encodeConstraint( constraintMode, types, values ) {
|
||||||
|
return [constraintMode, ethers.AbiCoder.defaultAbiCoder().encode(types,values)]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const TimeMode = {
|
||||||
|
Timestamp:0,
|
||||||
|
SinceOrderStart:1,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DISTANT_PAST = 0
|
||||||
|
export const DISTANT_FUTURE = uint32max
|
||||||
|
|
||||||
|
// struct Time {
|
||||||
|
// TimeMode mode;
|
||||||
|
// uint32 time;
|
||||||
|
// }
|
||||||
|
// struct TimeConstraint {
|
||||||
|
// Time earliest;
|
||||||
|
// Time latest;
|
||||||
|
// }
|
||||||
|
export function newTimeConstraint(startMode, start, endMode, end) {
|
||||||
|
// absolute time
|
||||||
|
return encodeConstraint(
|
||||||
|
ConstraintMode.Time,
|
||||||
|
['uint8', 'uint32', 'uint8', 'uint32'],
|
||||||
|
[startMode, start, endMode, end]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct PriceConstraint {
|
||||||
|
// bool isAbove;
|
||||||
|
// bool isRatio;
|
||||||
|
// uint160 valueSqrtX96;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// struct LineConstraint {
|
||||||
|
// bool isAbove;
|
||||||
|
// bool isRatio;
|
||||||
|
// uint32 time;
|
||||||
|
// uint160 valueSqrtX96;
|
||||||
|
// int160 slopeSqrtX96; // price change per second
|
||||||
|
// }
|
||||||
|
|
||||||
@@ -1,14 +1,18 @@
|
|||||||
import {ethers} from "ethers";
|
import {ethers} from "ethers";
|
||||||
import {useStore} from "@/store/store";
|
import {useStore} from "@/store/store";
|
||||||
|
import {socket} from "@/socket.js";
|
||||||
|
import {vaultContract} from "@/blockchain/contract.js";
|
||||||
|
|
||||||
export let provider = null
|
export let provider = null
|
||||||
|
|
||||||
function onChainChanged(chainId) {
|
export function onChainChanged(chainId) {
|
||||||
chainId = Number(chainId)
|
chainId = Number(chainId)
|
||||||
// console.log('chain changed', chainId)
|
// console.log('chain changed', chainId)
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
store.chainId = chainId
|
store.chainId = chainId
|
||||||
|
store.account = null
|
||||||
provider = new ethers.BrowserProvider(window.ethereum, chainId)
|
provider = new ethers.BrowserProvider(window.ethereum, chainId)
|
||||||
|
provider.listAccounts().then(onAccountsChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onAccountsChanged(accounts) {
|
function onAccountsChanged(accounts) {
|
||||||
@@ -18,8 +22,10 @@ function onAccountsChanged(accounts) {
|
|||||||
store.account = null
|
store.account = null
|
||||||
}
|
}
|
||||||
else if (accounts[0] !== store.account) {
|
else if (accounts[0] !== store.account) {
|
||||||
store.account = accounts[0]
|
store.account = accounts[0].address
|
||||||
|
flushOrders()
|
||||||
}
|
}
|
||||||
|
socket.emit('address', store.chainId, accounts[0].address)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function watchWallet() {
|
export async function watchWallet() {
|
||||||
@@ -62,4 +68,48 @@ const errorHandlingProxy = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// const wallet = new Proxy(new Wallet(), errorHandlingProxy);
|
export async function connectWallet() {
|
||||||
|
return provider.getSigner()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function pendOrder(order) {
|
||||||
|
console.log('order', order)
|
||||||
|
const s = useStore()
|
||||||
|
s.pendingOrders.push(order)
|
||||||
|
const signer = await connectWallet()
|
||||||
|
if (!s.vaults.length)
|
||||||
|
socket.emit('ensureVault', s.chainId, await signer.getAddress(), 0)
|
||||||
|
else
|
||||||
|
flushOrders()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function flushOrders() {
|
||||||
|
// noinspection JSIgnoredPromiseFromCall
|
||||||
|
asyncFlushOrders()
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function asyncFlushOrders() {
|
||||||
|
const s = useStore()
|
||||||
|
const orders = s.pendingOrders
|
||||||
|
if(!orders.length || !s.account)
|
||||||
|
return
|
||||||
|
const contract = await vaultContract(0, await provider.getSigner())
|
||||||
|
if( !contract )
|
||||||
|
return
|
||||||
|
const proms = []
|
||||||
|
for (const order of orders)
|
||||||
|
proms.push(contract.placeOrder(order))
|
||||||
|
s.pendingOrders = []
|
||||||
|
const txs = await Promise.all(proms)
|
||||||
|
for( const tx of txs )
|
||||||
|
console.log('placed order', tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.on('vaults', (vaults)=>{
|
||||||
|
const s = useStore()
|
||||||
|
console.log('vaults', vaults)
|
||||||
|
s.vaults = vaults
|
||||||
|
flushOrders()
|
||||||
|
})
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
<NeedsQueryHelper>
|
<NeedsQueryHelper>
|
||||||
<PhoneCard>
|
<PhoneCard>
|
||||||
<v-card-title class="big">DCA / TWAP</v-card-title>
|
<v-card-title class="big">DCA / TWAP</v-card-title>
|
||||||
<v-card-subtitle>Split order across time</v-card-subtitle>
|
<v-card-subtitle>Multiple tranches over a time range</v-card-subtitle>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
|
|
||||||
<token-choice v-model="tokenA" class="token-choice mb-1">
|
<token-choice v-model="tokenA" class="token-choice mb-1">
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<v-btn :text="buy ? 'Buy' : 'Sell'" :color="buy ? 'green' : 'red'"
|
<v-btn :text="buy ? 'Buy' : 'Sell'" :color="buy ? 'green' : 'red'"
|
||||||
@@ -35,15 +34,15 @@
|
|||||||
<v-text-field label='Amount' type="number" step="1" variant="outlined" aria-valuemin="0" min="0"
|
<v-text-field label='Amount' type="number" step="1" variant="outlined" aria-valuemin="0" min="0"
|
||||||
v-model="amount" :rules="[validateRequired,validateAmount]" v-auto-select>
|
v-model="amount" :rules="[validateRequired,validateAmount]" v-auto-select>
|
||||||
<template v-slot:append-inner>
|
<template v-slot:append-inner>
|
||||||
<v-btn @click="amountIsBase=!amountIsBase" variant="outlined" class="mr-2">
|
<v-btn @click="amountIsTokenA=!amountIsTokenA" variant="outlined" class="mr-2">
|
||||||
{{ amountIsBase ? tokenA.symbol : tokenB.symbol }}
|
{{ amountIsTokenA ? tokenA.symbol : tokenB.symbol }}
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn :text="amountIsTotal ? 'total' : 'per tranche'" variant="outlined"
|
<v-btn :text="amountIsTotal ? 'total' : 'per tranche'" variant="outlined"
|
||||||
@click="amountIsTotal=!amountIsTotal" class="total"/>
|
@click="amountIsTotal=!amountIsTotal" class="total"/>
|
||||||
</template>
|
</template>
|
||||||
</v-text-field>
|
</v-text-field>
|
||||||
<v-text-field label="Tranches" type="number" variant="outlined" aria-valuemin="1" min="1" max="255"
|
<v-text-field label="Tranches" type="number" variant="outlined" aria-valuemin="1" min="1" max="255"
|
||||||
:model-value="tranches" :rules="[validateRequired,validateTranches]" v-auto-select>
|
v-model="tranches" :rules="[validateRequired,validateTranches]" v-auto-select>
|
||||||
<!-- <template v-slot:prepend-inner>-->
|
<!-- <template v-slot:prepend-inner>-->
|
||||||
<!-- <div>{{ amountIsTotal ? 'Split into' : 'Times' }}</div>-->
|
<!-- <div>{{ amountIsTotal ? 'Split into' : 'Times' }}</div>-->
|
||||||
<!-- </template>-->
|
<!-- </template>-->
|
||||||
@@ -60,6 +59,7 @@
|
|||||||
<v-btn variant="outlined" :text="timeUnits[timeUnitIndex]" @click="toggleTimeUnits" class="time-units"/>
|
<v-btn variant="outlined" :text="timeUnits[timeUnitIndex]" @click="toggleTimeUnits" class="time-units"/>
|
||||||
</template>
|
</template>
|
||||||
</v-text-field>
|
</v-text-field>
|
||||||
|
<!--
|
||||||
<v-text-field v-model="limitPrice" :label="(limitIsMinimum?'Minimum':'Maximum')+' Price'" type="number"
|
<v-text-field v-model="limitPrice" :label="(limitIsMinimum?'Minimum':'Maximum')+' Price'" type="number"
|
||||||
variant="outlined" aria-valuemin="0" min="0"
|
variant="outlined" aria-valuemin="0" min="0"
|
||||||
clearable :rules="[validateAmount, validateMin]" v-auto-select>
|
clearable :rules="[validateAmount, validateMin]" v-auto-select>
|
||||||
@@ -69,13 +69,14 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
</v-text-field>
|
</v-text-field>
|
||||||
|
-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions class="d-flex justify-space-evenly mb-4">
|
<v-card-actions class="d-flex justify-space-evenly mb-4">
|
||||||
<v-btn variant="outlined" color="red">Cancel</v-btn>
|
<v-btn variant="outlined" color="red">Cancel</v-btn>
|
||||||
<v-btn variant="flat" color="green" :disabled="!validOrder">Place Order</v-btn>
|
<v-btn variant="flat" color="green" :disabled="!validOrder" @click="placeOrder">Place Order</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</PhoneCard>
|
</PhoneCard>
|
||||||
</NeedsQueryHelper>
|
</NeedsQueryHelper>
|
||||||
@@ -87,13 +88,15 @@ import {computed, ref} from "vue";
|
|||||||
import TokenChoice from "@/components/TokenChoice.vue"
|
import TokenChoice from "@/components/TokenChoice.vue"
|
||||||
import PhoneCard from "@/components/PhoneCard.vue";
|
import PhoneCard from "@/components/PhoneCard.vue";
|
||||||
import {queryHelperContract} from "@/blockchain/contract.js";
|
import {queryHelperContract} from "@/blockchain/contract.js";
|
||||||
import {SingletonCoroutine} from "@/misc.js";
|
|
||||||
import NeedsQueryHelper from "@/components/NeedsQueryHelper.vue";
|
|
||||||
// noinspection ES6UnusedImports
|
// noinspection ES6UnusedImports
|
||||||
import {vAutoSelect} from "@/misc.js";
|
import {SingletonCoroutine, vAutoSelect} from "@/misc.js";
|
||||||
|
import NeedsQueryHelper from "@/components/NeedsQueryHelper.vue";
|
||||||
|
import {Exchange, newOrder, newTimeConstraint, TimeMode} from "@/blockchain/orderlib.js";
|
||||||
|
import {FixedNumber} from "ethers";
|
||||||
|
import {pendOrder} from "@/blockchain/wallet.js";
|
||||||
|
|
||||||
const s = useStore()
|
const s = useStore()
|
||||||
const buy = ref(false)
|
const buy = ref(true)
|
||||||
let _tokenA = ref(s.tokens && s.tokens.length >= 1 ? s.tokens[0] : null)
|
let _tokenA = ref(s.tokens && s.tokens.length >= 1 ? s.tokens[0] : null)
|
||||||
let _tokenB = ref(s.tokens && s.tokens.length >= 2 ? s.tokens[1] : null)
|
let _tokenB = ref(s.tokens && s.tokens.length >= 2 ? s.tokens[1] : null)
|
||||||
const tokenA = computed({
|
const tokenA = computed({
|
||||||
@@ -129,8 +132,8 @@ const quote = computed(()=>{
|
|||||||
return !token?{}:token
|
return !token?{}:token
|
||||||
})
|
})
|
||||||
const routes = ref([])
|
const routes = ref([])
|
||||||
const amount = ref(0)
|
const amount = ref(100) // todo 0
|
||||||
const amountIsBase = ref(false)
|
const amountIsTokenA = ref(false)
|
||||||
const amountIsTotal = ref(true)
|
const amountIsTotal = ref(true)
|
||||||
const tranches = ref(3)
|
const tranches = ref(3)
|
||||||
const inverted = ref(false)
|
const inverted = ref(false)
|
||||||
@@ -169,7 +172,7 @@ async function findRoute() {
|
|||||||
case 0: // UniswapV2
|
case 0: // UniswapV2
|
||||||
break
|
break
|
||||||
case 1: // UniswapV3
|
case 1: // UniswapV3
|
||||||
result = {exchange: 'UniswapV3', pool, fee,}
|
result = {exchange: Exchange.UniswapV3, pool, fee,}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,6 +237,41 @@ function validateMin(v) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function placeOrder() {
|
||||||
|
const ta = tokenA.value;
|
||||||
|
const tb = tokenB.value;
|
||||||
|
const tokenIn = buy.value ? tb.address : ta.address
|
||||||
|
const tokenOut = buy.value ? ta.address : tb.address
|
||||||
|
const route = routes.value[0];
|
||||||
|
const amountToken = amountIsTokenA ? ta : tb
|
||||||
|
const amt = FixedNumber.fromString(amount.value.toString(), {decimals: amountToken.decimals}).value
|
||||||
|
const amountIsInput = !buy.value ^ amountIsTokenA.value
|
||||||
|
|
||||||
|
// build tranches
|
||||||
|
const n = tranches.value // num tranches
|
||||||
|
const ts = []
|
||||||
|
let duration = timeUnitIndex === 0 ? interval.value * 60 : // minutes
|
||||||
|
timeUnitIndex === 1 ? interval.value * 60 * 60 : // hours
|
||||||
|
interval.value * 24 * 60 * 60; // days
|
||||||
|
let window
|
||||||
|
if (!intervalIsTotal.value) {
|
||||||
|
window = duration
|
||||||
|
duration *= n // duration is the total time for all tranches
|
||||||
|
} else {
|
||||||
|
window = duration / n
|
||||||
|
}
|
||||||
|
const ceil = 10n ** 18n % BigInt(n) ? 1n : 0n
|
||||||
|
const amtPerTranche = 10n ** 18n / BigInt(n) + ceil
|
||||||
|
duration -= 15 // subtract 15 seconds so the last tranche completes before the deadline
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
const start = Math.floor(i * (duration / n))
|
||||||
|
const end = start + window
|
||||||
|
const cs = [newTimeConstraint(TimeMode.SinceOrderStart, start, TimeMode.SinceOrderStart, end)]
|
||||||
|
ts.push([amtPerTranche, cs])
|
||||||
|
}
|
||||||
|
const order = newOrder(tokenIn, tokenOut, route.exchange, route.fee, amt, amountIsInput, ts)
|
||||||
|
await pendOrder(order)
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -38,4 +38,6 @@ export const vAutoSelect = {
|
|||||||
const input = el.querySelector('input')
|
const input = el.querySelector('input')
|
||||||
input.onfocus = () => setTimeout(() => input.select(), 0)
|
input.onfocus = () => setTimeout(() => input.select(), 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export const uint64max = 18446744073709551615n
|
||||||
|
export const uint32max = 4294967295n
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import {io} from "socket.io-client";
|
import {io} from "socket.io-client";
|
||||||
import {useStore} from "@/store/store.js";
|
import {useStore} from "@/store/store.js";
|
||||||
|
import {onChainChanged} from "@/blockchain/wallet.js";
|
||||||
|
import {ethers} from "ethers";
|
||||||
|
|
||||||
export const socket = io(import.meta.env.VITE_WS_URL || undefined, { transports: ["websocket"] })
|
export const socket = io(import.meta.env.VITE_WS_URL || undefined, { transports: ["websocket"] })
|
||||||
|
|
||||||
@@ -11,11 +13,14 @@ socket.on('disconnect', ()=>{
|
|||||||
console.log('ws disconnected')
|
console.log('ws disconnected')
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on('welcome', (data)=>{
|
socket.on('welcome', async (data)=>{
|
||||||
console.log('welcome',data)
|
console.log('welcome',data)
|
||||||
|
const s = useStore()
|
||||||
|
s.chainInfo = data.chainInfo
|
||||||
|
s.vaultInitCodeHash = data.vaultInitCodeHash
|
||||||
|
const p = new ethers.BrowserProvider(window.ethereum)
|
||||||
|
const network = await p.getNetwork()
|
||||||
|
if( network !== null )
|
||||||
|
onChainChanged(network.chainId)
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on('chainInfo', async (chainInfo)=>{
|
|
||||||
const s = useStore()
|
|
||||||
s.chainInfo = chainInfo
|
|
||||||
})
|
|
||||||
|
|||||||
@@ -4,10 +4,12 @@ import {knownTokens} from "@/tokens.js";
|
|||||||
|
|
||||||
export const useStore = defineStore('app', {
|
export const useStore = defineStore('app', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
chainInfo: null,
|
|
||||||
chainId: null,
|
chainId: null,
|
||||||
|
chainInfo: null,
|
||||||
|
vaultInitCodeHash: null,
|
||||||
account: null,
|
account: null,
|
||||||
vault: null,
|
vaults: [],
|
||||||
|
pendingOrders: [], // created but not yet sent to metamask. maybe waiting on vault creation.
|
||||||
errors: [{
|
errors: [{
|
||||||
title: 'DANGER!',
|
title: 'DANGER!',
|
||||||
text: 'This is early development (alpha) software, which could have severe bugs that lose all your money. Thank you for testing a SMALL amount!',
|
text: 'This is early development (alpha) software, which could have severe bugs that lose all your money. Thank you for testing a SMALL amount!',
|
||||||
|
|||||||
Reference in New Issue
Block a user