import {uint32max, uint64max} from "@/misc.js"; import {encodeIEE754} from "@/common.js"; export const MAX_FRACTION = 65535; export const NO_CONDITIONAL_ORDER = uint64max; export const NO_OCO = uint64max; export const DISTANT_PAST = 0 export const DISTANT_FUTURE = uint32max // struct SwapOrder { // address tokenIn; // address tokenOut; // Route route; // uint256 amount; // uint256 minFillAmount; // if a tranche has less than this amount available to fill, it is considered completed // bool amountIsInput; // bool outputDirectlyToOwner; // bool inverted; // uint64 conditionalOrder; // use NO_CONDITIONAL_ORDER for no chaining. conditionalOrder index must be < than this order's index for safety (written first) and conditionalOrder state must be Template // Tranche[] tranches; // } // struct Route { // Exchange exchange; // uint24 fee; // } export function newOrder(tokenIn, tokenOut, exchange, fee, amount, amountIsInput, inverted, tranches, minFillAmount=null, outputDirectlyToOwner = false, conditionalOrder = NO_CONDITIONAL_ORDER) { amountIsInput = !!amountIsInput // force convert to bool outputDirectlyToOwner = !!outputDirectlyToOwner // force convert to bool amount = BigInt(amount) if (!tranches) tranches = [newTranche({marketOrder: true})] // todo this is just a swap: issue warning? if( minFillAmount === null ) minFillAmount = amount / 100n // default to min trade size of 1% return { tokenIn, tokenOut, route:{exchange, fee}, amount, minFillAmount, amountIsInput, outputDirectlyToOwner, inverted, conditionalOrder, tranches } } // struct Tranche { // uint16 fraction; // // bool startTimeIsRelative; // bool endTimeIsRelative; // bool minIsBarrier; // bool maxIsBarrier; // bool marketOrder; // if true, both min and max lines are ignored, and minIntercept is treated as a maximum slippage value (use positive numbers) // bool minIsRatio; // bool maxIsRatio; // bool _reserved7; // uint16 rateLimitFraction; // uint24 rateLimitPeriod; // // uint32 startTime; // use DISTANT_PAST to disable // uint32 endTime; // use DISTANT_FUTURE to disable // // // if intercept and slope are both 0 the line is disabled // float minIntercept; // if marketOrder==true, this is the (positive) max slippage amount // float minSlope; // float maxIntercept; // float maxSlope; // } export function newTranche({ fraction = MAX_FRACTION, marketOrder = false, startTimeIsRelative = false, startTime = DISTANT_PAST, endTimeIsRelative = false, endTime = DISTANT_FUTURE, minIsBarrier = false, minIsRatio = false, slippage = 0, // may also set minIntercept instead minIntercept = 0, minSlope = 0, maxIsBarrier = false, maxIsRatio = false, maxIntercept = 0, maxSlope = 0, rateLimitFraction = 0, rateLimitPeriod = 0, } = {}) { if( minIntercept === 0 && minSlope === 0 && maxIntercept === 0 && maxSlope === 0 ) marketOrder = true if( marketOrder ) { if (minIntercept !== 0 || minSlope !== 0 || maxIntercept !== 0 || maxSlope !== 0) console.warn('Ignoring line information in a market order') minIntercept = encodeIEE754(slippage) // this is the slippage field for market orders minSlope = 0 maxIntercept = 0 maxSlope = 0 } else { minIntercept = encodeIEE754(minIntercept) minSlope = encodeIEE754(minSlope) maxIntercept = encodeIEE754(maxIntercept) maxSlope = encodeIEE754(maxSlope) } const minLine = {intercept: minIntercept, slope: minSlope} const maxLine = {intercept: maxIntercept, slope: maxSlope} return { fraction: Math.min(MAX_FRACTION, Math.round(fraction)), marketOrder, startTimeIsRelative, startTime, endTimeIsRelative, endTime, minIsBarrier, minLine, maxIsBarrier, maxLine, minIsRatio, maxIsRatio, _reserved7: false, rateLimitFraction, rateLimitPeriod, } } export const Exchange = { UniswapV2: 0, UniswapV3: 1, } export const OrderState = { Unknown: -1, Signing: 0, Underfunded: 1, Open: 2, Canceled: 3, Expired: 4, Filled: 5, Error: 99, } export function isOpen(state) { return state >= 1 && state < 3 } export function parseElaboratedOrderStatus(chainId, status) { const [txId, ...remaining] = status const result = parseOrderStatus(chainId, remaining) result.txId = txId return result } export function parseOrderStatus(chainId, status) { let [ order, fillFeeHalfBps, state, startTime, startPrice, ocoGroup, filledIn, filledOut, trancheStatus, ] = status order = parseOrder(order) filledIn = BigInt(filledIn) filledOut = BigInt(filledOut) 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, filled, trancheStatus, }; console.log('SwapOrderStatus', result) return result } 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, filled, fee} } 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, amountIsInput)) const filled = amountIsInput ? filledIn : filledOut return {filledIn, filledOut, filled, activationTime, startTime, endTime, fills} } export function parseOrder(order) { let [ tokenIn, tokenOut, route, amount, minFillAmount, amountIsInput, outputDirectlyToOwner, inverted, conditionalOrder, tranches, ] = order route = parseRoute(route) amount = BigInt(amount) minFillAmount = BigInt(minFillAmount) tranches = tranches.map(parseTranche) return { tokenIn, tokenOut, route, amount, minFillAmount, amountIsInput, outputDirectlyToOwner, inverted, conditionalOrder, tranches } } export function parseRoute(route) { let [exchange, fee] = route return {exchange, fee} // todo enum? } export function parseTranche(tranche) { let [ fraction, startTimeIsRelative, endTimeIsRelative, minIsBarrier, maxIsBarrier, marketOrder, minIsRatio, maxIsRatio, _reserved7, rateLimitFraction, rateLimitPeriod, startTime, endTime, minLine, maxLine, ] = tranche const [minB,minS] = minLine minLine = {intercept: minB, slope: minS } const [maxB,maxS] = maxLine maxLine = {intercept: maxB, slope: maxS } const result = { fraction, startTimeIsRelative, endTimeIsRelative, minIsBarrier, maxIsBarrier, marketOrder, minIsRatio, maxIsRatio, rateLimitFraction, rateLimitPeriod, startTime, endTime, minLine, maxLine, } // console.log('parseTranche', tranche, result) return result } export function parseFeeSchedule(sched) { const [orderFee, orderExp, gasFee, gasExp, fillFeeHalfBps] = sched return { orderFee: orderFee << orderExp, // orderFee is in native (ETH) currency gasFee: gasFee << gasExp, // gasFee is in native (ETH) currency fillFee: fillFeeHalfBps/1_000_000 // fillFee is a multiplier on the filled volume. 0.0001 = 0.1% of the output token taken as a fee } }