2022-06-07 15:37:00 +00:00
|
|
|
import {
|
2022-06-08 15:45:09 +00:00
|
|
|
addPosition,
|
2022-06-09 02:56:59 +00:00
|
|
|
buyYes,
|
2022-06-07 15:37:00 +00:00
|
|
|
calculateLPCost,
|
|
|
|
fromProb,
|
|
|
|
getSwap3Probability,
|
2022-06-08 17:36:35 +00:00
|
|
|
grossLiquidity,
|
2022-06-07 16:46:36 +00:00
|
|
|
noShares,
|
2022-06-08 15:45:09 +00:00
|
|
|
sortedTickStates,
|
2022-06-07 15:37:00 +00:00
|
|
|
Swap3Pool,
|
2022-06-08 15:45:09 +00:00
|
|
|
toProb,
|
2022-06-07 16:46:36 +00:00
|
|
|
yesShares,
|
2022-06-07 15:37:00 +00:00
|
|
|
} from 'common/calculate-swap3'
|
|
|
|
import { formatPercent } from 'common/util/format'
|
|
|
|
import { useState } from 'react'
|
2022-06-07 16:36:42 +00:00
|
|
|
import { LiquidityGraph } from 'web/components/contract/liquidity-graph'
|
2022-06-07 15:37:00 +00:00
|
|
|
import { Col } from 'web/components/layout/col'
|
|
|
|
import { Row } from 'web/components/layout/row'
|
2022-06-08 17:36:35 +00:00
|
|
|
import { addLiquidity } from 'web/lib/firebase/fn-call'
|
2022-06-07 15:37:00 +00:00
|
|
|
|
2022-06-08 16:10:34 +00:00
|
|
|
const users: Record<string, any> = {
|
2022-06-07 15:37:00 +00:00
|
|
|
alice: {
|
|
|
|
M: 100,
|
|
|
|
YES: 0,
|
|
|
|
NO: 0,
|
|
|
|
},
|
|
|
|
bob: {
|
|
|
|
M: 200,
|
|
|
|
YES: 0,
|
|
|
|
NO: 0,
|
|
|
|
},
|
|
|
|
kipply: {
|
|
|
|
M: 300,
|
|
|
|
YES: 0,
|
|
|
|
NO: 0,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
function BalanceTable() {
|
|
|
|
/* Display all users current M, YES, and NO in a table */
|
|
|
|
return (
|
|
|
|
<table className="w-full">
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th className="px-4 py-2">User</th>
|
|
|
|
<th className="px-4 py-2">M</th>
|
|
|
|
<th className="px-4 py-2">YES</th>
|
|
|
|
<th className="px-4 py-2">NO</th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
|
|
|
{Object.keys(users).map((user) => (
|
|
|
|
<tr key={user}>
|
|
|
|
<td className="px-4 py-2">{user}</td>
|
|
|
|
<td className="px-4 py-2">{users[user].M}</td>
|
|
|
|
<td className="px-4 py-2">{users[user].YES}</td>
|
|
|
|
<td className="px-4 py-2">{users[user].NO}</td>
|
|
|
|
</tr>
|
|
|
|
))}
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Show the values in pool */
|
|
|
|
function PoolTable(props: { pool: Swap3Pool }) {
|
|
|
|
const { pool } = props
|
|
|
|
return (
|
2022-06-08 15:45:09 +00:00
|
|
|
<>
|
|
|
|
<Row className="gap-4">
|
|
|
|
<div>
|
|
|
|
<label>Implied: </label>
|
|
|
|
{formatPercent(getSwap3Probability(pool))}
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div>
|
|
|
|
<label>Liquidity: </label>
|
|
|
|
{pool.liquidity}
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<label>Tick: </label>
|
|
|
|
{pool.tick}
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<label>Pool YES: </label>
|
|
|
|
{yesShares(pool).toFixed(2)}
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<label>Pool NO: </label>
|
|
|
|
{noShares(pool).toFixed(2)}
|
|
|
|
</div>
|
|
|
|
</Row>
|
|
|
|
{/* Render each tickState as another row in a table */}
|
|
|
|
<table className="w-full">
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th className="px-4 py-2">Tick</th>
|
|
|
|
<th className="px-4 py-2">Prob</th>
|
|
|
|
<th className="px-4 py-2">Net Liquidity</th>
|
2022-06-08 17:36:35 +00:00
|
|
|
<th className="px-4 py-2">Gross Liquidity</th>
|
2022-06-08 15:45:09 +00:00
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
{sortedTickStates(pool).map((tickState, i) => (
|
|
|
|
<tr key={i}>
|
|
|
|
<td className="px-4 py-2">{tickState.tick}</td>
|
|
|
|
<td className="px-4 py-2">
|
|
|
|
{formatPercent(toProb(tickState.tick))}
|
|
|
|
</td>
|
|
|
|
<td className="px-4 py-2">{tickState.liquidityNet}</td>
|
2022-06-08 17:36:35 +00:00
|
|
|
<td className="px-4 py-2">{tickState.liquidityGross}</td>
|
2022-06-08 15:45:09 +00:00
|
|
|
</tr>
|
|
|
|
))}
|
|
|
|
</table>
|
|
|
|
</>
|
2022-06-07 15:37:00 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-06-09 03:29:23 +00:00
|
|
|
function Graph(props: { pool: Swap3Pool; previewMarker?: number }) {
|
|
|
|
const { pool, previewMarker } = props
|
2022-06-08 17:36:35 +00:00
|
|
|
const points = []
|
|
|
|
let lastGross = 0
|
2022-06-08 15:45:09 +00:00
|
|
|
for (const tickState of sortedTickStates(pool)) {
|
2022-06-08 17:36:35 +00:00
|
|
|
const { tick, liquidityGross } = tickState
|
|
|
|
points.push({ x: toProb(tick), y: lastGross })
|
|
|
|
points.push({ x: toProb(tick), y: liquidityGross })
|
|
|
|
lastGross = liquidityGross
|
2022-06-08 15:45:09 +00:00
|
|
|
}
|
2022-06-09 03:29:23 +00:00
|
|
|
return (
|
|
|
|
<LiquidityGraph
|
|
|
|
points={points}
|
|
|
|
marker={toProb(pool.tick)}
|
|
|
|
previewMarker={previewMarker}
|
|
|
|
/>
|
|
|
|
)
|
2022-06-07 16:36:42 +00:00
|
|
|
}
|
|
|
|
|
2022-06-07 15:37:00 +00:00
|
|
|
export default function Swap() {
|
2022-06-08 17:36:35 +00:00
|
|
|
// Set up an initial pool with 100 liquidity from 0% to 100%
|
|
|
|
// TODO: Not sure why maxTick of 2**23 breaks it, but 2**20 is okay...
|
|
|
|
let INIT_POOL: Swap3Pool = {
|
|
|
|
liquidity: 0,
|
2022-06-07 15:54:17 +00:00
|
|
|
tick: fromProb(0.3),
|
2022-06-07 16:36:42 +00:00
|
|
|
tickStates: [],
|
2022-06-08 17:36:35 +00:00
|
|
|
}
|
|
|
|
INIT_POOL = addPosition(INIT_POOL, -(2 ** 23), 2 ** 20, 100)
|
2022-06-09 02:56:59 +00:00
|
|
|
INIT_POOL = addPosition(INIT_POOL, fromProb(0.32), fromProb(0.35), 100)
|
2022-06-08 17:36:35 +00:00
|
|
|
INIT_POOL = grossLiquidity(INIT_POOL)
|
2022-06-09 02:56:59 +00:00
|
|
|
|
2022-06-08 17:36:35 +00:00
|
|
|
const [pool, setPool] = useState(INIT_POOL)
|
2022-06-07 15:37:00 +00:00
|
|
|
|
|
|
|
const [minTick, setMinTick] = useState(0)
|
|
|
|
const [maxTick, setMaxTick] = useState(0)
|
2022-06-10 16:12:44 +00:00
|
|
|
const [deltaL, setDeltaL] = useState(100)
|
2022-06-09 02:56:59 +00:00
|
|
|
const [buyAmount, setBuyAmount] = useState(0)
|
2022-06-07 15:37:00 +00:00
|
|
|
|
|
|
|
const { requiredN, requiredY } = calculateLPCost(
|
|
|
|
pool.tick,
|
|
|
|
minTick,
|
|
|
|
maxTick,
|
2022-06-10 16:12:44 +00:00
|
|
|
deltaL
|
2022-06-07 15:37:00 +00:00
|
|
|
)
|
|
|
|
|
2022-06-09 02:56:59 +00:00
|
|
|
const { newPoolTick, yesPurchased } = buyYes(pool, buyAmount)
|
|
|
|
|
2022-06-07 15:37:00 +00:00
|
|
|
return (
|
2022-06-08 15:45:09 +00:00
|
|
|
<Col className="mx-auto max-w-2xl gap-10 p-4">
|
2022-06-07 16:36:42 +00:00
|
|
|
{/* <BalanceTable /> */}
|
2022-06-07 15:37:00 +00:00
|
|
|
<PoolTable pool={pool} />
|
2022-06-09 03:29:23 +00:00
|
|
|
<Graph
|
|
|
|
pool={pool}
|
|
|
|
previewMarker={
|
|
|
|
newPoolTick === pool.tick ? undefined : toProb(newPoolTick)
|
|
|
|
}
|
|
|
|
/>
|
2022-06-07 15:37:00 +00:00
|
|
|
<input
|
|
|
|
className="input"
|
2022-06-07 16:46:36 +00:00
|
|
|
placeholder="Current%"
|
2022-06-07 15:37:00 +00:00
|
|
|
type="number"
|
2022-06-08 15:45:09 +00:00
|
|
|
onChange={(e) => {
|
|
|
|
pool.tick = inputPercentToTick(e)
|
|
|
|
setPool({ ...pool })
|
|
|
|
}}
|
2022-06-07 15:37:00 +00:00
|
|
|
/>
|
|
|
|
|
|
|
|
<Col>
|
2022-06-10 16:12:44 +00:00
|
|
|
<h2 className="my-2 text-xl">Add liquidity</h2>
|
2022-06-08 15:45:09 +00:00
|
|
|
{/* <input className="input" placeholder="Amount" type="number" /> */}
|
2022-06-10 16:12:44 +00:00
|
|
|
<Row className="gap-2">
|
|
|
|
<input
|
|
|
|
className="input"
|
|
|
|
placeholder="Min%"
|
|
|
|
type="number"
|
|
|
|
onChange={(e) => setMinTick(inputPercentToTick(e))}
|
|
|
|
/>
|
|
|
|
{/* Min Tick: {minTick} */}
|
|
|
|
<input
|
|
|
|
className="input"
|
|
|
|
placeholder="Max%"
|
|
|
|
type="number"
|
|
|
|
onChange={(e) => setMaxTick(inputPercentToTick(e))}
|
|
|
|
/>
|
|
|
|
{/* Max Tick: {maxTick} */}
|
|
|
|
<input
|
|
|
|
className="input"
|
|
|
|
placeholder="delta Liquidity"
|
|
|
|
type="number"
|
|
|
|
value={deltaL}
|
|
|
|
onChange={(e) => setDeltaL(parseFloat(e.target.value))}
|
|
|
|
/>
|
|
|
|
</Row>
|
2022-06-07 15:37:00 +00:00
|
|
|
<Row className="gap-2 py-2">
|
2022-06-10 16:12:44 +00:00
|
|
|
<div>Y required: {requiredY.toFixed(2)}</div>
|
|
|
|
<div>N required: {requiredN.toFixed(2)}</div>{' '}
|
2022-06-07 15:37:00 +00:00
|
|
|
</Row>
|
2022-06-08 15:45:09 +00:00
|
|
|
<button
|
|
|
|
className="btn"
|
|
|
|
onClick={() => {
|
|
|
|
addPosition(pool, minTick, maxTick, 100)
|
2022-06-08 17:36:35 +00:00
|
|
|
grossLiquidity(pool)
|
2022-06-08 15:45:09 +00:00
|
|
|
setPool({ ...pool })
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
Create pool
|
|
|
|
</button>
|
2022-06-07 15:37:00 +00:00
|
|
|
</Col>
|
|
|
|
|
|
|
|
<Col>
|
2022-06-10 16:12:44 +00:00
|
|
|
<h2 className="my-2 text-xl">Limit Order</h2>
|
|
|
|
TODO
|
|
|
|
</Col>
|
|
|
|
|
|
|
|
<Col>
|
|
|
|
<h2 className="my-2 text-xl">Buy Shares</h2>
|
2022-06-07 15:37:00 +00:00
|
|
|
{/* <input className="input" placeholder="User" type="text" /> */}
|
2022-06-09 02:56:59 +00:00
|
|
|
<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>
|
2022-06-07 15:37:00 +00:00
|
|
|
<Row className="gap-2">
|
|
|
|
<button className="btn">Buy YES</button>
|
2022-06-09 02:56:59 +00:00
|
|
|
{/* <button className="btn">Buy NO</button> */}
|
2022-06-07 15:37:00 +00:00
|
|
|
</Row>
|
|
|
|
</Col>
|
|
|
|
</Col>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
function inputPercentToTick(event: React.ChangeEvent<HTMLInputElement>) {
|
|
|
|
return fromProb(parseFloat(event.target.value) / 100)
|
|
|
|
}
|