manifold/common/calculate-swap3.ts
2022-06-07 09:46:36 -07:00

159 lines
4.1 KiB
TypeScript

type Swap3LiquidityPosition = {
// TODO: Record who added this stuff?
// Not sure if this is needed; maybe YES and NO left
// amount: number // M$ quantity
// For now, only support YES and NO outcome tokens
// TODO: replace with Outcome
// Hm, is this...
// 1. Number of shares left in this particular pool?
// 2. Fixed at injection time?
pool: { YES: number; NO: number }
// Uniswap uses 0.01, 0.003, 0.0005. Let's stick with 0.003 for now.
// fee: number
// Min/max is expressed as a odds ratio of cost of YES to cost of NO
// E.g. ratio of 1 = 1:1 = 50%; ratio of 3 = 3:1 = 75%
// minRatio: number
// maxRatio: number
minTick: number
// minTick = loq_sqrt_1.0001(sqrtRatio)
// sqrt(1.0001)^(minTick) = sqrtRatio
// minRatio = 1.0001^minTick
// e.g. minTick = 20k => 7.3883
maxTick: number
}
type TickState = {
tick: number
// Amount of liquidity added when crossing this tick from left to right
// Negative if we should remove liquidity
liquidityNet: number
// Total liquidity referencing this pool
liquidityGross: number
}
// From https://uniswap.org/whitepaper-v3.pdf
export type Swap3Pool = {
// id: string
// userId: string
// contractId: string
// createdTime: number
// 6.2 Global State
liquidity: number // = sqrt(NY)
// sqrtRatio: number // = sqrt(N / Y); N = # NO shares in pool
// So N = liquidity * sqrtRatio; Y = liquidity / sqrtRatio
// Current tick number.
// Stored as optimization. equal to floor(log_sqrt_1.0001(sqrtRatio))
tick: number
// TODO add fees?
// Mapping of tick indices to tick values.
tickStates: TickState[]
}
export function noShares(pool: Swap3Pool) {
return pool.liquidity * toRatio(pool.tick) ** 0.5
}
export function yesShares(pool: Swap3Pool) {
return pool.liquidity / toRatio(pool.tick) ** 0.5
}
export function getSwap3Probability(pool: Swap3Pool) {
// Probability is given by N / (N + Y)
// const N = pool.liquidity * pool.sqrtRatio
// const Y = pool.liquidity / pool.sqrtRatio
// return N / (N + Y)
// To check: this should be equal to toProb(pool.tick)?
return toProb(pool.tick)
}
function calculatePurchase(
pool: Swap3Pool,
amount: number,
outcome: 'YES' | 'NO'
) {
const shares = 10
const newPool = {}
}
export function calculateLPCost(
curTick: number,
minTick: number,
maxTick: number,
deltaL: number
) {
// TODO: this is subtly wrong, because of rounding between curTick and sqrtPrice
const upperTick = Math.min(maxTick, Math.max(minTick, curTick))
const costN = toRatio(upperTick) ** 0.5 - toRatio(minTick) ** 0.5
const lowerTick = Math.max(minTick, Math.min(maxTick, curTick))
const costY = 1 / toRatio(lowerTick) ** 0.5 - 1 / toRatio(maxTick) ** 0.5
return {
requiredN: deltaL * costN,
requiredY: deltaL * costY,
}
}
// TODO: Untested
function addPosition(
pool: Swap3Pool,
minTick: number,
maxTick: number,
deltaL: number
) {
const { requiredN, requiredY } = calculateLPCost(
pool.tick,
minTick,
maxTick,
deltaL
)
console.log(`Deducting required N: ${requiredN} and required Y: ${requiredY}`)
// Add liquidity as we pass through the larger tick
const maxTickState = pool.tickStates[maxTick] || {
tick: maxTick,
liquidityNet: 0,
liquidityGross: 0,
}
maxTickState.liquidityNet += deltaL
maxTickState.liquidityGross += deltaL
// And remove it as we pass through the lower one
const minTickState = pool.tickStates[minTick] || {
tick: minTick,
liquidityNet: 0,
liquidityGross: 0,
}
minTickState.liquidityNet -= deltaL
minTickState.liquidityGross -= deltaL
// TODO: add deltaL to liquidityGross of tickStates between minTick and maxTick
}
function toRatio(tick: number) {
return 1.0001 ** tick
}
function toProb(tick: number) {
const ratio = toRatio(tick)
return ratio / (ratio + 1)
}
// Returns the tick for a given probability from 0 to 1
export function fromProb(prob: number) {
const ratio = prob / (1 - prob)
return Math.floor(Math.log(ratio) / Math.log(1.0001))
}