Implement buy YES calculation
This commit is contained in:
		
							parent
							
								
									17ae9d953d
								
							
						
					
					
						commit
						06c49be05b
					
				|  | @ -89,6 +89,7 @@ export function calculateLPCost( | ||||||
|   deltaL: number |   deltaL: number | ||||||
| ) { | ) { | ||||||
|   // TODO: this is subtly wrong, because of rounding between curTick and sqrtPrice
 |   // 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 upperTick = Math.min(maxTick, Math.max(minTick, curTick)) | ||||||
|   const costN = toRatio(upperTick) ** 0.5 - toRatio(minTick) ** 0.5 |   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?
 | // Currently, this mutates the pool. Should it return a new object instead?
 | ||||||
| export function addPosition( | export function addPosition( | ||||||
|   pool: Swap3Pool, |   pool: Swap3Pool, | ||||||
|  | @ -165,5 +222,9 @@ export function toProb(tick: number) { | ||||||
| // Returns the tick for a given probability from 0 to 1
 | // Returns the tick for a given probability from 0 to 1
 | ||||||
| export function fromProb(prob: number) { | export function fromProb(prob: number) { | ||||||
|   const ratio = prob / (1 - prob) |   const ratio = prob / (1 - prob) | ||||||
|  |   return fromRatio(ratio) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function fromRatio(ratio: number) { | ||||||
|   return Math.floor(Math.log(ratio) / Math.log(1.0001)) |   return Math.floor(Math.log(ratio) / Math.log(1.0001)) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| import { | import { | ||||||
|   addPosition, |   addPosition, | ||||||
|  |   buyYes, | ||||||
|   calculateLPCost, |   calculateLPCost, | ||||||
|   fromProb, |   fromProb, | ||||||
|   getSwap3Probability, |   getSwap3Probability, | ||||||
|  | @ -136,11 +137,14 @@ export default function Swap() { | ||||||
|     tickStates: [], |     tickStates: [], | ||||||
|   } |   } | ||||||
|   INIT_POOL = addPosition(INIT_POOL, -(2 ** 23), 2 ** 20, 100) |   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) |   INIT_POOL = grossLiquidity(INIT_POOL) | ||||||
|  | 
 | ||||||
|   const [pool, setPool] = useState(INIT_POOL) |   const [pool, setPool] = useState(INIT_POOL) | ||||||
| 
 | 
 | ||||||
|   const [minTick, setMinTick] = useState(0) |   const [minTick, setMinTick] = useState(0) | ||||||
|   const [maxTick, setMaxTick] = useState(0) |   const [maxTick, setMaxTick] = useState(0) | ||||||
|  |   const [buyAmount, setBuyAmount] = useState(0) | ||||||
| 
 | 
 | ||||||
|   const { requiredN, requiredY } = calculateLPCost( |   const { requiredN, requiredY } = calculateLPCost( | ||||||
|     pool.tick, |     pool.tick, | ||||||
|  | @ -149,6 +153,8 @@ export default function Swap() { | ||||||
|     100 // deltaL
 |     100 // deltaL
 | ||||||
|   ) |   ) | ||||||
| 
 | 
 | ||||||
|  |   const { newPoolTick, yesPurchased } = buyYes(pool, buyAmount) | ||||||
|  | 
 | ||||||
|   return ( |   return ( | ||||||
|     <Col className="mx-auto max-w-2xl gap-10 p-4"> |     <Col className="mx-auto max-w-2xl gap-10 p-4"> | ||||||
|       {/* <BalanceTable /> */} |       {/* <BalanceTable /> */} | ||||||
|  | @ -200,10 +206,20 @@ export default function Swap() { | ||||||
|       <Col> |       <Col> | ||||||
|         Bob: Buy Tokens |         Bob: Buy Tokens | ||||||
|         {/* <input className="input" placeholder="User" type="text" /> */} |         {/* <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"> |         <Row className="gap-2"> | ||||||
|           <button className="btn">Buy YES</button> |           <button className="btn">Buy YES</button> | ||||||
|           <button className="btn">Buy NO</button> |           {/* <button className="btn">Buy NO</button> */} | ||||||
|         </Row> |         </Row> | ||||||
|       </Col> |       </Col> | ||||||
|     </Col> |     </Col> | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user