From 9660c35105bb78772c8af0fab307e61bb31ce670 Mon Sep 17 00:00:00 2001 From: strobie <0xstrobe@protonmail.com> Date: Fri, 30 Aug 2024 01:30:33 +0200 Subject: [PATCH 1/4] implement naive position editing recipe --- src/recipes/edit-position.ts | 98 ++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 src/recipes/edit-position.ts diff --git a/src/recipes/edit-position.ts b/src/recipes/edit-position.ts new file mode 100644 index 0000000..da308a9 --- /dev/null +++ b/src/recipes/edit-position.ts @@ -0,0 +1,98 @@ +import { TransactionResponse } from "ethers"; +import { OrderDirective } from "../encoding/longform"; +import { CrocPoolView } from "../pool"; +import { tickToPrice } from "../utils"; +import { baseTokenForConcLiq, quoteTokenForConcLiq } from "../utils/liquidity"; +import { GAS_PADDING } from "../utils"; +import { ensureChain } from "../context"; + +interface EditPositionTarget { + mint: TickRange + burn: TickRange + liquidity: bigint +} + +type TickRange = [number, number] + +export interface CrocEditPositionOpts { + impact?: number +} + +export class CrocEditPosition { + constructor(pool: CrocPoolView, target: EditPositionTarget, opts: CrocEditPositionOpts = {}) { + this.pool = pool; + this.burnRange = target.burn; + this.mintRange = target.mint; + this.liquidity = target.liquidity; + this.spotPrice = this.pool.spotPrice(); + this.spotTick = this.pool.spotTick(); + this.impact = opts?.impact || DEFAULT_EDIT_SLIPPAGE; + } + + async edit(): Promise { + const directive = await this.formatDirective(); + const cntx = await this.pool.context; + const path = cntx.chain.proxyPaths.long; + await ensureChain(cntx); + const gasEst = await cntx.dex.userCmd.estimateGas(path, directive.encodeBytes()); + return cntx.dex.userCmd(path, directive.encodeBytes(), { gasLimit: gasEst + GAS_PADDING, chainId: cntx.chain.chainId }); + } + + async simStatic() { + const directive = await this.formatDirective(); + const path = (await this.pool.context).chain.proxyPaths.long; + return (await this.pool.context).dex.userCmd.staticCall(path, directive.encodeBytes()); + } + + async currentCollateral(): Promise<[bigint, bigint]> { + const baseAmount = baseTokenForConcLiq(await this.spotPrice, this.liquidity, + tickToPrice(this.burnRange[0]), tickToPrice(this.burnRange[1])); + const quoteAmount = quoteTokenForConcLiq(await this.spotPrice, this.liquidity, + tickToPrice(this.burnRange[0]), tickToPrice(this.burnRange[1])); + return [baseAmount, quoteAmount]; + } + + async newCollateral(): Promise<[bigint, bigint]> { + const baseAmount = baseTokenForConcLiq(await this.spotPrice, this.liquidity, + tickToPrice(this.mintRange[0]), tickToPrice(this.mintRange[1])); + const quoteAmount = quoteTokenForConcLiq(await this.spotPrice, this.liquidity, + tickToPrice(this.mintRange[0]), tickToPrice(this.mintRange[1])); + return [baseAmount, quoteAmount]; + } + + async surplus(): Promise<[bigint, bigint]> { + const [currentBase, currentQuote] = await this.currentCollateral(); + const [newBase, newQuote] = await this.newCollateral(); + return [currentBase - newBase, currentQuote - newQuote]; + } + + private async formatDirective(): Promise { + const directive = new OrderDirective(this.pool.baseToken.tokenAddr); + directive.appendHop(this.pool.quoteToken.tokenAddr); + directive.appendPool((await this.pool.context).chain.poolIndex); + + directive.appendRangeBurn(this.burnRange[0], this.burnRange[1], this.liquidity); + + const [surplusBase, surplusQuote] = await this.surplus(); + if (surplusBase > 0) { + directive.open.limitQty = surplusBase; + } else { + directive.hops[0].settlement.limitQty = surplusQuote; + } + + const mint = directive.appendRangeMint(this.mintRange[0], this.mintRange[1], this.liquidity); + mint.rollType = 5; + + return directive; + } + + pool: CrocPoolView; + burnRange: TickRange; + mintRange: TickRange; + liquidity: bigint; + spotPrice: Promise; + spotTick: Promise; + impact: number; +} + +const DEFAULT_EDIT_SLIPPAGE = .02; From 603e42c1ef2bdc7c80893aec8e4ed831d4cbcdea Mon Sep 17 00:00:00 2001 From: Ben Wolski Date: Thu, 12 Sep 2024 13:22:26 -0400 Subject: [PATCH 2/4] add export of edit-position recipe from index.ts --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index fd7ca5b..678adac 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,3 +9,4 @@ export * from "./croc"; export * from "./encoding/liquidity"; export * from "./encoding/longform"; export * from "./recipes/reposition"; +export * from "./recipes/edit-position"; From acc4fd6ed4fd8fb9232b7fab446fbd02183b25da Mon Sep 17 00:00:00 2001 From: strobie <0xstrobe@protonmail.com> Date: Thu, 3 Oct 2024 23:09:42 +0200 Subject: [PATCH 3/4] remove slippage for now --- src/recipes/edit-position.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/recipes/edit-position.ts b/src/recipes/edit-position.ts index da308a9..59f0119 100644 --- a/src/recipes/edit-position.ts +++ b/src/recipes/edit-position.ts @@ -15,7 +15,6 @@ interface EditPositionTarget { type TickRange = [number, number] export interface CrocEditPositionOpts { - impact?: number } export class CrocEditPosition { @@ -26,7 +25,6 @@ export class CrocEditPosition { this.liquidity = target.liquidity; this.spotPrice = this.pool.spotPrice(); this.spotTick = this.pool.spotTick(); - this.impact = opts?.impact || DEFAULT_EDIT_SLIPPAGE; } async edit(): Promise { @@ -92,7 +90,4 @@ export class CrocEditPosition { liquidity: bigint; spotPrice: Promise; spotTick: Promise; - impact: number; } - -const DEFAULT_EDIT_SLIPPAGE = .02; From 1daa0ab4e297c0007a68010d1ee791a953860eb4 Mon Sep 17 00:00:00 2001 From: strobie <0xstrobe@protonmail.com> Date: Fri, 4 Oct 2024 00:13:23 +0200 Subject: [PATCH 4/4] experiment --- src/recipes/edit-position.ts | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/recipes/edit-position.ts b/src/recipes/edit-position.ts index 59f0119..d9a7dea 100644 --- a/src/recipes/edit-position.ts +++ b/src/recipes/edit-position.ts @@ -2,7 +2,7 @@ import { TransactionResponse } from "ethers"; import { OrderDirective } from "../encoding/longform"; import { CrocPoolView } from "../pool"; import { tickToPrice } from "../utils"; -import { baseTokenForConcLiq, quoteTokenForConcLiq } from "../utils/liquidity"; +import { baseTokenForConcLiq, liquidityForBaseConc, liquidityForQuoteConc, quoteTokenForConcLiq } from "../utils/liquidity"; import { GAS_PADDING } from "../utils"; import { ensureChain } from "../context"; @@ -50,37 +50,37 @@ export class CrocEditPosition { return [baseAmount, quoteAmount]; } - async newCollateral(): Promise<[bigint, bigint]> { - const baseAmount = baseTokenForConcLiq(await this.spotPrice, this.liquidity, + async targetLiquidityViaBase(baseAmount: bigint): Promise { + return liquidityForBaseConc(await this.spotPrice, baseAmount, tickToPrice(this.mintRange[0]), tickToPrice(this.mintRange[1])); - const quoteAmount = quoteTokenForConcLiq(await this.spotPrice, this.liquidity, + } + + async targetLiquidityViaQuote(quoteAmount: bigint): Promise { + return liquidityForQuoteConc(await this.spotPrice, quoteAmount, tickToPrice(this.mintRange[0]), tickToPrice(this.mintRange[1])); - return [baseAmount, quoteAmount]; } - async surplus(): Promise<[bigint, bigint]> { + async targetMintParams(): Promise<[bigint, number]> { const [currentBase, currentQuote] = await this.currentCollateral(); - const [newBase, newQuote] = await this.newCollateral(); - return [currentBase - newBase, currentQuote - newQuote]; + const liquidityViaBase = await this.targetLiquidityViaBase(currentBase); + const liquidityViaQuote = await this.targetLiquidityViaQuote(currentQuote); + return liquidityViaBase < liquidityViaQuote ? [liquidityViaBase, 4] : [liquidityViaQuote, 5]; } private async formatDirective(): Promise { const directive = new OrderDirective(this.pool.baseToken.tokenAddr); directive.appendHop(this.pool.quoteToken.tokenAddr); directive.appendPool((await this.pool.context).chain.poolIndex); - + directive.appendRangeBurn(this.burnRange[0], this.burnRange[1], this.liquidity); + + const [mintLiquidity, mintRollType] = await this.targetMintParams(); - const [surplusBase, surplusQuote] = await this.surplus(); - if (surplusBase > 0) { - directive.open.limitQty = surplusBase; - } else { - directive.hops[0].settlement.limitQty = surplusQuote; - } - - const mint = directive.appendRangeMint(this.mintRange[0], this.mintRange[1], this.liquidity); - mint.rollType = 5; + const mint = directive.appendRangeMint(this.mintRange[0], this.mintRange[1], mintLiquidity); + mint.rollType = mintRollType; + directive.open.limitQty = BigInt(0) + directive.hops[0].settlement.limitQty = BigInt(0) return directive; }