diff --git a/docs/new-pool-types.md b/docs/new-pool-types.md index 76d0a9a..092c785 100644 --- a/docs/new-pool-types.md +++ b/docs/new-pool-types.md @@ -4,81 +4,116 @@ To integrate new pool types into the Balancer subgraph, follow these steps below ## Setup -Navigate to the `subgraphs/pools` directory before starting the integration process. - -## Adding the Factory - -Run the following command to add your pool factory: - -``` -pnpm add-factory [factory-address] [network] -``` - -This command fetch the factory ABI, retrieves the deployment block, and adds it to the subgraph manifest. - -## Adding a Pool Instance - -Execute this command to fetch the pool ABI: - -``` -pnpm add-pool [pool-address] [network] -``` - -Ensure you have a pool deployed from your factory before running this command. - -## Generating Types - -Run the codegen command to ensure that types from your ABIs are generated: - -``` -pnpm codegen -``` +Navigate to the `subgraphs/v3-pools` directory before starting the integration process. ## Updating the GraphQL Schema -Edit the `schema.graphql` file to add any specific parameters based on your pool type to the `Pool` entity. - -```graphql -type Pool @entity { - # ... Existing fields - - " Your custom parameter " - customParam: BigInt -} -``` - -Add your custom fields to this schema as needed for your specific pool type. - -## Modifying the Pool Creation Handler - -Navigate to `src/mappings/factories.ts` and update the handler function for the new pool type: - - -```typescript -import { YourPool } from "../types/YourPoolFactory/YourPool"; - -export function handleYourPoolCreated(event: PoolCreated): void { - let poolAddress = event.params.pool; - let pool = new Pool(poolAddress); - pool.address = poolAddress; - - let factory = getFactory(event.address, PoolType.YourPoolType, 1); - pool.factory = factory.id; - - - // First, bind the pool address to its contract - let yourPool = YourPool.bind(poolAddress); - - // Then fetch the pool-specific parameters - let customParamResult = yourPool.try_getCustomParameter(); - if (!customParamResult.reverted) { - pool.customParam = customParamResult.value; - } - - // Add more parameter fetching logic as needed - - pool.save(); -} -``` - -In this function, replace the example parameter fetching logic with calls to your pool's specific methods to retrieve and store the relevant parameters. +1. Edit the `schema.graphql` file: + + a. Add your pool type to the `PoolType` enum: + + ```graphql + enum PoolType { + Weighted + Stable + Custom # Add your new pool type here + } + ``` + + b. Create an entity for your pool-type specific parameters: + + ```graphql + type CustomParams @entity { + id: Bytes! + customParam: BigInt! + # Add other custom parameters as needed + } + ``` + + c. Extend the `Pool` entity to expose your custom params: + + ```graphql + type Pool @entity { + id: Bytes! + address: Bytes! + factory: Factory! + stableParams: StableParams + weightedParams: WeightedParams + customParams: CustomParams # Add the new entity here + } + ``` + +2. Save the `schema.graphql` file. Run the codegen command to generate types from your ABIs: + + ```bash + pnpm codegen + ``` + +## Creating the Subgraph Manifest + +1. Update the `subgraph.sepolia.yaml` file to include your new pool factory: + + ```yaml + dataSources: + # Existing data sources... + - kind: ethereum/contract + name: CustomPoolFactory + network: sepolia + source: + address: "0x..." # Your custom pool factory address + abi: BasePoolFactory + mapping: + kind: ethereum/events + apiVersion: 0.0.7 + language: wasm/assemblyscript + file: ./src/mappings/custom.ts + entities: + - Pool + - CustomParams + abis: + - name: BasePoolFactory + file: ./abis/BasePoolFactory.json + eventHandlers: + - event: PoolCreated(indexed address,bytes32) + handler: handleCustomPoolCreated + ``` + +## Implementing Pool Factory Mapping + +1. Update `src/mappings/common.ts` to include your new pool type: + + ```typescript + export class PoolType { + static Weighted: string = "Weighted"; + static Stable: string = "Stable"; + static Custom: string = "Custom"; // Add your new pool type here + } + ``` + +2. Create a new file in the `src/mappings` directory for your custom pool factory (e.g., `custom.ts`). + +3. Implement the factory mapping. See Stable and Weighted implementations as reference. + + ```typescript + import { Address } from "@graphprotocol/graph-ts"; + + import { PoolCreated } from "../types/CustomPoolFactory/BasePoolFactory"; + import { handlePoolCreated } from "./factories"; + import { PoolType } from "./constants"; + + export function handleCustomPoolCreated(event: CustomPoolCreated): void { + handlePoolCreated( + event.params.pool, + event.address, // Factory + PoolType.Custom, + 1, // version of your pool type factory + handleCustomPoolParams, + "customParams" // should be the name of the field you added to the Pool entity + ); + } + + function handleCustomPoolParams(poolAddress: Address): Bytes { + // Implement custom logic to fetch and save custom parameters + // Return the ID of the saved CustomParams entity + } + ``` diff --git a/subgraphs/v3-pools/abis/BasePoolFactory.json b/subgraphs/v3-pools/abis/BasePoolFactory.json new file mode 100644 index 0000000..2713127 --- /dev/null +++ b/subgraphs/v3-pools/abis/BasePoolFactory.json @@ -0,0 +1,15 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "pool", + "type": "address" + } + ], + "name": "PoolCreated", + "type": "event" + } +] diff --git a/subgraphs/v3-pools/abis/StablePoolFactory.json b/subgraphs/v3-pools/abis/StablePoolFactory.json deleted file mode 100644 index bd16df8..0000000 --- a/subgraphs/v3-pools/abis/StablePoolFactory.json +++ /dev/null @@ -1,371 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "contract IVault", - "name": "vault", - "type": "address" - }, - { - "internalType": "uint32", - "name": "pauseWindowDuration", - "type": "uint32" - }, - { - "internalType": "string", - "name": "factoryVersion", - "type": "string" - }, - { - "internalType": "string", - "name": "poolVersion", - "type": "string" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "Disabled", - "type": "error" - }, - { - "inputs": [], - "name": "PoolPauseWindowDurationOverflow", - "type": "error" - }, - { - "inputs": [], - "name": "SenderNotAllowed", - "type": "error" - }, - { - "inputs": [], - "name": "StandardPoolWithCreator", - "type": "error" - }, - { - "anonymous": false, - "inputs": [], - "name": "FactoryDisabled", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "pool", - "type": "address" - } - ], - "name": "PoolCreated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "string", - "name": "symbol", - "type": "string" - }, - { - "components": [ - { - "internalType": "contract IERC20", - "name": "token", - "type": "address" - }, - { - "internalType": "enum TokenType", - "name": "tokenType", - "type": "uint8" - }, - { - "internalType": "contract IRateProvider", - "name": "rateProvider", - "type": "address" - }, - { - "internalType": "bool", - "name": "paysYieldFees", - "type": "bool" - } - ], - "internalType": "struct TokenConfig[]", - "name": "tokens", - "type": "tuple[]" - }, - { - "internalType": "uint256[]", - "name": "normalizedWeights", - "type": "uint256[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "pauseManager", - "type": "address" - }, - { - "internalType": "address", - "name": "swapFeeManager", - "type": "address" - }, - { - "internalType": "address", - "name": "poolCreator", - "type": "address" - } - ], - "internalType": "struct PoolRoleAccounts", - "name": "roleAccounts", - "type": "tuple" - }, - { - "internalType": "uint256", - "name": "swapFeePercentage", - "type": "uint256" - }, - { - "internalType": "address", - "name": "poolHooksContract", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - } - ], - "name": "create", - "outputs": [ - { - "internalType": "address", - "name": "pool", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "disable", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - } - ], - "name": "getActionId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getAuthorizer", - "outputs": [ - { - "internalType": "contract IAuthorizer", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getDefaultLiquidityManagement", - "outputs": [ - { - "components": [ - { - "internalType": "bool", - "name": "disableUnbalancedLiquidity", - "type": "bool" - }, - { - "internalType": "bool", - "name": "enableAddLiquidityCustom", - "type": "bool" - }, - { - "internalType": "bool", - "name": "enableRemoveLiquidityCustom", - "type": "bool" - } - ], - "internalType": "struct LiquidityManagement", - "name": "liquidityManagement", - "type": "tuple" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "getDefaultPoolHooksContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - } - ], - "name": "getDeploymentAddress", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getNewPoolPauseWindowEndTime", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getOriginalPauseWindowEndTime", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getPauseWindowDuration", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getPoolVersion", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getVault", - "outputs": [ - { - "internalType": "contract IVault", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "isDisabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pool", - "type": "address" - } - ], - "name": "isPoolFromFactory", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/subgraphs/v3-pools/abis/WeightedPoolFactory.json b/subgraphs/v3-pools/abis/WeightedPoolFactory.json deleted file mode 100644 index bd16df8..0000000 --- a/subgraphs/v3-pools/abis/WeightedPoolFactory.json +++ /dev/null @@ -1,371 +0,0 @@ -[ - { - "inputs": [ - { - "internalType": "contract IVault", - "name": "vault", - "type": "address" - }, - { - "internalType": "uint32", - "name": "pauseWindowDuration", - "type": "uint32" - }, - { - "internalType": "string", - "name": "factoryVersion", - "type": "string" - }, - { - "internalType": "string", - "name": "poolVersion", - "type": "string" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "Disabled", - "type": "error" - }, - { - "inputs": [], - "name": "PoolPauseWindowDurationOverflow", - "type": "error" - }, - { - "inputs": [], - "name": "SenderNotAllowed", - "type": "error" - }, - { - "inputs": [], - "name": "StandardPoolWithCreator", - "type": "error" - }, - { - "anonymous": false, - "inputs": [], - "name": "FactoryDisabled", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "pool", - "type": "address" - } - ], - "name": "PoolCreated", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "string", - "name": "symbol", - "type": "string" - }, - { - "components": [ - { - "internalType": "contract IERC20", - "name": "token", - "type": "address" - }, - { - "internalType": "enum TokenType", - "name": "tokenType", - "type": "uint8" - }, - { - "internalType": "contract IRateProvider", - "name": "rateProvider", - "type": "address" - }, - { - "internalType": "bool", - "name": "paysYieldFees", - "type": "bool" - } - ], - "internalType": "struct TokenConfig[]", - "name": "tokens", - "type": "tuple[]" - }, - { - "internalType": "uint256[]", - "name": "normalizedWeights", - "type": "uint256[]" - }, - { - "components": [ - { - "internalType": "address", - "name": "pauseManager", - "type": "address" - }, - { - "internalType": "address", - "name": "swapFeeManager", - "type": "address" - }, - { - "internalType": "address", - "name": "poolCreator", - "type": "address" - } - ], - "internalType": "struct PoolRoleAccounts", - "name": "roleAccounts", - "type": "tuple" - }, - { - "internalType": "uint256", - "name": "swapFeePercentage", - "type": "uint256" - }, - { - "internalType": "address", - "name": "poolHooksContract", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - } - ], - "name": "create", - "outputs": [ - { - "internalType": "address", - "name": "pool", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "disable", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes4", - "name": "selector", - "type": "bytes4" - } - ], - "name": "getActionId", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getAuthorizer", - "outputs": [ - { - "internalType": "contract IAuthorizer", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getDefaultLiquidityManagement", - "outputs": [ - { - "components": [ - { - "internalType": "bool", - "name": "disableUnbalancedLiquidity", - "type": "bool" - }, - { - "internalType": "bool", - "name": "enableAddLiquidityCustom", - "type": "bool" - }, - { - "internalType": "bool", - "name": "enableRemoveLiquidityCustom", - "type": "bool" - } - ], - "internalType": "struct LiquidityManagement", - "name": "liquidityManagement", - "type": "tuple" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "getDefaultPoolHooksContract", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - } - ], - "name": "getDeploymentAddress", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getNewPoolPauseWindowEndTime", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getOriginalPauseWindowEndTime", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getPauseWindowDuration", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getPoolVersion", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "getVault", - "outputs": [ - { - "internalType": "contract IVault", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "isDisabled", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "pool", - "type": "address" - } - ], - "name": "isPoolFromFactory", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "version", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/subgraphs/v3-pools/package.json b/subgraphs/v3-pools/package.json index b767925..2eaa5d0 100644 --- a/subgraphs/v3-pools/package.json +++ b/subgraphs/v3-pools/package.json @@ -4,7 +4,7 @@ "scripts": { "add-pool": "node scripts/cli.js", "add-factory": "node scripts/cli.js", - "codegen": "graph codegen --output-dir src/types/", + "codegen": "graph codegen subgraph.sepolia.yaml --output-dir src/types/", "deploy": "graph deploy", "build": "graph build", "test": "graph test" diff --git a/subgraphs/v3-pools/schema.graphql b/subgraphs/v3-pools/schema.graphql index 497808e..fd62639 100644 --- a/subgraphs/v3-pools/schema.graphql +++ b/subgraphs/v3-pools/schema.graphql @@ -37,8 +37,6 @@ type Pool @entity { address: Bytes! "Factory that created this Pool" factory: Factory! - "Type of the pool" - type: PoolType! "Parameters for Weighted pools (null for other pool types)" weightedParams: WeightedParams "Parameters for Stable pools (null for other pool types)" diff --git a/subgraphs/v3-pools/scripts/add-factory.js b/subgraphs/v3-pools/scripts/add-factory.js deleted file mode 100755 index 738a52c..0000000 --- a/subgraphs/v3-pools/scripts/add-factory.js +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env node - -const { execSync } = require('child_process'); - -const [,, address, networkName] = process.argv; - -if (!address || !networkName) { - console.error('Usage: pnpm cli