diff --git a/packages/panoptic-sdk/README.md b/packages/panoptic-sdk/README.md index bf41626..d5558c0 100644 --- a/packages/panoptic-sdk/README.md +++ b/packages/panoptic-sdk/README.md @@ -22,6 +22,7 @@ Typescript SDK for Panoptic - [x] `createPanopticPool` - [x] `createPanopticCollateral` - [x] `createPanopticPosition` + - [x] `createPanopticSemiFungiblePosition` - [x] `calculatePanopticTokenID` - [x] `calculatePanopticPositionKey` - [ ] `calculatePanopticDeployNewPool` @@ -47,6 +48,7 @@ Typescript SDK for Panoptic - [x] `getPanopticCollateralPositionData` - [x] `getPanoptionLegData` - [x] `getPanopticPositionData` + - [x] `getPanopticSemiFungiblePositionData` - [x] `simulatePanopticDeployNewPool` - [x] `simulatePanopticMintOptions` - [x] `simulatePanopticBurnOptions` diff --git a/packages/panoptic-sdk/src/index.ts b/packages/panoptic-sdk/src/index.ts index f22c166..2e82eac 100644 --- a/packages/panoptic-sdk/src/index.ts +++ b/packages/panoptic-sdk/src/index.ts @@ -17,6 +17,7 @@ export { getPanopticCollateralData } from "./publicActions/getPanopticCollateral export { getPanopticCollateralPositionData } from "./publicActions/getPanopticCollateralPositionData.js"; export { getPanoptionLegData } from "./publicActions/getPanoptionLegData.js"; export { getPanopticPositionData } from "./publicActions/getPanopticPositionData.js"; +export { getPanopticSemiFungiblePositionData } from "./publicActions/getPanopticSemiFungiblePositionData.js"; export { simulatePanopticCollateralDeposit } from "./publicActions/simulatePanopticCollateralDeposit.js"; export { simulatePanopticCollateralWithdraw } from "./publicActions/simulatePanopticCollateralWithdraw.js"; diff --git a/packages/panoptic-sdk/src/publicActions/getPanopticPositionData.test.ts b/packages/panoptic-sdk/src/publicActions/getPanopticPositionData.test.ts new file mode 100644 index 0000000..7070bd7 --- /dev/null +++ b/packages/panoptic-sdk/src/publicActions/getPanopticPositionData.test.ts @@ -0,0 +1,108 @@ +import { createAmountFromString } from "reverse-mirage"; +import { createUniswapV3Tick } from "uniswap-v3-sdk"; +import { type Hex } from "viem"; +import { simulateContract, writeContract } from "viem/actions"; +import { beforeEach, expect, test } from "vitest"; +import { ALICE } from "../_test/constants.js"; +import { + deployPool, + publicClient, + testClient, + walletClient, +} from "../_test/utils.js"; +import { mockErc20ABI } from "../generated.js"; +import type { PanopticPool } from "../types/PanopticPool.js"; +import type { PanopticPosition } from "../types/PanopticPosition.js"; +import { createPanopticPosition } from "../utils/createPanopticPosition.js"; +import { getPanopticPositionData } from "./getPanopticPositionData.js"; +import { simulatePanopticCollateralDeposit } from "./simulatePanopticCollateralDeposit.js"; +import { simulatePanopticMintOptions } from "./simulatePanopticMintOptions.js"; +import { simulatePanopticSFPMInitializeAMMPool } from "./simulatePanopticSFPMInitializeAMMPool.js"; + +let id: Hex | undefined = undefined; + +let pool: PanopticPool; + +let position: PanopticPosition; + +beforeEach(async () => { + if (id === undefined) { + pool = await deployPool(); + const { request: initializeRequest } = + await simulatePanopticSFPMInitializeAMMPool(publicClient, { + args: { + pool: pool.uniswapPool, + sfpm: pool.factory.semiFungiblePositionManager, + }, + }); + + const initializeHash = await walletClient.writeContract(initializeRequest); + await publicClient.waitForTransactionReceipt({ hash: initializeHash }); + + const { request: approveRequest } = await simulateContract(publicClient, { + address: pool.collateralTracker0.underlyingToken.address, + abi: mockErc20ABI, + functionName: "approve", + args: [pool.collateralTracker0.address, 10n ** 18n], + account: ALICE, + }); + + const approveHash = await writeContract(walletClient, approveRequest); + await publicClient.waitForTransactionReceipt({ hash: approveHash }); + + const { request: depositRequest } = await simulatePanopticCollateralDeposit( + publicClient, + { + args: { + collateral: pool.collateralTracker0, + amount: createAmountFromString( + pool.collateralTracker0.underlyingToken, + "1", + ), + to: ALICE, + }, + account: ALICE, + }, + ); + + const depositHash = await writeContract(walletClient, depositRequest); + await publicClient.waitForTransactionReceipt({ hash: depositHash }); + + position = createPanopticPosition(ALICE, pool, [ + { + asset: "token0", + optionRatio: 1, + position: "short", + tokenType: "token0", + riskPartnerIndex: 0, + tickLower: createUniswapV3Tick(0), + tickUpper: createUniswapV3Tick(10), + }, + undefined, + undefined, + undefined, + ]); + + const { request } = await simulatePanopticMintOptions(publicClient, { + args: { + position, + amount: 5n * 10n ** 17n, + }, + account: ALICE, + }); + const hash = await walletClient.writeContract(request); + await publicClient.waitForTransactionReceipt({ hash }); + } else { + await testClient.revert({ id }); + } + id = await testClient.snapshot(); +}, 100_000); + +test("get position data", async () => { + const positionData = await getPanopticPositionData(publicClient, { + position, + }); + + expect(positionData.position).toStrictEqual(position); + expect(positionData.amount).toBe(5n * 10n ** 17n); +}); diff --git a/packages/panoptic-sdk/src/publicActions/getPanopticPositionData.ts b/packages/panoptic-sdk/src/publicActions/getPanopticPositionData.ts index b99291f..a608fa4 100644 --- a/packages/panoptic-sdk/src/publicActions/getPanopticPositionData.ts +++ b/packages/panoptic-sdk/src/publicActions/getPanopticPositionData.ts @@ -1,5 +1,4 @@ import { createFraction } from "reverse-mirage"; -import type { UniswapV3Tick } from "uniswap-v3-sdk"; import type { Chain, Client, ReadContractParameters, Transport } from "viem"; import { readContract } from "viem/actions"; import { panopticPoolABI } from "../generated.js"; @@ -7,71 +6,41 @@ import type { PanopticPosition, PanopticPositionData, } from "../types/PanopticPosition.js"; -import { getPanoptionLegData } from "./getPanoptionLegData.js"; export type GetPanopticPositionDataParameters = Omit< ReadContractParameters, "address" | "abi" | "functionName" | "args" > & { - panopticPosition: PanopticPosition; - tick: UniswapV3Tick; + position: PanopticPosition; }; export type GetPanopticPositionDataReturnType = PanopticPositionData; export const getPanopticPositionData = ( client: Client, - { panopticPosition, tick, ...request }: GetPanopticPositionDataParameters, + { position, ...request }: GetPanopticPositionDataParameters, ): Promise => Promise.all([ readContract(client, { abi: panopticPoolABI, functionName: "optionPositionBalance", - address: panopticPosition.pool.address, - args: [panopticPosition.address, panopticPosition.id], + address: position.pool.address, + args: [position.owner, position.id], ...request, }), - panopticPosition.legs[0] - ? getPanoptionLegData(client, { - leg: panopticPosition.legs[0], - address: panopticPosition.address, - pool: panopticPosition.pool, - tick, - ...request, - }) - : undefined, - panopticPosition.legs[1] - ? getPanoptionLegData(client, { - leg: panopticPosition.legs[1], - address: panopticPosition.address, - pool: panopticPosition.pool, - tick, - ...request, - }) - : undefined, - panopticPosition.legs[2] - ? getPanoptionLegData(client, { - leg: panopticPosition.legs[2], - address: panopticPosition.address, - pool: panopticPosition.pool, - tick, - ...request, - }) - : undefined, - panopticPosition.legs[3] - ? getPanoptionLegData(client, { - leg: panopticPosition.legs[3], - address: panopticPosition.address, - pool: panopticPosition.pool, - tick, - ...request, - }) - : undefined, - ] as const).then(([optionsBalance, leg0, leg1, leg2, leg3]) => ({ + readContract(client, { + abi: panopticPoolABI, + functionName: "calculateAccumulatedFeesBatch", + address: position.pool.address, + args: [position.owner, [position.id]], + ...request, + }), + ] as const).then(([optionsBalance, accumumlatedFees]) => ({ type: "panopticPositionData", + position, amount: optionsBalance[0], token0Utilization: createFraction(optionsBalance[1], 2n ** 64n), token1Utilization: createFraction(optionsBalance[2], 2n ** 64n), - token: panopticPosition, - legData: [leg0, leg1, leg2, leg3], + premium0: accumumlatedFees[0], + premium1: accumumlatedFees[1], })); diff --git a/packages/panoptic-sdk/src/publicActions/getPanopticSemiFungiblePositionData.test.ts b/packages/panoptic-sdk/src/publicActions/getPanopticSemiFungiblePositionData.test.ts new file mode 100644 index 0000000..104bb6e --- /dev/null +++ b/packages/panoptic-sdk/src/publicActions/getPanopticSemiFungiblePositionData.test.ts @@ -0,0 +1,99 @@ +import { createUniswapV3Tick } from "uniswap-v3-sdk"; +import { type Hex } from "viem"; +import { simulateContract, writeContract } from "viem/actions"; +import { sepolia } from "viem/chains"; +import { beforeEach, expect, test } from "vitest"; +import { ALICE } from "../_test/constants.js"; +import { + deployPool, + publicClient, + testClient, + walletClient, +} from "../_test/utils.js"; +import { mockErc20ABI } from "../generated.js"; +import type { PanopticPool } from "../types/PanopticPool.js"; +import type { PanopticSemiFungiblePosition } from "../types/PanopticSemiFungiblePositionManager.js"; +import { createPanopticSemiFungiblePosition } from "../utils/createPanopticSemiFungiblePosition.js"; +import { getPanopticSemiFungiblePositionData } from "./getPanopticSemiFungiblePositionData.js"; +import { simulatePanopticSFPMInitializeAMMPool } from "./simulatePanopticSFPMInitializeAMMPool.js"; +import { simulatePanopticSFPMMintTokenizedPosition } from "./simulatePanopticSFPMMintTokenizedPosition.js"; + +let id: Hex | undefined = undefined; + +let pool: PanopticPool; + +let position: PanopticSemiFungiblePosition; + +beforeEach(async () => { + if (id === undefined) { + pool = await deployPool(); + const { request: initializeRequest } = + await simulatePanopticSFPMInitializeAMMPool(publicClient, { + args: { + pool: pool.uniswapPool, + sfpm: pool.factory.semiFungiblePositionManager, + }, + }); + + const initializeHash = await walletClient.writeContract(initializeRequest); + await publicClient.waitForTransactionReceipt({ hash: initializeHash }); + + const { request: approveRequest } = await simulateContract(publicClient, { + address: pool.collateralTracker0.underlyingToken.address, + abi: mockErc20ABI, + functionName: "approve", + args: [pool.factory.semiFungiblePositionManager.address, 10n ** 18n], + account: ALICE, + }); + + const approveHash = await writeContract(walletClient, approveRequest); + await publicClient.waitForTransactionReceipt({ hash: approveHash }); + + position = createPanopticSemiFungiblePosition( + ALICE, + pool.factory.semiFungiblePositionManager, + [ + { + asset: "token0", + optionRatio: 1, + position: "short", + tokenType: "token0", + riskPartnerIndex: 0, + tickLower: createUniswapV3Tick(0), + tickUpper: createUniswapV3Tick(10), + }, + undefined, + undefined, + undefined, + ], + pool.uniswapPool, + sepolia.id, + ); + + const { request } = await simulatePanopticSFPMMintTokenizedPosition( + publicClient, + { + args: { + position, + amount: 10n ** 18n, + }, + account: ALICE, + }, + ); + const hash = await walletClient.writeContract(request); + await publicClient.waitForTransactionReceipt({ hash }); + } else { + await testClient.revert({ id }); + } + id = await testClient.snapshot(); +}, 100_000); + +test("get sfpm position data", async () => { + const positionData = await getPanopticSemiFungiblePositionData(publicClient, { + position, + tick: createUniswapV3Tick(0), + }); + + expect(positionData.amount).toBe(10n ** 18n); + expect(positionData.token).toStrictEqual(position); +}); diff --git a/packages/panoptic-sdk/src/publicActions/getPanopticSemiFungiblePositionData.ts b/packages/panoptic-sdk/src/publicActions/getPanopticSemiFungiblePositionData.ts new file mode 100644 index 0000000..375f526 --- /dev/null +++ b/packages/panoptic-sdk/src/publicActions/getPanopticSemiFungiblePositionData.ts @@ -0,0 +1,84 @@ +import type { UniswapV3Tick } from "uniswap-v3-sdk"; +import type { Chain, Client, ReadContractParameters, Transport } from "viem"; +import { readContract } from "viem/actions"; +import { + panopticPoolABI, + semiFungiblePositionManagerABI, +} from "../generated.js"; +import type { + PanopticSemiFungiblePosition, + PanopticSemiFungiblePositionData, +} from "../types/PanopticSemiFungiblePositionManager.js"; +import { getPanoptionLegData } from "./getPanoptionLegData.js"; + +export type GetPanopticSemiFungiblePositionDataParameters = Omit< + ReadContractParameters, + "address" | "abi" | "functionName" | "args" +> & { + position: PanopticSemiFungiblePosition; + tick: UniswapV3Tick; +}; + +export type GetPanopticSemiFungiblePositionDataReturnType = + PanopticSemiFungiblePositionData; + +export const getPanopticSemiFungiblePositionData = < + TChain extends Chain | undefined, +>( + client: Client, + { position, tick, ...request }: GetPanopticSemiFungiblePositionDataParameters, +): Promise => + Promise.all([ + readContract(client, { + abi: semiFungiblePositionManagerABI, + functionName: "balanceOf", + address: position.address, + args: [position.owner, position.id], + ...request, + }), + position.legs[0] + ? getPanoptionLegData(client, { + leg: position.legs[0], + address: position.address, + owner: position.owner, + uniswapPool: position.uniswapPool, + tick, + ...request, + }) + : undefined, + position.legs[1] + ? getPanoptionLegData(client, { + leg: position.legs[1], + address: position.address, + owner: position.owner, + uniswapPool: position.uniswapPool, + tick, + ...request, + }) + : undefined, + position.legs[2] + ? getPanoptionLegData(client, { + leg: position.legs[2], + address: position.address, + owner: position.owner, + uniswapPool: position.uniswapPool, + tick, + ...request, + }) + : undefined, + position.legs[3] + ? getPanoptionLegData(client, { + leg: position.legs[3], + address: position.address, + owner: position.owner, + uniswapPool: position.uniswapPool, + tick, + ...request, + }) + : undefined, + ] as const).then(([balance, leg0, leg1, leg2, leg3]) => ({ + type: "panopticSemiFungiblePositionData", + token: position, + amount: balance, + legData: [leg0, leg1, leg2, leg3], + })); diff --git a/packages/panoptic-sdk/src/publicActions/getPanoptionLegData.test.ts b/packages/panoptic-sdk/src/publicActions/getPanoptionLegData.test.ts index 1a04d16..597b944 100644 --- a/packages/panoptic-sdk/src/publicActions/getPanoptionLegData.test.ts +++ b/packages/panoptic-sdk/src/publicActions/getPanoptionLegData.test.ts @@ -12,8 +12,8 @@ import { } from "../_test/utils.js"; import { mockErc20ABI } from "../generated.js"; import type { PanopticPool } from "../types/PanopticPool.js"; -import type { PanopticPosition } from "../types/PanopticPosition.js"; -import { createPanopticPosition } from "../utils/createPanopticPosition.js"; +import type { PanopticSemiFungiblePosition } from "../types/PanopticSemiFungiblePositionManager.js"; +import { createPanopticSemiFungiblePosition } from "../utils/createPanopticSemiFungiblePosition.js"; import { getPanoptionLegData } from "./getPanoptionLegData.js"; import { simulatePanopticSFPMInitializeAMMPool } from "./simulatePanopticSFPMInitializeAMMPool.js"; import { simulatePanopticSFPMMintTokenizedPosition } from "./simulatePanopticSFPMMintTokenizedPosition.js"; @@ -21,7 +21,7 @@ import { simulatePanopticSFPMMintTokenizedPosition } from "./simulatePanopticSFP let id: Hex | undefined = undefined; let pool: PanopticPool; -let position: PanopticPosition; +let position: PanopticSemiFungiblePosition; beforeEach(async () => { if (id === undefined) { @@ -48,9 +48,9 @@ beforeEach(async () => { const approveHash = await writeContract(walletClient, approveRequest); await publicClient.waitForTransactionReceipt({ hash: approveHash }); - position = createPanopticPosition( + position = createPanopticSemiFungiblePosition( ALICE, - pool, + pool.factory.semiFungiblePositionManager, [ { asset: "token0", @@ -65,6 +65,7 @@ beforeEach(async () => { undefined, undefined, ], + pool.uniswapPool, sepolia.id, ); @@ -88,9 +89,10 @@ beforeEach(async () => { test("get leg data", async () => { const legData = await getPanoptionLegData(publicClient, { + address: pool.factory.semiFungiblePositionManager.address, + owner: ALICE, leg: position.legs[0]!, - address: ALICE, - pool: pool, + uniswapPool: pool.uniswapPool, tick: createUniswapV3Tick(0), }); diff --git a/packages/panoptic-sdk/src/publicActions/getPanoptionLegData.ts b/packages/panoptic-sdk/src/publicActions/getPanoptionLegData.ts index 2d6df89..e2cd682 100644 --- a/packages/panoptic-sdk/src/publicActions/getPanoptionLegData.ts +++ b/packages/panoptic-sdk/src/publicActions/getPanoptionLegData.ts @@ -1,4 +1,4 @@ -import type { UniswapV3Tick } from "uniswap-v3-sdk"; +import type { UniswapV3Pool, UniswapV3Tick } from "uniswap-v3-sdk"; import type { Address, Chain, @@ -9,7 +9,6 @@ import type { import { readContract } from "viem/actions"; import { panopticPoolABI } from "../generated.js"; import { semiFungiblePositionManagerABI } from "../generated.js"; -import type { PanopticPool } from "../types/PanopticPool.js"; import type { PanoptionLeg, PanoptionLegData, @@ -20,9 +19,10 @@ export type GetPanoptionLegDataParameters = Omit< ReadContractParameters, "address" | "abi" | "functionName" | "args" > & { - leg: PanoptionLeg; address: Address; - pool: PanopticPool; + owner: Address; + leg: PanoptionLeg; + uniswapPool: UniswapV3Pool; tick: UniswapV3Tick; }; @@ -30,16 +30,23 @@ export type GetPanoptionLegDataReturnType = PanoptionLegData; export const getPanoptionLegData = ( client: Client, - { leg, pool, address, tick, ...request }: GetPanoptionLegDataParameters, + { + address, + owner, + leg, + uniswapPool, + tick, + ...request + }: GetPanoptionLegDataParameters, ): Promise => Promise.all([ readContract(client, { abi: semiFungiblePositionManagerABI, functionName: "getAccountLiquidity", - address: pool.factory.semiFungiblePositionManager.address, + address, args: [ - pool.uniswapPool.address, - address, + uniswapPool.address, + owner, leg.tokenType === "token0" ? 0n : 1n, leg.tickLower.tick, leg.tickUpper.tick, @@ -49,10 +56,10 @@ export const getPanoptionLegData = ( readContract(client, { abi: semiFungiblePositionManagerABI, functionName: "getAccountPremium", - address: pool.factory.semiFungiblePositionManager.address, + address, args: [ - pool.uniswapPool.address, - address, + uniswapPool.address, + owner, leg.tokenType === "token0" ? 0n : 1n, leg.tickLower.tick, leg.tickUpper.tick, @@ -64,10 +71,10 @@ export const getPanoptionLegData = ( readContract(client, { abi: semiFungiblePositionManagerABI, functionName: "getAccountFeesBase", - address: pool.factory.semiFungiblePositionManager.address, + address, args: [ - pool.uniswapPool.address, - address, + uniswapPool.address, + owner, leg.tokenType === "token0" ? 0n : 1n, leg.tickLower.tick, leg.tickUpper.tick, diff --git a/packages/panoptic-sdk/src/publicActions/simulatePanopticBurnOptions.test.ts b/packages/panoptic-sdk/src/publicActions/simulatePanopticBurnOptions.test.ts index 508f05b..d4cf0ca 100644 --- a/packages/panoptic-sdk/src/publicActions/simulatePanopticBurnOptions.test.ts +++ b/packages/panoptic-sdk/src/publicActions/simulatePanopticBurnOptions.test.ts @@ -2,7 +2,6 @@ import { createAmountFromString } from "reverse-mirage"; import { createUniswapV3Tick } from "uniswap-v3-sdk"; import { type Hex } from "viem"; import { simulateContract, writeContract } from "viem/actions"; -import { sepolia } from "viem/chains"; import { beforeEach, test } from "vitest"; import { ALICE } from "../_test/constants.js"; import { @@ -68,25 +67,20 @@ beforeEach(async () => { const depositHash = await writeContract(walletClient, depositRequest); await publicClient.waitForTransactionReceipt({ hash: depositHash }); - position = createPanopticPosition( - ALICE, - pool, - [ - { - asset: "token0", - optionRatio: 1, - position: "short", - tokenType: "token0", - riskPartnerIndex: 0, - tickLower: createUniswapV3Tick(0), - tickUpper: createUniswapV3Tick(10), - }, - undefined, - undefined, - undefined, - ], - sepolia.id, - ); + position = createPanopticPosition(ALICE, pool, [ + { + asset: "token0", + optionRatio: 1, + position: "short", + tokenType: "token0", + riskPartnerIndex: 0, + tickLower: createUniswapV3Tick(0), + tickUpper: createUniswapV3Tick(10), + }, + undefined, + undefined, + undefined, + ]); const { request } = await simulatePanopticMintOptions(publicClient, { args: { diff --git a/packages/panoptic-sdk/src/publicActions/simulatePanopticMintOptions.test.ts b/packages/panoptic-sdk/src/publicActions/simulatePanopticMintOptions.test.ts index 2375e36..6afffe7 100644 --- a/packages/panoptic-sdk/src/publicActions/simulatePanopticMintOptions.test.ts +++ b/packages/panoptic-sdk/src/publicActions/simulatePanopticMintOptions.test.ts @@ -2,7 +2,6 @@ import { createAmountFromString } from "reverse-mirage"; import { createUniswapV3Tick } from "uniswap-v3-sdk"; import { type Hex } from "viem"; import { simulateContract, writeContract } from "viem/actions"; -import { sepolia } from "viem/chains"; import { beforeEach, test } from "vitest"; import { ALICE } from "../_test/constants.js"; import { @@ -71,25 +70,20 @@ beforeEach(async () => { }, 100_000); test("mint options", async () => { - const position = createPanopticPosition( - ALICE, - pool, - [ - { - asset: "token0", - optionRatio: 1, - position: "short", - tokenType: "token0", - riskPartnerIndex: 0, - tickLower: createUniswapV3Tick(0), - tickUpper: createUniswapV3Tick(10), - }, - undefined, - undefined, - undefined, - ], - sepolia.id, - ); + const position = createPanopticPosition(ALICE, pool, [ + { + asset: "token0", + optionRatio: 1, + position: "short", + tokenType: "token0", + riskPartnerIndex: 0, + tickLower: createUniswapV3Tick(0), + tickUpper: createUniswapV3Tick(10), + }, + undefined, + undefined, + undefined, + ]); const { request } = await simulatePanopticMintOptions(publicClient, { args: { diff --git a/packages/panoptic-sdk/src/publicActions/simulatePanopticRollOptions.test.ts b/packages/panoptic-sdk/src/publicActions/simulatePanopticRollOptions.test.ts index 4d54ed3..a977261 100644 --- a/packages/panoptic-sdk/src/publicActions/simulatePanopticRollOptions.test.ts +++ b/packages/panoptic-sdk/src/publicActions/simulatePanopticRollOptions.test.ts @@ -2,7 +2,6 @@ import { createAmountFromString } from "reverse-mirage"; import { createUniswapV3Tick } from "uniswap-v3-sdk"; import { type Hex } from "viem"; import { simulateContract, writeContract } from "viem/actions"; -import { sepolia } from "viem/chains"; import { beforeEach, test } from "vitest"; import { ALICE } from "../_test/constants.js"; import { @@ -68,25 +67,20 @@ beforeEach(async () => { const depositHash = await writeContract(walletClient, depositRequest); await publicClient.waitForTransactionReceipt({ hash: depositHash }); - position = createPanopticPosition( - ALICE, - pool, - [ - { - asset: "token0", - optionRatio: 1, - position: "short", - tokenType: "token0", - riskPartnerIndex: 0, - tickLower: createUniswapV3Tick(0), - tickUpper: createUniswapV3Tick(10), - }, - undefined, - undefined, - undefined, - ], - sepolia.id, - ); + position = createPanopticPosition(ALICE, pool, [ + { + asset: "token0", + optionRatio: 1, + position: "short", + tokenType: "token0", + riskPartnerIndex: 0, + tickLower: createUniswapV3Tick(0), + tickUpper: createUniswapV3Tick(10), + }, + undefined, + undefined, + undefined, + ]); const { request } = await simulatePanopticMintOptions(publicClient, { args: { @@ -104,25 +98,20 @@ beforeEach(async () => { }, 100_000); test("burn options", async () => { - const newPosition = createPanopticPosition( - ALICE, - pool, - [ - { - asset: "token0", - optionRatio: 1, - position: "short", - tokenType: "token0", - riskPartnerIndex: 0, - tickLower: createUniswapV3Tick(10), - tickUpper: createUniswapV3Tick(20), - }, - undefined, - undefined, - undefined, - ], - sepolia.id, - ); + const newPosition = createPanopticPosition(ALICE, pool, [ + { + asset: "token0", + optionRatio: 1, + position: "short", + tokenType: "token0", + riskPartnerIndex: 0, + tickLower: createUniswapV3Tick(10), + tickUpper: createUniswapV3Tick(20), + }, + undefined, + undefined, + undefined, + ]); const { request } = await simulatePanopticRollOptions(publicClient, { args: { diff --git a/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMBurnTokenizedPosition.test.ts b/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMBurnTokenizedPosition.test.ts index 058fc58..b82904c 100644 --- a/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMBurnTokenizedPosition.test.ts +++ b/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMBurnTokenizedPosition.test.ts @@ -13,8 +13,8 @@ import { } from "../_test/utils.js"; import { mockErc20ABI } from "../generated.js"; import type { PanopticPool } from "../types/PanopticPool.js"; -import type { PanopticPosition } from "../types/PanopticPosition.js"; -import { createPanopticPosition } from "../utils/createPanopticPosition.js"; +import type { PanopticSemiFungiblePosition } from "../types/PanopticSemiFungiblePositionManager.js"; +import { createPanopticSemiFungiblePosition } from "../utils/createPanopticSemiFungiblePosition.js"; import { simulatePanopticSFPMBurnTokenizedPosition } from "./simulatePanopticSFPMBurnTokenizedPosition.js"; import { simulatePanopticSFPMInitializeAMMPool } from "./simulatePanopticSFPMInitializeAMMPool.js"; import { simulatePanopticSFPMMintTokenizedPosition } from "./simulatePanopticSFPMMintTokenizedPosition.js"; @@ -23,7 +23,7 @@ let id: Hex | undefined = undefined; let pool: PanopticPool; -let position: PanopticPosition; +let position: PanopticSemiFungiblePosition; beforeEach(async () => { if (id === undefined) { @@ -50,9 +50,9 @@ beforeEach(async () => { const approveHash = await writeContract(walletClient, approveRequest); await publicClient.waitForTransactionReceipt({ hash: approveHash }); - position = createPanopticPosition( + position = createPanopticSemiFungiblePosition( ALICE, - pool, + pool.factory.semiFungiblePositionManager, [ { asset: "token0", @@ -67,6 +67,7 @@ beforeEach(async () => { undefined, undefined, ], + pool.uniswapPool, sepolia.id, ); diff --git a/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMBurnTokenizedPosition.ts b/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMBurnTokenizedPosition.ts index 507b907..02acb0f 100644 --- a/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMBurnTokenizedPosition.ts +++ b/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMBurnTokenizedPosition.ts @@ -8,10 +8,10 @@ import type { } from "viem"; import { simulateContract } from "viem/contract"; import { semiFungiblePositionManagerABI } from "../generated.js"; -import type { PanopticPosition } from "../types/PanopticPosition.js"; +import type { PanopticSemiFungiblePosition } from "../types/PanopticSemiFungiblePositionManager.js"; export type PanopticSFPMBurnTokenizedPositionParameters = { - position: PanopticPosition; + position: PanopticSemiFungiblePosition; amount: bigint; }; @@ -54,7 +54,7 @@ export const simulatePanopticSFPMBurnTokenizedPosition = < SimulatePanopticSFPMBurnTokenizedPositionReturnType > => simulateContract(client, { - address: position.pool.factory.semiFungiblePositionManager.address, + address: position.address, abi: semiFungiblePositionManagerABI, functionName: "burnTokenizedPosition", args: [position.id, amount, MIN_TICK, MAX_TICK], diff --git a/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMMintTokenizedPosition.test.ts b/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMMintTokenizedPosition.test.ts index ca402cb..943dc60 100644 --- a/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMMintTokenizedPosition.test.ts +++ b/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMMintTokenizedPosition.test.ts @@ -13,7 +13,7 @@ import { } from "../_test/utils.js"; import { mockErc20ABI } from "../generated.js"; import type { PanopticPool } from "../types/PanopticPool.js"; -import { createPanopticPosition } from "../utils/createPanopticPosition.js"; +import { createPanopticSemiFungiblePosition } from "../utils/createPanopticSemiFungiblePosition.js"; import { simulatePanopticSFPMInitializeAMMPool } from "./simulatePanopticSFPMInitializeAMMPool.js"; import { simulatePanopticSFPMMintTokenizedPosition } from "./simulatePanopticSFPMMintTokenizedPosition.js"; @@ -52,9 +52,9 @@ beforeEach(async () => { }, 100_000); test("mint tokenized position", async () => { - const position = createPanopticPosition( + const position = createPanopticSemiFungiblePosition( ALICE, - pool, + pool.factory.semiFungiblePositionManager, [ { asset: "token0", @@ -69,6 +69,7 @@ test("mint tokenized position", async () => { undefined, undefined, ], + pool.uniswapPool, sepolia.id, ); diff --git a/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMMintTokenizedPosition.ts b/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMMintTokenizedPosition.ts index d85611b..36e6e6e 100644 --- a/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMMintTokenizedPosition.ts +++ b/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMMintTokenizedPosition.ts @@ -8,10 +8,10 @@ import type { } from "viem"; import { simulateContract } from "viem/contract"; import { semiFungiblePositionManagerABI } from "../generated.js"; -import type { PanopticPosition } from "../types/PanopticPosition.js"; +import type { PanopticSemiFungiblePosition } from "../types/PanopticSemiFungiblePositionManager.js"; export type PanopticSFPMMintTokenizedPositionParameters = { - position: PanopticPosition; + position: PanopticSemiFungiblePosition; amount: bigint; }; @@ -54,7 +54,7 @@ export const simulatePanopticSFPMMintTokenizedPosition = < SimulatePanopticSFPMMintTokenizedPositionReturnType > => simulateContract(client, { - address: position.pool.factory.semiFungiblePositionManager.address, + address: position.address, abi: semiFungiblePositionManagerABI, functionName: "mintTokenizedPosition", args: [position.id, amount, MIN_TICK, MAX_TICK], diff --git a/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMRollTokenizedPositions.test.ts b/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMRollTokenizedPositions.test.ts index 67cae51..3164419 100644 --- a/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMRollTokenizedPositions.test.ts +++ b/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMRollTokenizedPositions.test.ts @@ -13,8 +13,8 @@ import { } from "../_test/utils.js"; import { mockErc20ABI } from "../generated.js"; import type { PanopticPool } from "../types/PanopticPool.js"; -import type { PanopticPosition } from "../types/PanopticPosition.js"; -import { createPanopticPosition } from "../utils/createPanopticPosition.js"; +import type { PanopticSemiFungiblePosition } from "../types/PanopticSemiFungiblePositionManager.js"; +import { createPanopticSemiFungiblePosition } from "../utils/createPanopticSemiFungiblePosition.js"; import { simulatePanopticSFPMInitializeAMMPool } from "./simulatePanopticSFPMInitializeAMMPool.js"; import { simulatePanopticSFPMMintTokenizedPosition } from "./simulatePanopticSFPMMintTokenizedPosition.js"; import { simulatePanopticSFPMRollTokenizedPositions } from "./simulatePanopticSFPMRollTokenizedPositions.js"; @@ -23,7 +23,7 @@ let id: Hex | undefined = undefined; let pool: PanopticPool; -let position: PanopticPosition; +let position: PanopticSemiFungiblePosition; beforeEach(async () => { if (id === undefined) { @@ -50,9 +50,9 @@ beforeEach(async () => { const approveHash = await writeContract(walletClient, approveRequest); await publicClient.waitForTransactionReceipt({ hash: approveHash }); - position = createPanopticPosition( + position = createPanopticSemiFungiblePosition( ALICE, - pool, + pool.factory.semiFungiblePositionManager, [ { asset: "token0", @@ -67,6 +67,7 @@ beforeEach(async () => { undefined, undefined, ], + pool.uniswapPool, sepolia.id, ); @@ -89,9 +90,9 @@ beforeEach(async () => { }, 100_000); test("roll tokenized position", async () => { - const newPosition = createPanopticPosition( + const newPosition = createPanopticSemiFungiblePosition( ALICE, - pool, + pool.factory.semiFungiblePositionManager, [ { asset: "token0", @@ -106,6 +107,7 @@ test("roll tokenized position", async () => { undefined, undefined, ], + pool.uniswapPool, sepolia.id, ); diff --git a/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMRollTokenizedPositions.ts b/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMRollTokenizedPositions.ts index 34f4f54..74094a2 100644 --- a/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMRollTokenizedPositions.ts +++ b/packages/panoptic-sdk/src/publicActions/simulatePanopticSFPMRollTokenizedPositions.ts @@ -8,11 +8,11 @@ import type { } from "viem"; import { simulateContract } from "viem/contract"; import { semiFungiblePositionManagerABI } from "../generated.js"; -import type { PanopticPosition } from "../types/PanopticPosition.js"; +import type { PanopticSemiFungiblePosition } from "../types/PanopticSemiFungiblePositionManager.js"; export type PanopticSFPMRollTokenizedPositionsParameters = { - oldPosition: PanopticPosition; - newPosition: PanopticPosition; + oldPosition: PanopticSemiFungiblePosition; + newPosition: PanopticSemiFungiblePosition; amount: bigint; }; @@ -55,7 +55,7 @@ export const simulatePanopticSFPMRollTokenizedPositions = < SimulatePanopticSFPMRollTokenizedPositionsReturnType > => simulateContract(client, { - address: newPosition.pool.factory.semiFungiblePositionManager.address, + address: newPosition.address, abi: semiFungiblePositionManagerABI, functionName: "rollTokenizedPositions", args: [oldPosition.id, newPosition.id, amount, MIN_TICK, MAX_TICK], diff --git a/packages/panoptic-sdk/src/types/PanopticPosition.ts b/packages/panoptic-sdk/src/types/PanopticPosition.ts index 8a4f00a..104956e 100644 --- a/packages/panoptic-sdk/src/types/PanopticPosition.ts +++ b/packages/panoptic-sdk/src/types/PanopticPosition.ts @@ -1,4 +1,4 @@ -import type { BaseERC1155, ERC1155Data, Fraction, Tuple } from "reverse-mirage"; +import type { Fraction, Tuple } from "reverse-mirage"; import type { UniswapV3Tick } from "uniswap-v3-sdk"; import type { Address } from "viem/accounts"; import type { PanopticPool } from "./PanopticPool.js"; @@ -13,8 +13,10 @@ export type PanoptionLeg = { tickUpper: UniswapV3Tick; }; -export type PanopticPosition = BaseERC1155<"panopticPosition"> & { +export type PanopticPosition = { + type: "panopticPosition"; owner: Address; + id: bigint; pool: PanopticPool; legs: Tuple; }; @@ -28,8 +30,12 @@ export type PanoptionLegData = { baseFee1: bigint; }; -export type PanopticPositionData = ERC1155Data & { +export type PanopticPositionData = { + type: "panopticPositionData"; + position: PanopticPosition; + amount: bigint; token0Utilization: Fraction; token1Utilization: Fraction; - legData: Tuple; + premium0: bigint; + premium1: bigint; }; diff --git a/packages/panoptic-sdk/src/types/PanopticSemiFungiblePositionManager.ts b/packages/panoptic-sdk/src/types/PanopticSemiFungiblePositionManager.ts index 197b685..7576d56 100644 --- a/packages/panoptic-sdk/src/types/PanopticSemiFungiblePositionManager.ts +++ b/packages/panoptic-sdk/src/types/PanopticSemiFungiblePositionManager.ts @@ -1,7 +1,25 @@ +import type { BaseERC1155, ERC1155Data, Tuple } from "reverse-mirage"; +import type { UniswapV3Pool } from "uniswap-v3-sdk"; import type { Address } from "viem/accounts"; +import type { PanoptionLeg, PanoptionLegData } from "./PanopticPosition.js"; export type PanopticSemiFungiblePositionManager = { type: "panopticSemiFungiblePositionManager"; address: Address; blockCreated: bigint; }; + +export type PanopticSemiFungiblePosition = + BaseERC1155<"panopticSemiFungiblePosition"> & { + owner: Address; + uniswapPool: UniswapV3Pool; + legs: Tuple; + }; + +export type PanopticSemiFungiblePositionData = + ERC1155Data & { + legData: Tuple< + Omit | undefined, + 4 + >; + }; diff --git a/packages/panoptic-sdk/src/utils/calculatePanopticTokenID.ts b/packages/panoptic-sdk/src/utils/calculatePanopticTokenID.ts index 2620b32..a1e84e5 100644 --- a/packages/panoptic-sdk/src/utils/calculatePanopticTokenID.ts +++ b/packages/panoptic-sdk/src/utils/calculatePanopticTokenID.ts @@ -1,6 +1,5 @@ import type { Tuple } from "reverse-mirage"; -import type { TickSpacing } from "uniswap-v3-sdk"; -import type { PanopticPool } from "../types/PanopticPool.js"; +import type { TickSpacing, UniswapV3Pool } from "uniswap-v3-sdk"; import type { PanoptionLeg } from "../types/PanopticPosition.js"; export const calculateLegID = (leg: PanoptionLeg, tickSpacing: TickSpacing) => { @@ -16,22 +15,20 @@ export const calculateLegID = (leg: PanoptionLeg, tickSpacing: TickSpacing) => { }; export const calculatePanopticTokenID = ( - pool: PanopticPool, + uniswapPool: UniswapV3Pool, legs: Tuple, ) => { let id = 0n; - id |= (BigInt(pool.uniswapPool.address) >> 96n) & 0xffffffffffffffffn; - id |= legs[0] - ? calculateLegID(legs[0], pool.uniswapPool.tickSpacing) << 64n - : 0n; + id |= (BigInt(uniswapPool.address) >> 96n) & 0xffffffffffffffffn; + id |= legs[0] ? calculateLegID(legs[0], uniswapPool.tickSpacing) << 64n : 0n; id |= legs[1] - ? calculateLegID(legs[1], pool.uniswapPool.tickSpacing) << (64n + 48n) + ? calculateLegID(legs[1], uniswapPool.tickSpacing) << (64n + 48n) : 0n; id |= legs[2] - ? calculateLegID(legs[2], pool.uniswapPool.tickSpacing) << (64n + 48n + 48n) + ? calculateLegID(legs[2], uniswapPool.tickSpacing) << (64n + 48n + 48n) : 0n; id |= legs[3] - ? calculateLegID(legs[3], pool.uniswapPool.tickSpacing) << + ? calculateLegID(legs[3], uniswapPool.tickSpacing) << (64n + 48n + 48n + 48n) : 0n; diff --git a/packages/panoptic-sdk/src/utils/createPanopticPosition.ts b/packages/panoptic-sdk/src/utils/createPanopticPosition.ts index 76d035f..9acfab0 100644 --- a/packages/panoptic-sdk/src/utils/createPanopticPosition.ts +++ b/packages/panoptic-sdk/src/utils/createPanopticPosition.ts @@ -11,18 +11,12 @@ export const createPanopticPosition = ( owner: Address, pool: PanopticPool, legs: Tuple, - chainID: number, - blockCreated = 0n, ): PanopticPosition => { return { type: "panopticPosition", - address: pool.factory.semiFungiblePositionManager.address, owner, pool, legs, - id: calculatePanopticTokenID(pool, legs), - uri: "", - chainID, - blockCreated, + id: calculatePanopticTokenID(pool.uniswapPool, legs), }; }; diff --git a/packages/panoptic-sdk/src/utils/createPanopticSemiFungiblePosition.ts b/packages/panoptic-sdk/src/utils/createPanopticSemiFungiblePosition.ts new file mode 100644 index 0000000..38b2d2d --- /dev/null +++ b/packages/panoptic-sdk/src/utils/createPanopticSemiFungiblePosition.ts @@ -0,0 +1,30 @@ +import type { Tuple } from "reverse-mirage"; +import type { UniswapV3Pool } from "uniswap-v3-sdk"; +import type { Address } from "viem/accounts"; +import type { PanoptionLeg } from "../types/PanopticPosition.js"; +import type { + PanopticSemiFungiblePosition, + PanopticSemiFungiblePositionManager, +} from "../types/PanopticSemiFungiblePositionManager.js"; +import { calculatePanopticTokenID } from "./calculatePanopticTokenID.js"; + +export const createPanopticSemiFungiblePosition = ( + owner: Address, + semiFungiblePositionManager: PanopticSemiFungiblePositionManager, + legs: Tuple, + uniswapPool: UniswapV3Pool, + chainID: number, + blockCreated = 0n, +): PanopticSemiFungiblePosition => { + return { + type: "panopticSemiFungiblePosition", + address: semiFungiblePositionManager.address, + owner, + uniswapPool, + legs, + id: calculatePanopticTokenID(uniswapPool, legs), + uri: "", + chainID, + blockCreated, + }; +};