Skip to content

Commit

Permalink
adjust decimals correctly based on correct 6/18 decimal prices in con…
Browse files Browse the repository at this point in the history
…tract
  • Loading branch information
eli-d committed Jun 24, 2024
1 parent 4777676 commit a41f9d6
Show file tree
Hide file tree
Showing 11 changed files with 42 additions and 41 deletions.
12 changes: 6 additions & 6 deletions web/__tests__/01_lib_math/001_sqrt_price.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,22 @@ describe("sqrtPriceX96ToPrice", () => {
it("18 decimals, price > 1", () => {
const decimals = 18;
const sqrtPriceX96 = 1082626999771884967498373611162n
const encoded = sqrtPriceX96ToPrice(sqrtPriceX96)
const encoded = sqrtPriceX96ToPrice(sqrtPriceX96, decimals)
expect(encoded).toBe(186723311178398592718n)
expect(Number(encoded) / 10 ** decimals).toBe(186.7233111783986)
});
it("18 decimals, price < 1", () => {
const decimals = 18;
const sqrtPriceX96 = 4730467712712532270754096n
const encoded = sqrtPriceX96ToPrice(sqrtPriceX96)
const encoded = sqrtPriceX96ToPrice(sqrtPriceX96, decimals)
expect(encoded).toBe(3564913510n)
expect(Number(encoded) / 10 ** decimals).toBe(3.56491351e-9)
});
it("6 decimals, price > 1", () => {
const decimals = 6;
const sqrtPriceX96 = 79141441126769916199805n
const encoded = sqrtPriceX96ToPrice(sqrtPriceX96)
expect(encoded).toBe(997812n)
expect(Number(encoded) / 10 ** decimals).toBe(0.997812)
const sqrtPriceX96 = 79255302979313818192107071359n
const encoded = sqrtPriceX96ToPrice(sqrtPriceX96, decimals)
expect(encoded).toBe(1000685n)
expect(Number(encoded) / 10 ** decimals).toBe(1.000685)
});
});
2 changes: 1 addition & 1 deletion web/src/app/SwapForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export const SwapForm = () => {
});

const tokenPrice = poolSqrtPriceX96
? sqrtPriceX96ToPrice(poolSqrtPriceX96.result)
? sqrtPriceX96ToPrice(poolSqrtPriceX96.result, token0.decimals)
: 0n;

const { data: token0Balance, refetch: refetchToken0Balance } = useBalance({
Expand Down
3 changes: 2 additions & 1 deletion web/src/app/stake/AllPools.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { sum } from "lodash";
import { graphql, useFragment } from "@/gql";
import { useRouter } from "next/navigation";
import { getFormattedPriceFromTick } from "@/lib/amounts";
import { fUSDC } from "@/config/tokens";

const DisplayModeMenu = ({
setDisplayMode,
Expand Down Expand Up @@ -134,7 +135,7 @@ export const AllPools = () => {
position.lower < min ? position.lower : min,
position.upper > max ? position.upper : max
], [0, 0]).map(tick =>
getFormattedPriceFromTick(tick, pool.token.decimals)
getFormattedPriceFromTick(tick, pool.token.decimals, fUSDC.decimals)
) as [string, string];

return {
Expand Down
4 changes: 2 additions & 2 deletions web/src/app/stake/pool/confirm-withdraw/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default function ConfirmWithdrawLiquidity() {
address: ammAddress,
abi: seawaterContract.abi,
functionName: "updatePosition",
args: [token0.address, id, delta],
args: [token0.address, id, -delta],
});
},
[delta, writeContractUpdatePosition, token0AmountRaw, token0],
Expand All @@ -61,7 +61,7 @@ export default function ConfirmWithdrawLiquidity() {
});

const tokenPrice = poolSqrtPriceX96
? sqrtPriceX96ToPrice(poolSqrtPriceX96.result)
? sqrtPriceX96ToPrice(poolSqrtPriceX96.result, token0.decimals)
: 0n;

// step 1 pending
Expand Down
4 changes: 2 additions & 2 deletions web/src/app/stake/pool/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -307,9 +307,9 @@ export default function PoolPage() {
<div className="flex flex-1 flex-col">
<div className="text-3xs md:text-2xs">Current Position Range</div>
<div className="text-xl md:text-2xl">
{getFormattedPriceFromTick(lowerTick ?? 0, fUSDC.decimals)}
{lowerTick ? getFormattedPriceFromTick(lowerTick, token0.decimals, token1.decimals) : usdFormat(0)}
-
{getFormattedPriceFromTick(upperTick ?? 0, fUSDC.decimals)}
{upperTick ? getFormattedPriceFromTick(upperTick, token0.decimals, token1.decimals) : usdFormat(0)}
</div>
</div>
<div className="flex flex-1 flex-col">
Expand Down
4 changes: 2 additions & 2 deletions web/src/app/stake/pool/withdraw-liquidity/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export default function WithdrawLiquidity() {
});

const tokenPrice = poolSqrtPriceX96
? sqrtPriceX96ToPrice(poolSqrtPriceX96.result)
? sqrtPriceX96ToPrice(poolSqrtPriceX96.result, token0.decimals)
: 0n;

const { data } = useGraphqlUser();
Expand All @@ -117,7 +117,7 @@ export default function WithdrawLiquidity() {
const deltaUsd = useMemo(() => {
if (!token0Amount || !token1Amount)
return "$0.00"
const token0AmountScaled = Number(token0Amount) * Number(tokenPrice) * 10 ** fUSDC.decimals;
const token0AmountScaled = Number(token0Amount) * Number(tokenPrice) / 10 ** fUSDC.decimals
return usdFormat(token0AmountScaled + parseFloat(token1Amount))
}, [token0Amount, token1Amount])

Expand Down
2 changes: 1 addition & 1 deletion web/src/components/ConfirmStake.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const ConfirmStake = ({ mode, positionId }: ConfirmStakeProps) => {
});

const tokenPrice = poolSqrtPriceX96
? sqrtPriceX96ToPrice(poolSqrtPriceX96.result)
? sqrtPriceX96ToPrice(poolSqrtPriceX96.result, token0.decimals)
: 0n;

// if no token or no token amount redirect to the stake form
Expand Down
25 changes: 13 additions & 12 deletions web/src/components/StakeForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ export const StakeForm = ({ mode, poolId, positionId }: StakeFormProps) => {
});

