Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: inconsistent factory behavior #1576

Open
khaidarkairbek opened this issue Mar 4, 2025 · 0 comments · May be fixed by #1569
Open

bug: inconsistent factory behavior #1576

khaidarkairbek opened this issue Mar 4, 2025 · 0 comments · May be fixed by #1569

Comments

@khaidarkairbek
Copy link
Collaborator

khaidarkairbek commented Mar 4, 2025

Version

0.9.24

Current behavior

I have created a ponder app that has two contracts defined in the config with identical factory as an address but distinct non-overlapping block ranges. The config is given below:

const UNISWAP_V3_FACTORY_ADDRESS = "0x1F98431c8aD98523631AE4a59f267346ea31F984"; 

export default createConfig({
  networks: {
    mainnet: {
      chainId: 1,
      transport: http(process.env.PONDER_RPC_URL_1),
    },
  },
  contracts: {
    uniV3Factory: {
      network: "mainnet",
      address: UNISWAP_V3_FACTORY_ADDRESS,
      startBlock: 19000000,
      endBlock: 19100000,
      abi: parseAbi([
        "event PoolCreated(address indexed token0, address indexed token1, uint24 indexed fee, int24 tickSpacing, address pool)",
      ]),
    },
    uniV3PrevPools: {
      network: "mainnet", 
      address: factory({
        address: UNISWAP_V3_FACTORY_ADDRESS, 
        event: parseAbiItem("event PoolCreated(address indexed token0, address indexed token1, uint24 indexed fee, int24 tickSpacing, address pool)"),
        parameter: "pool"
      }), 
      startBlock: 19000000,
      endBlock: 19050000,
      abi: parseAbi([
        "event Mint(address sender,address indexed owner,int24 indexed tickLower,int24 indexed tickUpper,uint128 amount,uint256 amount0,uint256 amount1)"
      ])
    },
    uniV3Pools: {
      network: "mainnet", 
      address: factory({
        address: UNISWAP_V3_FACTORY_ADDRESS, 
        event: parseAbiItem("event PoolCreated(address indexed token0, address indexed token1, uint24 indexed fee, int24 tickSpacing, address pool)"),
        parameter: "pool"
      }), 
      startBlock: 19050001,
      endBlock: 19100000,
      abi: parseAbi([
        "event Mint(address sender,address indexed owner,int24 indexed tickLower,int24 indexed tickUpper,uint128 amount,uint256 amount0,uint256 amount1)"
      ])
    }
  },
});

Additionally, I have created the simple indexing functions as shown below.

ponder.on("uniV3Factory:PoolCreated", async ({event, context}) => {
  await context.db.insert(factory).values({
    address: context.contracts.uniV3Factory.address, 
    numPools: 1n
  }).onConflictDoUpdate((row) => ({
    numPools: row.numPools + 1n,
  })); 

  await context.db.insert(pool).values({
    address: event.args.pool, 
    blockNumber: event.block.number, 
    mintCount: 0n
  });
})

ponder.on("uniV3Pools:Mint", async ({ event, context }) => {
  await context.db.update(pool, { address: event.log.address }).set((row) => {
    if (row.blockNumber < 19050001n) {
      throw Error("Pool created before the startBlock of the contract")
    }

    return { mintCount: row.mintCount + 1n }
  })
})

ponder.on("uniV3PrevPools:Mint", async ({ event, context }) => {
  await context.db.update(pool, { address: event.log.address }).set((row) => ({ mintCount: row.mintCount + 1n}))
})

The tables are:

export const factory = onchainTable("factory", (p) => ({
  address: p.hex().notNull().primaryKey(), 
  numPools: p.bigint().notNull(),
}))

export const pool = onchainTable("pool", (p) => ({
  address: p.hex().notNull().primaryKey(), 
  blockNumber: p.bigint().notNull(),
  mintCount: p.bigint().notNull()
}))

Currently, the pools captured via factory for uniV3PrevPools also get captured by factory in uniV3Pools even though they have different block ranges.

Expected behavior

I would expect that uniV3PrevPools would index Mint events only for pools created in 19000000 - 19050000 range and uniV3Pools would index Mint events only for pools created in 19050001 - 19100000 block range. I suspect that the issue in the way childAddresses are fetched from the syncStore, with no apparent filtering on blockRange:

const logFactorySQL = (
  qb: SelectQueryBuilder<PonderSyncSchema, "logs", {}>,
  factory: LogFactory,
) =>
  qb
    .select(
      (() => {
        if (factory.childAddressLocation.startsWith("offset")) {
          const childAddressOffset = Number(
            factory.childAddressLocation.substring(6),
          );
          const start = 2 + 12 * 2 + childAddressOffset * 2 + 1;
          const length = 20 * 2;
          return ksql<Hex>`'0x' || substring(data from ${start}::int for ${length}::int)`;
        } else {
          const start = 2 + 12 * 2 + 1;
          const length = 20 * 2;
          return ksql<Hex>`'0x' || substring(${ksql.ref(
            factory.childAddressLocation,
          )} from ${start}::integer for ${length}::integer)`;
        }
      })().as("childAddress"),
    )
    .distinct()
    .$call((qb) => {
      if (Array.isArray(factory.address)) {
        return qb.where("address", "in", factory.address);
      }
      return qb.where("address", "=", factory.address);
    })
    .where("topic0", "=", factory.eventSelector)
    .where("chainId", "=", factory.chainId);

Steps to reproduce

No response

Link to repository

No response

Anything else?

No response

@kyscott18 kyscott18 linked a pull request Mar 6, 2025 that will close this issue
@kyscott18 kyscott18 linked a pull request Mar 6, 2025 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant