Implement buy YES calculation
This commit is contained in:
		
							parent
							
								
									17ae9d953d
								
							
						
					
					
						commit
						06c49be05b
					
				|  | @ -89,6 +89,7 @@ export function calculateLPCost( | |||
|   deltaL: number | ||||
| ) { | ||||
|   // TODO: this is subtly wrong, because of rounding between curTick and sqrtPrice
 | ||||
|   // Also below in buyYES
 | ||||
|   const upperTick = Math.min(maxTick, Math.max(minTick, curTick)) | ||||
|   const costN = toRatio(upperTick) ** 0.5 - toRatio(minTick) ** 0.5 | ||||
| 
 | ||||
|  | @ -101,6 +102,62 @@ export function calculateLPCost( | |||
|   } | ||||
| } | ||||
| 
 | ||||
| // Returns a preview of the new pool + number of YES shares purchased.
 | ||||
| // Does NOT modify the pool
 | ||||
| // Hm, logic is pretty complicated. Let's see if we can simplify this.
 | ||||
| export function buyYes( | ||||
|   pool: Swap3Pool, | ||||
|   amount: number // In M$
 | ||||
| ) { | ||||
|   const tickStates = sortedTickStates(pool) | ||||
|   let tick = pool.tick | ||||
|   let stateIndex = 0 | ||||
|   let amountLeft = amount | ||||
|   let yesPurchased = 0 | ||||
|   while (amountLeft > 0) { | ||||
|     // Find the current tick state
 | ||||
|     while (tick >= tickStates[stateIndex + 1].tick) { | ||||
|       stateIndex++ | ||||
|       if (stateIndex > tickStates.length - 2) { | ||||
|         // We've reached the end of the tick states...
 | ||||
|         throw new Error('Ran out of tick states') | ||||
|       } | ||||
|     } | ||||
|     const state = tickStates[stateIndex] | ||||
|     const nextState = tickStates[stateIndex + 1] | ||||
| 
 | ||||
|     // Copied from above; TODO extract to common function
 | ||||
|     const noCost = toRatio(nextState.tick) ** 0.5 - toRatio(tick) ** 0.5 | ||||
|     const yesCost = | ||||
|       1 / toRatio(tick) ** 0.5 - 1 / toRatio(nextState.tick) ** 0.5 | ||||
| 
 | ||||
|     if (noCost * state.liquidityGross <= amountLeft) { | ||||
|       // We can fully purchase up until the next tick state
 | ||||
|       amountLeft -= noCost * state.liquidityGross | ||||
|       yesPurchased += yesCost * state.liquidityGross | ||||
|       tick = nextState.tick | ||||
|     } else { | ||||
|       // Buy as much as we can at the current tick state. Derivation:
 | ||||
|       // noCostLeft = toRatio(upTick) ** 0.5 - toRatio(tick) ** 0.5
 | ||||
|       // (noCostLeft + toRatio(tick) ** 0.5) ** 2 = toRatio(upTick)
 | ||||
|       // TODO check flooring done here
 | ||||
|       const noCostLeft = amountLeft / state.liquidityGross | ||||
|       const finalTick = fromRatio((noCostLeft + toRatio(tick) ** 0.5) ** 2) | ||||
|       const yesCostLeft = | ||||
|         1 / toRatio(tick) ** 0.5 - 1 / toRatio(finalTick) ** 0.5 | ||||
| 
 | ||||
|       amountLeft = 0 | ||||
|       yesPurchased += yesCostLeft * state.liquidityGross | ||||
|       tick = finalTick | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return { | ||||
|     newPoolTick: tick, | ||||
|     yesPurchased, | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // Currently, this mutates the pool. Should it return a new object instead?
 | ||||
| export function addPosition( | ||||
|   pool: Swap3Pool, | ||||
|  | @ -165,5 +222,9 @@ export function toProb(tick: number) { | |||
| // Returns the tick for a given probability from 0 to 1
 | ||||
| export function fromProb(prob: number) { | ||||
|   const ratio = prob / (1 - prob) | ||||
|   return fromRatio(ratio) | ||||
| } | ||||
| 
 | ||||
| function fromRatio(ratio: number) { | ||||
|   return Math.floor(Math.log(ratio) / Math.log(1.0001)) | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| import { | ||||
|   addPosition, | ||||
|   buyYes, | ||||
|   calculateLPCost, | ||||
|   fromProb, | ||||
|   getSwap3Probability, | ||||
|  | @ -136,11 +137,14 @@ export default function Swap() { | |||
|     tickStates: [], | ||||
|   } | ||||
|   INIT_POOL = addPosition(INIT_POOL, -(2 ** 23), 2 ** 20, 100) | ||||
|   INIT_POOL = addPosition(INIT_POOL, fromProb(0.32), fromProb(0.35), 100) | ||||
|   INIT_POOL = grossLiquidity(INIT_POOL) | ||||
| 
 | ||||
|   const [pool, setPool] = useState(INIT_POOL) | ||||
| 
 | ||||
|   const [minTick, setMinTick] = useState(0) | ||||
|   const [maxTick, setMaxTick] = useState(0) | ||||
|   const [buyAmount, setBuyAmount] = useState(0) | ||||
| 
 | ||||
|   const { requiredN, requiredY } = calculateLPCost( | ||||
|     pool.tick, | ||||
|  | @ -149,6 +153,8 @@ export default function Swap() { | |||
|     100 // deltaL
 | ||||
|   ) | ||||
| 
 | ||||
|   const { newPoolTick, yesPurchased } = buyYes(pool, buyAmount) | ||||
| 
 | ||||
|   return ( | ||||
|     <Col className="mx-auto max-w-2xl gap-10 p-4"> | ||||
|       {/* <BalanceTable /> */} | ||||
|  | @ -200,10 +206,20 @@ export default function Swap() { | |||
|       <Col> | ||||
|         Bob: Buy Tokens | ||||
|         {/* <input className="input" placeholder="User" type="text" /> */} | ||||
|         <input className="input" placeholder="Amount" type="number" /> | ||||
|         <input | ||||
|           className="input" | ||||
|           placeholder="Amount" | ||||
|           type="number" | ||||
|           onChange={(e) => setBuyAmount(parseFloat(e.target.value))} | ||||
|         /> | ||||
|         <Row className="gap-2 py-2"> | ||||
|           <div>Y shares purchaseable: {yesPurchased.toFixed(2)}</div> | ||||
|           <div>New Tick: {newPoolTick}</div> | ||||
|           <div>New prob: {formatPercent(toProb(newPoolTick))}</div> | ||||
|         </Row> | ||||
|         <Row className="gap-2"> | ||||
|           <button className="btn">Buy YES</button> | ||||
|           <button className="btn">Buy NO</button> | ||||
|           {/* <button className="btn">Buy NO</button> */} | ||||
|         </Row> | ||||
|       </Col> | ||||
|     </Col> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user