From c62c9644409ab4be2993a090a4c6da942fa26f67 Mon Sep 17 00:00:00 2001 From: Kyle Scott Date: Fri, 29 Sep 2023 11:16:12 -0400 Subject: [PATCH] deploy new pool --- packages/panoptic-sdk/README.md | 19 ++- .../src/publicActions/getPanopticPool.test.ts | 28 ++++ .../src/publicActions/getPanopticPool.ts | 33 ++++ .../simulatePanopticDeployNewPool.test.ts | 155 ++++++++++++++++++ .../simulatePanopticDeployNewPool.ts | 69 ++++++++ 5 files changed, 295 insertions(+), 9 deletions(-) create mode 100644 packages/panoptic-sdk/src/publicActions/getPanopticPool.test.ts create mode 100644 packages/panoptic-sdk/src/publicActions/getPanopticPool.ts create mode 100644 packages/panoptic-sdk/src/publicActions/simulatePanopticDeployNewPool.test.ts diff --git a/packages/panoptic-sdk/README.md b/packages/panoptic-sdk/README.md index 93a0f83..57dba1c 100644 --- a/packages/panoptic-sdk/README.md +++ b/packages/panoptic-sdk/README.md @@ -8,14 +8,14 @@ Typescript SDK for Panoptic - [x] `PanopticFactory`: The factory contract in the Panoptic protocol - [x] `PanopticSemiFungiblePositionManager`: The semi-fungible position manager in the Panoptic protocol - - [x] `PanopticPool` - - [x] `PanopticPoolData` - - [x] `PanopticCollateral` - - [x] `PanopticCollateralData` - - [x] `PanopticPosition` - - [x] `PanopticPositionData` - - [x] `PanopticCollateralPosition` - - [x] `PanopticCollateralPositionData` + - [x] `PanopticPool`: A pool created by `PanopticFactory` + - [x] `PanopticPoolData`: The state of a `PanopticPool` + - [x] `PanopticCollateral`: A collateral tracker in a `PanopticPool` + - [x] `PanopticCollateralData`: The state of a `PanopticCollateral` + - [x] `PanopticPosition`: A user position in a `PanopticPool` + - [x] `PanopticPositionData`: The state of a `PanopticPosition` + - [x] `PanopticCollateralPosition`: A user position in a `PanopticCollateral` + - [x] `PanopticCollateralPositionData`: The state of a `PanopticCollateralPosition` - Utilities @@ -41,11 +41,12 @@ Typescript SDK for Panoptic - Public Actions + - [x] `getPanopticPool` - [x] `getPanopticPoolData` - [x] `getPanopticCollateralData` - [x] `getPanopticCollateralPositionData` - [x] `getPanopticPositionData` - - [ ] `simulatePanopticDeployNewPool` + - [x] `simulatePanopticDeployNewPool` - [x] `simulatePanopticMintOptions` - [x] `simulatePanopticRollOptions` - [x] `simulatePanopticBurnOptions` diff --git a/packages/panoptic-sdk/src/publicActions/getPanopticPool.test.ts b/packages/panoptic-sdk/src/publicActions/getPanopticPool.test.ts new file mode 100644 index 0000000..f947856 --- /dev/null +++ b/packages/panoptic-sdk/src/publicActions/getPanopticPool.test.ts @@ -0,0 +1,28 @@ +import { type Hex } from "viem"; +import { beforeEach, expect, test } from "vitest"; +import { deployPool, publicClient, testClient } from "../_test/utils.js"; +import { sepoliaPanoptic } from "../chains/sepolia.js"; +import type { PanopticPool } from "../types/index.js"; +import { getPanopticPool } from "./getPanopticPool.js"; + +let id: Hex | undefined = undefined; + +let pool: PanopticPool; + +beforeEach(async () => { + if (id === undefined) { + pool = await deployPool(); + } else { + await testClient.revert({ id }); + } + id = await testClient.snapshot(); +}, 100_000); + +test("get panoptic pool", async () => { + const address = await getPanopticPool(publicClient, { + uniswapPool: pool.uniswapPool, + factory: sepoliaPanoptic.factory, + }); + + expect(address).toBe(pool.address); +}); diff --git a/packages/panoptic-sdk/src/publicActions/getPanopticPool.ts b/packages/panoptic-sdk/src/publicActions/getPanopticPool.ts new file mode 100644 index 0000000..1c3b567 --- /dev/null +++ b/packages/panoptic-sdk/src/publicActions/getPanopticPool.ts @@ -0,0 +1,33 @@ +import { type UniswapV3Pool } from "uniswap-v3-sdk"; +import type { + Address, + Chain, + Client, + ReadContractParameters, + Transport, +} from "viem"; +import { readContract } from "viem/actions"; +import { panopticFactoryABI } from "../generated.js"; +import type { PanopticFactory } from "../types/PanopticFactory.js"; + +export type GetPanopticPoolParameters = Omit< + ReadContractParameters, + "address" | "abi" | "functionName" | "args" +> & { + uniswapPool: Pick; + factory: Pick; +}; + +export type GetPanopticPoolReturnType = Address; + +export const getPanopticPool = ( + client: Client, + { uniswapPool, factory, ...request }: GetPanopticPoolParameters, +): Promise => + readContract(client, { + address: factory.address, + abi: panopticFactoryABI, + functionName: "getPanopticPool", + args: [uniswapPool.address], + ...request, + }); diff --git a/packages/panoptic-sdk/src/publicActions/simulatePanopticDeployNewPool.test.ts b/packages/panoptic-sdk/src/publicActions/simulatePanopticDeployNewPool.test.ts new file mode 100644 index 0000000..0715e8f --- /dev/null +++ b/packages/panoptic-sdk/src/publicActions/simulatePanopticDeployNewPool.test.ts @@ -0,0 +1,155 @@ +import { createERC20 } from "reverse-mirage"; +import invariant from "tiny-invariant"; +import { + type UniswapV3Pool, + createUniswapV3Pool, + uniswapV3FactoryABI, + uniswapV3PoolABI, +} from "uniswap-v3-sdk"; +import { type Hex } from "viem"; +import { sepolia } from "viem/chains"; +import { beforeEach, expect, test } from "vitest"; +import MockERC20Bytecode from "../../../../lib/panoptic-v1-core/artifacts/contracts/MockERC20.sol/MockERC20.json"; +import { ALICE } from "../_test/constants.js"; +import { publicClient, testClient, walletClient } from "../_test/utils.js"; +import { sepoliaPanoptic } from "../chains/sepolia.js"; +import { mockErc20ABI } from "../generated.js"; +import { getPanopticPool } from "./getPanopticPool.js"; +import { simulatePanopticDeployNewPool } from "./simulatePanopticDeployNewPool.js"; + +let id: Hex | undefined = undefined; + +let uniswapPool: UniswapV3Pool; + +beforeEach(async () => { + if (id === undefined) { + let deployHash = await walletClient.deployContract({ + account: ALICE, + abi: mockErc20ABI, + bytecode: MockERC20Bytecode.bytecode.object as Hex, + args: ["name", "symbol", 18], + }); + const { contractAddress: tokenAAddress } = + await publicClient.waitForTransactionReceipt({ + hash: deployHash, + }); + invariant(tokenAAddress); + const tokenA = createERC20(tokenAAddress, "name", "symbol", 18, sepolia.id); + deployHash = await walletClient.deployContract({ + account: ALICE, + abi: mockErc20ABI, + bytecode: MockERC20Bytecode.bytecode.object as Hex, + args: ["name", "symbol", 18], + }); + const { contractAddress: tokenBAddress } = + await publicClient.waitForTransactionReceipt({ + hash: deployHash, + }); + invariant(tokenBAddress); + const tokenB = createERC20(tokenBAddress, "name", "symbol", 18, sepolia.id); + + // Mint + const { request: mintRequestA } = await publicClient.simulateContract({ + abi: mockErc20ABI, + address: tokenA.address, + functionName: "mint", + args: [ALICE, 10n ** 36n], + }); + const mintHashA = await walletClient.writeContract(mintRequestA); + await publicClient.waitForTransactionReceipt({ + hash: mintHashA, + }); + + const { request: mintRequestB } = await publicClient.simulateContract({ + abi: mockErc20ABI, + address: tokenB.address, + functionName: "mint", + args: [ALICE, 10n ** 36n], + }); + const mintHashB = await walletClient.writeContract(mintRequestB); + await publicClient.waitForTransactionReceipt({ + hash: mintHashB, + }); + + // Approve + const { request: approveRequestA } = await publicClient.simulateContract({ + abi: mockErc20ABI, + address: tokenA.address, + functionName: "approve", + args: [sepoliaPanoptic.factory.address, 10n ** 36n], + account: ALICE, + }); + const approveHashA = await walletClient.writeContract(approveRequestA); + await publicClient.waitForTransactionReceipt({ + hash: approveHashA, + }); + + const { request: approveRequestB } = await publicClient.simulateContract({ + abi: mockErc20ABI, + address: tokenB.address, + functionName: "approve", + args: [sepoliaPanoptic.factory.address, 10n ** 36n], + account: ALICE, + }); + const approveHashB = await walletClient.writeContract(approveRequestB); + await publicClient.waitForTransactionReceipt({ + hash: approveHashB, + }); + + // Create pool + const { request } = await publicClient.simulateContract({ + address: sepoliaPanoptic.factory.uniswapFactory.address, + abi: uniswapV3FactoryABI, + functionName: "createPool", + args: [tokenA.address, tokenB.address, 500], + account: ALICE, + }); + const hash = await walletClient.writeContract(request); + await publicClient.waitForTransactionReceipt({ + hash, + }); + + uniswapPool = createUniswapV3Pool( + tokenA, + tokenB, + 500, + sepoliaPanoptic.factory.uniswapFactory, + ); + + const { request: initializeRequest } = await publicClient.simulateContract({ + address: uniswapPool.address, + abi: uniswapV3PoolABI, + functionName: "initialize", + args: [2n ** 96n], + account: ALICE, + }); + const initializeHash = await walletClient.writeContract(initializeRequest); + await publicClient.waitForTransactionReceipt({ + hash: initializeHash, + }); + } else { + await testClient.revert({ id }); + } + id = await testClient.snapshot(); +}, 100_000); + +test("simulate deploy pool", async () => { + const { request } = await simulatePanopticDeployNewPool(publicClient, { + args: { + uniswapPool, + factory: sepoliaPanoptic.factory, + salt: 0n, + }, + account: ALICE, + }); + + const hash = await walletClient.writeContract(request); + await publicClient.waitForTransactionReceipt({ hash }); + + const address = await getPanopticPool(publicClient, { + uniswapPool, + factory: sepoliaPanoptic.factory, + }); + + expect(address).toBeTruthy(); +}); diff --git a/packages/panoptic-sdk/src/publicActions/simulatePanopticDeployNewPool.ts b/packages/panoptic-sdk/src/publicActions/simulatePanopticDeployNewPool.ts index e69de29..244bb5a 100644 --- a/packages/panoptic-sdk/src/publicActions/simulatePanopticDeployNewPool.ts +++ b/packages/panoptic-sdk/src/publicActions/simulatePanopticDeployNewPool.ts @@ -0,0 +1,69 @@ +import type { UniswapV3Pool } from "uniswap-v3-sdk"; +import type { + Chain, + Client, + SimulateContractParameters, + SimulateContractReturnType, + Transport, +} from "viem"; +import { simulateContract } from "viem/contract"; +import { panopticFactoryABI } from "../generated.js"; +import type { PanopticFactory } from "../types/PanopticFactory.js"; + +export type PanopticDeployNewPoolParameters = { + factory: PanopticFactory; + uniswapPool: UniswapV3Pool; + salt: bigint; +}; + +export type SimulatePanopticDeployNewPoolParameters< + TChain extends Chain | undefined = Chain, + TChainOverride extends Chain | undefined = Chain | undefined, +> = Omit< + SimulateContractParameters< + typeof panopticFactoryABI, + "deployNewPool", + TChain, + TChainOverride + >, + "args" | "address" | "abi" | "functionName" +> & { args: PanopticDeployNewPoolParameters }; + +export type SimulatePanopticDeployNewPoolReturnType< + TChain extends Chain | undefined, + TChainOverride extends Chain | undefined = undefined, +> = SimulateContractReturnType< + typeof panopticFactoryABI, + "deployNewPool", + TChain, + TChainOverride +>; + +// TODO: return PanopticPool +export const simulatePanopticDeployNewPool = < + TChain extends Chain | undefined, + TChainOverride extends Chain | undefined, +>( + client: Client, + { + args: { factory, uniswapPool, salt }, + ...request + }: SimulatePanopticDeployNewPoolParameters, +): Promise> => + simulateContract(client, { + address: factory.address, + abi: panopticFactoryABI, + functionName: "deployNewPool", + args: [ + uniswapPool.token0.address, + uniswapPool.token1.address, + uniswapPool.feeTier, + salt, + ], + ...request, + } as unknown as SimulateContractParameters< + typeof panopticFactoryABI, + "deployNewPool", + TChain, + TChainOverride + >);