const tokenPrice = poolSqrtPriceX96
? sqrtPriceX96ToPrice(poolSqrtPriceX96.result)
? sqrtPriceX96ToPrice(poolSqrtPriceX96.result, token0.decimals)
: 0n;

// in this context, token0 is actually token1. It's converted to token1
Expand Down Expand Up @@ -270,31 +270,32 @@ export const StakeForm = ({ mode, poolId, positionId }: StakeFormProps) => {
useEffect(() => {
// set the ticks to the existing ticks of the pool
if (mode === "existing") {
const priceLower = lowerTick === 0 ? "0" : (1.0001 ** lowerTick).toFixed(fUSDC.decimals)
const priceHigher = (1.0001 ** upperTick).toFixed(fUSDC.decimals)
setPriceLower(priceLower)
setPriceUpper(priceHigher)
const scale = token0.decimals - fUSDC.decimals
const priceLower = (1.0001 ** lowerTick * 10 ** scale).toFixed(fUSDC.decimals)
const priceHigher = (1.0001 ** upperTick * 10 ** scale).toFixed(fUSDC.decimals)
setPriceLower(priceLower, token0.decimals)
setPriceUpper(priceHigher, token0.decimals)
return
}

if (liquidityRangeType === "full-range") {
// lower price is 1 base fUSDC (0.000001)
setPriceLower(`0.${"0".repeat(token1.decimals - 1)}1`)
setPriceLower(`0.${"0".repeat(token1.decimals - 1)}1`, token0.decimals)
// upper price is max tick
setPriceUpper(String(1.0001 ** MAX_TICK))
setPriceUpper(String(1.0001 ** MAX_TICK), token0.decimals)
}
else if (liquidityRangeType === "auto") {
if (!curTick)
return
// auto sets the price range to +-10% of the current tick
const priceAtTick = sqrtPriceX96ToPrice(getSqrtRatioAtTick(curTick.result))
const priceAtTick = sqrtPriceX96ToPrice(getSqrtRatioAtTick(curTick.result), token0.decimals)
const diff = priceAtTick / 10n
const pu = priceAtTick + diff
const pl = priceAtTick - diff
const priceLower = (Number(pl) / 10 ** fUSDC.decimals).toFixed(fUSDC.decimals)
const priceUpper = (Number(pu) / 10 ** fUSDC.decimals).toFixed(fUSDC.decimals)
setPriceLower(priceLower)
setPriceUpper(priceUpper)
setPriceLower(priceLower, token0.decimals)
setPriceUpper(priceUpper, token0.decimals)
}
}, [
mode,
Expand Down Expand Up @@ -784,7 +785,7 @@ export const StakeForm = ({ mode, poolId, positionId }: StakeFormProps) => {
className="border-b border-white text-2xs md:text-base bg-black"
disabled={liquidityRangeType !== "custom" || mode === "existing"}
value={priceLower}
onChange={(e) => setPriceLower(e.target.value)}
onChange={(e) => setPriceLower(e.target.value, token0.decimals)}
/>
<div className="mt-1 flex flex-row items-center gap-1 text-3xs">
<Ethereum className="invert" /> fUSDC per {token0.name}
Expand All @@ -797,7 +798,7 @@ export const StakeForm = ({ mode, poolId, positionId }: StakeFormProps) => {
className="border-b border-white text-2xs md:text-base bg-black"
disabled={liquidityRangeType !== "custom" || mode === "existing"}
value={priceUpper}
onChange={(e) => setPriceUpper(e.target.value)}
onChange={(e) => setPriceUpper(e.target.value, token0.decimals)}
/>
<div className="mt-1 flex flex-row items-center gap-1 text-3xs">
<Ethereum className="invert" /> fUSDC per {token0.name}
Expand Down
8 changes: 4 additions & 4 deletions web/src/lib/amounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ const getFormattedPriceFromAmount = (amount: string, price: string | bigint, dec
Number(amount) * Number(price) / 10 ** decimalsFusdc

// convert a tick to a formatted price, scaled by decimals
const getFormattedPriceFromTick = (tick: number, decimals: number) => {
const getFormattedPriceFromTick = (tick: number, decimals0: number, decimals1: number) => {
const ratio = getSqrtRatioAtTick(BigInt(tick))
const priceUnscaled = Number(sqrtPriceX96ToPrice(ratio))
// adjust for decimals, and for 18 digits of price precision
const scale = 10 ** -(decimals + 18)
const priceUnscaled = Number(sqrtPriceX96ToPrice(ratio, decimals0))
// adjust for decimals
const scale = 10 ** -(decimals1)
const formattedPrice = usdFormat(priceUnscaled * scale)
// display '∞ ' if the price is greater than $10e18 after scaling
return formattedPrice.length > 20 ? '∞ ' : formattedPrice
Expand Down
7 changes: 3 additions & 4 deletions web/src/lib/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,11 @@ export const encodeSqrtPrice = (price: number): bigint => {
return BigInt(Math.sqrt(price) * 2 ** 96);
};

// convert a sqrtPriceX96 to a price in 18 digits of precision
// convert a sqrtPriceX96 to a price in n digits of precision
// to then be adjusted and converted via token decimals.
export const sqrtPriceX96ToPrice = (sqrtPriceX96: bigint): bigint => {
export const sqrtPriceX96ToPrice = (sqrtPriceX96: bigint, decimals: number): bigint => {
const sqrtPrice = sqrtPriceX96 ** 2n;
const decimals = 10n ** 18n;
const price = sqrtPrice * decimals / (1n << 192n);
const price = sqrtPrice * 10n ** BigInt(decimals) / (1n << 192n);
return price;
};

Expand Down
12 changes: 6 additions & 6 deletions web/src/stores/useStakeStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ interface StakeStore {
priceUpper: string;

// parse and set from a display amount
setPriceLower: (tick: string) => void;
setPriceUpper: (tick: string) => void;
setPriceLower: (tick: string, decimals: number) => void;
setPriceUpper: (tick: string, decimals: number) => void;
}

export const useStakeStore = create<StakeStore>((set) => ({
Expand Down Expand Up @@ -148,7 +148,7 @@ export const useStakeStore = create<StakeStore>((set) => ({
priceLower: "0",
priceUpper: "0",

setPriceLower: (price) => {
setPriceLower: (price, decimals) => {
const validNumber = !price.includes(" ") && !isNaN(Number(price)) || price === "."
// update display amount if `amount` is valid as a display number
if (!validNumber)
Expand All @@ -158,15 +158,15 @@ export const useStakeStore = create<StakeStore>((set) => ({
const priceN = Number(rawPrice);
let tick = 0;
try {
const newTick = getTickAtSqrtRatio(encodeSqrtPrice(priceN));
const newTick = getTickAtSqrtRatio(encodeSqrtPrice(priceN * 10 ** -decimals));
tick = newTick;
} catch { }
set({
tickLower: tick,
priceLower: price,
});
},
setPriceUpper: (price) => {
setPriceUpper: (price, decimals) => {
const validNumber = !price.includes(" ") && !isNaN(Number(price)) || price === "."
// update display amount if `amount` is valid as a display number
if (!validNumber)
Expand All @@ -176,7 +176,7 @@ export const useStakeStore = create<StakeStore>((set) => ({
const priceN = Number(rawPrice);
let tick = 0;
try {
const newTick = getTickAtSqrtRatio(encodeSqrtPrice(priceN));
const newTick = getTickAtSqrtRatio(encodeSqrtPrice(priceN * 10 ** -decimals));
tick = newTick;
} catch { }
set({
Expand Down

0 comments on commit a41f9d6

Please sign in to comment.