From 234ebf6741a71fe08b63e0c84838a74eaf1fcacb Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Thu, 8 Dec 2022 11:36:04 +0000
Subject: [PATCH 01/25] Added debug.

---
 balancer-js/src/modules/data/pool/subgraph.ts |   3 +-
 .../joins/debug.module.integration.spec.ts    | 242 ++++++++++++++++++
 balancer-js/src/modules/joins/joins.module.ts |   9 +
 3 files changed, 253 insertions(+), 1 deletion(-)
 create mode 100644 balancer-js/src/modules/joins/debug.module.integration.spec.ts

diff --git a/balancer-js/src/modules/data/pool/subgraph.ts b/balancer-js/src/modules/data/pool/subgraph.ts
index d54613f00..5fb495660 100644
--- a/balancer-js/src/modules/data/pool/subgraph.ts
+++ b/balancer-js/src/modules/data/pool/subgraph.ts
@@ -107,7 +107,8 @@ export class PoolsSubgraphRepository
       where: { swapEnabled: true, totalShares_gt: '0.000000000001' },
       orderBy: Pool_OrderBy.TotalLiquidity,
       orderDirection: OrderDirection.Desc,
-      block: await this.block(),
+      // block: await this.block(),
+      block: { number: 16067738 },
     });
     console.timeEnd('fetching pools');
 
diff --git a/balancer-js/src/modules/joins/debug.module.integration.spec.ts b/balancer-js/src/modules/joins/debug.module.integration.spec.ts
new file mode 100644
index 000000000..c54471efc
--- /dev/null
+++ b/balancer-js/src/modules/joins/debug.module.integration.spec.ts
@@ -0,0 +1,242 @@
+// yarn test:only ./src/modules/joins/debug.module.integration.spec.ts
+import dotenv from 'dotenv';
+import { expect } from 'chai';
+import hardhat from 'hardhat';
+
+import { BalancerSDK, BalancerTenderlyConfig, Network } from '@/.';
+import { BigNumber, formatFixed, parseFixed } from '@ethersproject/bignumber';
+import { Contracts } from '@/modules/contracts/contracts.module';
+import { forkSetup, getBalances } from '@/test/lib/utils';
+import { ADDRESSES } from '@/test/lib/constants';
+import { Relayer } from '@/modules/relayer/relayer.module';
+import { JsonRpcSigner } from '@ethersproject/providers';
+import { SolidityMaths } from '@/lib/utils/solidityMaths';
+
+dotenv.config();
+
+const TEST_BOOSTED = true;
+
+/*
+ * Testing on MAINNET
+ * - Update hardhat.config.js with chainId = 1
+ * - Update ALCHEMY_URL on .env with a mainnet api key
+ * - Run node on terminal: yarn run node
+ * - Uncomment section below:
+ */
+const network = Network.MAINNET;
+const blockNumber = 16067738;
+const customSubgraphUrl =
+  'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2';
+const { ALCHEMY_URL: jsonRpcUrl } = process.env;
+const rpcUrl = 'http://127.0.0.1:8545';
+
+const { TENDERLY_ACCESS_KEY, TENDERLY_USER, TENDERLY_PROJECT } = process.env;
+const { ethers } = hardhat;
+const MAX_GAS_LIMIT = 8e6;
+
+const tenderlyConfig: BalancerTenderlyConfig = {
+  accessKey: TENDERLY_ACCESS_KEY as string,
+  user: TENDERLY_USER as string,
+  project: TENDERLY_PROJECT as string,
+  blockNumber,
+};
+
+const sdk = new BalancerSDK({
+  network,
+  rpcUrl,
+  customSubgraphUrl,
+  tenderly: tenderlyConfig,
+});
+const { pools } = sdk;
+const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network);
+const signer = provider.getSigner();
+const { contracts, contractAddresses } = new Contracts(
+  network as number,
+  provider
+);
+const relayer = contractAddresses.relayerV4 as string;
+const addresses = ADDRESSES[network];
+
+interface Test {
+  signer: JsonRpcSigner;
+  description: string;
+  pool: {
+    id: string;
+    address: string;
+  };
+  tokensIn: string[];
+  amountsIn: string[];
+  authorisation: string | undefined;
+  wrapMainTokens: boolean;
+}
+
+const runTests = async (tests: Test[]) => {
+  for (let i = 0; i < tests.length; i++) {
+    const test = tests[i];
+    it(test.description, async () => {
+      const userAddress = await test.signer.getAddress();
+      const authorisation = await Relayer.signRelayerApproval(
+        relayer,
+        userAddress,
+        signer,
+        contracts.vault
+      );
+      await testFlow(
+        userAddress,
+        test.pool,
+        test.tokensIn,
+        test.amountsIn,
+        test.wrapMainTokens,
+        authorisation
+      );
+    }).timeout(120000);
+  }
+};
+
+const testFlow = async (
+  userAddress: string,
+  pool: { id: string; address: string },
+  tokensIn: string[],
+  amountsIn: string[],
+  wrapMainTokens: boolean,
+  authorisation: string | undefined
+) => {
+  const [bptBalanceBefore, ...tokensInBalanceBefore] = await getBalances(
+    [pool.address, ...tokensIn],
+    signer,
+    userAddress
+  );
+
+  const gasLimit = MAX_GAS_LIMIT;
+  const slippage = '10'; // 10 bps = 0.1%
+
+  const query = await pools.generalisedJoin(
+    pool.id,
+    tokensIn,
+    amountsIn,
+    userAddress,
+    wrapMainTokens,
+    slippage,
+    authorisation
+  );
+
+  console.log(query.priceImpact, 'priceImpact Raw');
+  const piPercent = SolidityMaths.mulDownFixed(
+    BigInt(query.priceImpact),
+    BigInt('100000000000000000000')
+  );
+  console.log(formatFixed(piPercent, 18), 'priceImpact %');
+
+  const response = await signer.sendTransaction({
+    to: query.to,
+    data: query.callData,
+    gasLimit,
+  });
+
+  const receipt = await response.wait();
+  console.log('Gas used', receipt.gasUsed.toString());
+
+  const [bptBalanceAfter, ...tokensInBalanceAfter] = await getBalances(
+    [pool.address, ...tokensIn],
+    signer,
+    userAddress
+  );
+  expect(receipt.status).to.eql(1);
+  expect(BigNumber.from(query.minOut).gte('0')).to.be.true;
+  expect(BigNumber.from(query.expectedOut).gt(query.minOut)).to.be.true;
+  tokensInBalanceAfter.forEach((balanceAfter, i) => {
+    expect(balanceAfter.toString()).to.eq(
+      tokensInBalanceBefore[i].sub(amountsIn[i]).toString()
+    );
+  });
+  expect(bptBalanceBefore.eq(0)).to.be.true;
+  expect(bptBalanceAfter.gte(query.minOut)).to.be.true;
+  console.log(bptBalanceAfter.toString(), 'bpt after');
+  console.log(query.minOut, 'minOut');
+  console.log(query.expectedOut, 'expectedOut');
+};
+
+describe('generalised join execution', async () => {
+  context('bbausd', async () => {
+    if (!TEST_BOOSTED) return true;
+    let authorisation: string | undefined;
+    beforeEach(async () => {
+      const tokens = [
+        addresses.USDC.address,
+        addresses.DAI.address,
+        addresses.USDT.address,
+      ];
+      const slots = [
+        addresses.USDC.slot,
+        addresses.DAI.slot,
+        addresses.USDT.slot,
+      ];
+      const balances = [
+        parseFixed('1000000', 6).toString(),
+        parseFixed('1000000', 18).toString(),
+        parseFixed('1000000', 6).toString(),
+      ];
+      await forkSetup(
+        signer,
+        tokens,
+        slots,
+        balances,
+        jsonRpcUrl as string,
+        blockNumber
+      );
+    });
+
+    await runTests([
+      {
+        signer,
+        description: 'join with leaf tokens',
+        pool: {
+          id: addresses.bbausd2.id,
+          address: addresses.bbausd2.address,
+        },
+        tokensIn: [
+          addresses.USDC.address,
+          addresses.DAI.address,
+          addresses.USDT.address,
+        ],
+        amountsIn: [
+          parseFixed('10', 6).toString(),
+          parseFixed('10', 18).toString(),
+          parseFixed('10', 6).toString(),
+        ],
+        authorisation: authorisation,
+        wrapMainTokens: false,
+      },
+      {
+        signer,
+        description: 'join with leaf tokens',
+        pool: {
+          id: addresses.bbausd2.id,
+          address: addresses.bbausd2.address,
+        },
+        tokensIn: [addresses.USDC.address, addresses.DAI.address],
+        amountsIn: [
+          parseFixed('0.1', 6).toString(),
+          parseFixed('0.001', 18).toString(),
+        ],
+        authorisation: authorisation,
+        wrapMainTokens: false,
+      },
+      {
+        signer,
+        description: 'join with leaf tokens',
+        pool: {
+          id: addresses.bbausd2.id,
+          address: addresses.bbausd2.address,
+        },
+        tokensIn: [addresses.USDC.address, addresses.DAI.address],
+        amountsIn: [
+          parseFixed('900000', 6).toString(),
+          parseFixed('0.001', 18).toString(),
+        ],
+        authorisation: authorisation,
+        wrapMainTokens: false,
+      },
+    ]);
+  });
+});
diff --git a/balancer-js/src/modules/joins/joins.module.ts b/balancer-js/src/modules/joins/joins.module.ts
index da74ed427..9b4f252de 100644
--- a/balancer-js/src/modules/joins/joins.module.ts
+++ b/balancer-js/src/modules/joins/joins.module.ts
@@ -122,6 +122,9 @@ export class Join {
       true
     ).toString();
 
+    console.log(totalMinAmountOut, `totalMinOut`);
+    console.log(totalBptZeroPi.toString(), `totalBptZeroPi`);
+
     // Create calls with minAmountsOut
     const { callData, deltas } = await this.createCalls(
       joinPaths,
@@ -408,6 +411,10 @@ export class Join {
         parentNode.joinAction === 'joinPool'
       ) {
         const sp = parentNode.spotPrices[childAddress.toLowerCase()];
+        console.log(
+          `Spot price ${childAddress.toLowerCase()}: `,
+          sp.toString()
+        );
         spProduct = spProduct * parseFloat(sp);
         childAddress = parentNode.address;
       }
@@ -420,6 +427,8 @@ export class Join {
       inputAmountScaled,
       spPriceScaled.toBigInt()
     );
+    console.log('sp product: ', spProduct.toString());
+    console.log('zeroPriceImpact amount for path: ', bptOut.toString(), '\n');
     return bptOut;
   };
 

From 6019b26c3a9c03795167a7b812e7bf04c1242276 Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Wed, 14 Dec 2022 12:06:39 +0000
Subject: [PATCH 02/25] Update to use onchain pools/priceRates. Linear uses SP
 calc instead of default.

---
 balancer-js/package.json                      |   2 +-
 balancer-js/src/modules/data/index.ts         |  35 +++
 balancer-js/src/modules/data/pool/index.ts    |   1 +
 .../src/modules/data/pool/onChainData.ts      | 277 ++++++++++++++++
 balancer-js/src/modules/data/pool/subgraph.ts |   7 +-
 .../src/modules/data/pool/subgraphOnChain.ts  | 295 ++++++++++++++++++
 balancer-js/src/modules/graph/graph.ts        |   2 +-
 .../joins/debug.module.integration.spec.ts    |   2 +-
 balancer-js/src/modules/joins/joins.module.ts |   3 +-
 balancer-js/src/modules/pools/index.ts        |   4 +-
 balancer-js/src/types.ts                      |   1 +
 balancer-js/yarn.lock                         |   7 +-
 12 files changed, 621 insertions(+), 15 deletions(-)
 create mode 100644 balancer-js/src/modules/data/pool/onChainData.ts
 create mode 100644 balancer-js/src/modules/data/pool/subgraphOnChain.ts

diff --git a/balancer-js/package.json b/balancer-js/package.json
index ff8dd76b5..e7034d9c9 100644
--- a/balancer-js/package.json
+++ b/balancer-js/package.json
@@ -89,7 +89,7 @@
     "typescript": "^4.0.2"
   },
   "dependencies": {
-    "@balancer-labs/sor": "^4.0.1-beta.15",
+    "@balancer-labs/sor": "/Users/jg/Documents/balancer-sor/balancer-labs-sor-v4.0.1-beta.22.tgz",
     "@balancer-labs/typechain": "^1.0.0",
     "axios": "^0.24.0",
     "graphql": "^15.6.1",
diff --git a/balancer-js/src/modules/data/index.ts b/balancer-js/src/modules/data/index.ts
index 57cc72428..d44911131 100644
--- a/balancer-js/src/modules/data/index.ts
+++ b/balancer-js/src/modules/data/index.ts
@@ -14,10 +14,12 @@ export * from './protocol-fees/provider';
 export * from './token-yields/repository';
 export * from './block-number';
 
+import { GraphQLArgs } from '@/.';
 import { BalancerNetworkConfig, BalancerDataRepositories } from '@/types';
 import { PoolsSubgraphRepository } from './pool/subgraph';
 import { PoolSharesRepository } from './pool-shares/repository';
 import { PoolJoinExitRepository } from './pool-joinExit/repository';
+import { PoolsSubgraphOnChainRepository } from './pool/subgraphOnChain';
 import { PoolGaugesRepository } from './pool-gauges/repository';
 import { GaugeSharesRepository } from './gauge-shares/repository';
 import { BlockNumberRepository } from './block-number';
@@ -43,6 +45,7 @@ import { SubgraphPriceRepository } from './token-prices/subgraph';
 
 export class Data implements BalancerDataRepositories {
   pools;
+  poolsOnChain;
   yesterdaysPools;
   poolShares;
   poolGauges;
@@ -64,6 +67,38 @@ export class Data implements BalancerDataRepositories {
       chainId: networkConfig.chainId,
     });
 
+    const subgraphArgs: GraphQLArgs = {
+      where: {
+        swapEnabled: {
+          eq: true,
+        },
+        totalShares: {
+          gt: 0.000000000001,
+        },
+        id: {
+          in: [
+            '0xa13a9247ea42d743238089903570127dda72fe4400000000000000000000035d',
+            '0x2F4EB100552EF93840D5ADC30560E5513DFFFACB000000000000000000000334'.toLowerCase(),
+            '0xAE37D54AE477268B9997D4161B96B8200755935C000000000000000000000337'.toLowerCase(),
+            '0x82698AECC9E28E9BB27608BD52CF57F704BD1B83000000000000000000000336'.toLowerCase(),
+          ],
+        },
+      },
+      orderBy: 'totalLiquidity',
+      orderDirection: 'desc',
+      block: { number: 16176441 },
+    };
+    const subgraphQuery = { args: subgraphArgs, attrs: {} };
+
+    this.poolsOnChain = new PoolsSubgraphOnChainRepository({
+      url: networkConfig.urls.subgraph,
+      chainId: networkConfig.chainId,
+      provider: provider,
+      multicall: networkConfig.addresses.contracts.multicall,
+      vault: networkConfig.addresses.contracts.vault,
+      query: subgraphQuery,
+    });
+
     this.poolShares = new PoolSharesRepository(
       networkConfig.urls.subgraph,
       networkConfig.chainId
diff --git a/balancer-js/src/modules/data/pool/index.ts b/balancer-js/src/modules/data/pool/index.ts
index 5c246217e..89d24baf0 100644
--- a/balancer-js/src/modules/data/pool/index.ts
+++ b/balancer-js/src/modules/data/pool/index.ts
@@ -3,3 +3,4 @@ export * from './balancer-api';
 export * from './fallback';
 export * from './static';
 export * from './subgraph';
+export * from './subgraphOnChain';
diff --git a/balancer-js/src/modules/data/pool/onChainData.ts b/balancer-js/src/modules/data/pool/onChainData.ts
new file mode 100644
index 000000000..484515d3c
--- /dev/null
+++ b/balancer-js/src/modules/data/pool/onChainData.ts
@@ -0,0 +1,277 @@
+import { formatFixed } from '@ethersproject/bignumber';
+import { Provider } from '@ethersproject/providers';
+import { PoolFilter } from '@balancer-labs/sor';
+import { Multicaller } from '@/lib/utils/multiCaller';
+import { isSameAddress } from '@/lib/utils';
+import { Vault__factory } from '@balancer-labs/typechain';
+import { Pool } from '@/types';
+
+// TODO: decide whether we want to trim these ABIs down to the relevant functions
+import aTokenRateProvider from '@/lib/abi/StaticATokenRateProvider.json';
+import weightedPoolAbi from '@/lib/abi/WeightedPool.json';
+import stablePoolAbi from '@/lib/abi/StablePool.json';
+import elementPoolAbi from '@/lib/abi/ConvergentCurvePool.json';
+import linearPoolAbi from '@/lib/abi/LinearPool.json';
+import composableStableAbi from '@/lib/abi/ComposableStable.json';
+
+export async function getOnChainBalances(
+  subgraphPoolsOriginal: Pool[],
+  multiAddress: string,
+  vaultAddress: string,
+  provider: Provider
+): Promise<Pool[]> {
+  if (subgraphPoolsOriginal.length === 0) return subgraphPoolsOriginal;
+
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  const abis: any = Object.values(
+    // Remove duplicate entries using their names
+    Object.fromEntries(
+      [
+        ...Vault__factory.abi,
+        ...aTokenRateProvider,
+        ...weightedPoolAbi,
+        ...stablePoolAbi,
+        ...elementPoolAbi,
+        ...linearPoolAbi,
+        ...composableStableAbi,
+      ].map((row) => [row.name, row])
+    )
+  );
+
+  const multiPool = new Multicaller(multiAddress, provider, abis);
+
+  const supportedPoolTypes: string[] = Object.values(PoolFilter);
+  const subgraphPools: Pool[] = [];
+  subgraphPoolsOriginal.forEach((pool) => {
+    if (!supportedPoolTypes.includes(pool.poolType)) {
+      console.error(`Unknown pool type: ${pool.poolType} ${pool.id}`);
+      return;
+    }
+
+    subgraphPools.push(pool);
+
+    multiPool.call(`${pool.id}.poolTokens`, vaultAddress, 'getPoolTokens', [
+      pool.id,
+    ]);
+    multiPool.call(`${pool.id}.totalSupply`, pool.address, 'totalSupply');
+
+    // Pools with pre minted BPT
+    if (pool.poolType.includes('Linear') || pool.poolType === 'StablePhantom') {
+      multiPool.call(
+        `${pool.id}.virtualSupply`,
+        pool.address,
+        'getVirtualSupply'
+      );
+    }
+
+    /**
+     * Returns the effective BPT supply.
+     * In other pools, this would be the same as `totalSupply`, but there are two key differences here:
+     *  - this pool pre-mints BPT and holds it in the Vault as a token, and as such we need to subtract the Vault's
+     *    balance to get the total "circulating supply". This is called the 'virtualSupply'.
+     *  - the Pool owes debt to the Protocol in the form of unminted BPT, which will be minted immediately before the
+     *    next join or exit. We need to take these into account since, even if they don't yet exist, they will
+     *    effectively be included in any Pool operation that involves BPT.
+     * In the vast majority of cases, this function should be used instead of `totalSupply()`.
+     */
+    if (pool.poolType === 'ComposableStable')
+      multiPool.call(
+        `${pool.id}.actualSupply`,
+        pool.address,
+        'getActualSupply'
+      );
+
+    // TO DO - Make this part of class to make more flexible?
+    if (
+      pool.poolType === 'Weighted' ||
+      pool.poolType === 'LiquidityBootstrapping' ||
+      pool.poolType === 'Investment'
+    ) {
+      multiPool.call(
+        `${pool.id}.weights`,
+        pool.address,
+        'getNormalizedWeights'
+      );
+      multiPool.call(
+        `${pool.id}.swapFee`,
+        pool.address,
+        'getSwapFeePercentage'
+      );
+    } else if (
+      pool.poolType === 'Stable' ||
+      pool.poolType === 'MetaStable' ||
+      pool.poolType === 'StablePhantom' ||
+      pool.poolType === 'ComposableStable'
+    ) {
+      // MetaStable & StablePhantom is the same as Stable for multicall purposes
+      multiPool.call(
+        `${pool.id}.amp`,
+        pool.address,
+        'getAmplificationParameter'
+      );
+      multiPool.call(
+        `${pool.id}.swapFee`,
+        pool.address,
+        'getSwapFeePercentage'
+      );
+    } else if (pool.poolType === 'Element') {
+      multiPool.call(`${pool.id}.swapFee`, pool.address, 'percentFee');
+    } else if (pool.poolType.toString().includes('Linear')) {
+      multiPool.call(
+        `${pool.id}.swapFee`,
+        pool.address,
+        'getSwapFeePercentage'
+      );
+
+      multiPool.call(`${pool.id}.targets`, pool.address, 'getTargets');
+      multiPool.call(`${pool.id}.rate`, pool.address, 'getWrappedTokenRate');
+    } else if (pool.poolType.toString().includes('Gyro')) {
+      multiPool.call(
+        `${pool.id}.swapFee`,
+        pool.address,
+        'getSwapFeePercentage'
+      );
+    }
+  });
+
+  let pools = {} as Record<
+    string,
+    {
+      amp?: string[];
+      swapFee: string;
+      weights?: string[];
+      targets?: string[];
+      poolTokens: {
+        tokens: string[];
+        balances: string[];
+      };
+      totalSupply: string;
+      virtualSupply?: string;
+      rate?: string;
+      actualSupply?: string;
+    }
+  >;
+
+  try {
+    pools = (await multiPool.execute()) as Record<
+      string,
+      {
+        amp?: string[];
+        swapFee: string;
+        weights?: string[];
+        poolTokens: {
+          tokens: string[];
+          balances: string[];
+        };
+        totalSupply: string;
+        virtualSupply?: string;
+        rate?: string;
+        actualSupply?: string;
+      }
+    >;
+  } catch (err) {
+    throw `Issue with multicall execution.`;
+  }
+
+  const onChainPools: Pool[] = [];
+
+  Object.entries(pools).forEach(([poolId, onchainData], index) => {
+    try {
+      const {
+        poolTokens,
+        swapFee,
+        weights,
+        totalSupply,
+        virtualSupply,
+        actualSupply,
+      } = onchainData;
+
+      if (
+        subgraphPools[index].poolType === 'Stable' ||
+        subgraphPools[index].poolType === 'MetaStable' ||
+        subgraphPools[index].poolType === 'StablePhantom' ||
+        subgraphPools[index].poolType === 'ComposableStable'
+      ) {
+        if (!onchainData.amp) {
+          console.error(`Stable Pool Missing Amp: ${poolId}`);
+          return;
+        } else {
+          // Need to scale amp by precision to match expected Subgraph scale
+          // amp is stored with 3 decimals of precision
+          subgraphPools[index].amp = formatFixed(onchainData.amp[0], 3);
+        }
+      }
+
+      if (subgraphPools[index].poolType.includes('Linear')) {
+        if (!onchainData.targets) {
+          console.error(`Linear Pool Missing Targets: ${poolId}`);
+          return;
+        } else {
+          subgraphPools[index].lowerTarget = formatFixed(
+            onchainData.targets[0],
+            18
+          );
+          subgraphPools[index].upperTarget = formatFixed(
+            onchainData.targets[1],
+            18
+          );
+        }
+
+        const wrappedIndex = subgraphPools[index].wrappedIndex;
+        if (wrappedIndex === undefined || onchainData.rate === undefined) {
+          console.error(
+            `Linear Pool Missing WrappedIndex or PriceRate: ${poolId}`
+          );
+          return;
+        }
+        // Update priceRate of wrappedToken
+        subgraphPools[index].tokens[wrappedIndex].priceRate = formatFixed(
+          onchainData.rate,
+          18
+        );
+      }
+
+      subgraphPools[index].swapFee = formatFixed(swapFee, 18);
+
+      poolTokens.tokens.forEach((token, i) => {
+        const T = subgraphPools[index].tokens.find((t) =>
+          isSameAddress(t.address, token)
+        );
+        if (!T) throw `Pool Missing Expected Token: ${poolId} ${token}`;
+        T.balance = formatFixed(poolTokens.balances[i], T.decimals);
+        if (weights) {
+          // Only expected for WeightedPools
+          T.weight = formatFixed(weights[i], 18);
+        }
+      });
+
+      // Pools with pre minted BPT
+      if (
+        subgraphPools[index].poolType.includes('Linear') ||
+        subgraphPools[index].poolType === 'StablePhantom'
+      ) {
+        if (virtualSupply === undefined) {
+          console.error(
+            `Pool with pre-minted BPT missing Virtual Supply: ${poolId}`
+          );
+          return;
+        }
+        subgraphPools[index].totalShares = formatFixed(virtualSupply, 18);
+      } else if (subgraphPools[index].poolType === 'ComposableStable') {
+        if (actualSupply === undefined) {
+          console.error(`ComposableStable missing Actual Supply: ${poolId}`);
+          return;
+        }
+        subgraphPools[index].totalShares = formatFixed(actualSupply, 18);
+      } else {
+        subgraphPools[index].totalShares = formatFixed(totalSupply, 18);
+      }
+
+      onChainPools.push(subgraphPools[index]);
+    } catch (err) {
+      throw `Issue with pool onchain data: ${err}`;
+    }
+  });
+
+  return onChainPools;
+}
diff --git a/balancer-js/src/modules/data/pool/subgraph.ts b/balancer-js/src/modules/data/pool/subgraph.ts
index 5fb495660..18ad56425 100644
--- a/balancer-js/src/modules/data/pool/subgraph.ts
+++ b/balancer-js/src/modules/data/pool/subgraph.ts
@@ -33,11 +33,11 @@ interface PoolsSubgraphRepositoryOptions {
   query?: GraphQLQuery;
 }
 
-interface SubgraphSubPoolToken extends SubgraphSubPoolTokenFragment {
+export interface SubgraphSubPoolToken extends SubgraphSubPoolTokenFragment {
   token?: SubgraphSubPoolMeta | null;
 }
 
-interface SubgraphSubPoolMeta {
+export interface SubgraphSubPoolMeta {
   latestUSDPrice?: string | null;
   pool?: SubgraphSubPool | null;
 }
@@ -107,8 +107,7 @@ export class PoolsSubgraphRepository
       where: { swapEnabled: true, totalShares_gt: '0.000000000001' },
       orderBy: Pool_OrderBy.TotalLiquidity,
       orderDirection: OrderDirection.Desc,
-      // block: await this.block(),
-      block: { number: 16067738 },
+      block: await this.block(),
     });
     console.timeEnd('fetching pools');
 
diff --git a/balancer-js/src/modules/data/pool/subgraphOnChain.ts b/balancer-js/src/modules/data/pool/subgraphOnChain.ts
new file mode 100644
index 000000000..dea17d097
--- /dev/null
+++ b/balancer-js/src/modules/data/pool/subgraphOnChain.ts
@@ -0,0 +1,295 @@
+import { Findable, Searchable } from '../types';
+import {
+  createSubgraphClient,
+  SubgraphClient,
+  SubgraphPool,
+  Pool_OrderBy,
+  OrderDirection,
+  SubgraphPoolTokenFragment,
+} from '@/modules/subgraph/subgraph';
+import {
+  GraphQLArgsBuilder,
+  SubgraphArgsFormatter,
+} from '@/lib/graphql/args-builder';
+import { GraphQLArgs } from '@/lib/graphql/types';
+import { Provider } from '@ethersproject/providers';
+import { PoolAttribute, PoolsRepositoryFetchOptions } from './types';
+import {
+  GraphQLQuery,
+  Pool,
+  PoolType,
+  PoolToken,
+  SubPool,
+  SubPoolMeta,
+} from '@/types';
+import { Network } from '@/lib/constants/network';
+import { PoolsQueryVariables } from '../../subgraph/subgraph';
+import { getOnChainBalances } from './onChainData';
+import { SubgraphSubPoolMeta, SubgraphSubPoolToken } from './subgraph';
+
+interface PoolsSubgraphOnChainRepositoryOptions {
+  url: string;
+  chainId: Network;
+  provider: Provider;
+  multicall: string;
+  vault: string;
+  blockHeight?: () => Promise<number | undefined>;
+  query?: GraphQLQuery;
+}
+
+/**
+ * Access pools using generated subgraph client.
+ *
+ * Balancer's subgraph URL: https://thegraph.com/hosted-service/subgraph/balancer-labs/balancer-v2
+ */
+export class PoolsSubgraphOnChainRepository
+  implements Findable<Pool, PoolAttribute>, Searchable<Pool>
+{
+  private client: SubgraphClient;
+  private chainId: Network;
+  private provider: Provider;
+  private pools?: Promise<Pool[]>;
+  private multicall: string;
+  private vault: string;
+  public skip = 0;
+  private blockHeight: undefined | (() => Promise<number | undefined>);
+  private query: GraphQLQuery;
+
+  /**
+   * Repository with optional lazy loaded blockHeight
+   *
+   * @param url subgraph URL
+   * @param chainId current network, needed for L2s logic
+   * @param blockHeight lazy loading blockHeigh resolver
+   * @param multicall multicall address
+   * @param valt vault address
+   */
+  constructor(options: PoolsSubgraphOnChainRepositoryOptions) {
+    this.client = createSubgraphClient(options.url);
+    this.blockHeight = options.blockHeight;
+    this.chainId = options.chainId;
+    this.provider = options.provider;
+    this.multicall = options.multicall;
+    this.vault = options.vault;
+
+    const defaultArgs: GraphQLArgs = {
+      orderBy: Pool_OrderBy.TotalLiquidity,
+      orderDirection: OrderDirection.Desc,
+      where: {
+        swapEnabled: {
+          eq: true,
+        },
+        totalShares: {
+          gt: 0.000000000001,
+        },
+      },
+    };
+
+    const args = options.query?.args || defaultArgs;
+    const attrs = options.query?.attrs || {};
+
+    this.query = {
+      args,
+      attrs,
+    };
+  }
+
+  /**
+   * We need a list of all the pools, for calculating APRs (nested pools), and for SOR (path finding).
+   * All the pools are fetched on page load and cachced for speedy lookups.
+   *
+   * @returns Promise resolving to pools list
+   */
+  private async fetchDefault(): Promise<Pool[]> {
+    console.time('fetching pools');
+    const { pool0, pool1000, pool2000 } = await this.client.AllPools(
+      await this.getDefaultFilter(this.query.args)
+    );
+    const pools = [...pool0, ...pool1000, ...pool2000].map(
+      this.mapType.bind(this)
+    );
+    console.timeEnd('fetching pools');
+    console.log(pools.length, 'Example filter should limit the pools length');
+    console.log('Fetching onchain!');
+    const onchainPools = await getOnChainBalances(
+      pools,
+      this.multicall,
+      this.vault,
+      this.provider
+    );
+
+    return onchainPools;
+  }
+
+  async fetch(options?: PoolsRepositoryFetchOptions): Promise<Pool[]> {
+    if (options?.skip) {
+      this.query.args.skip = options.skip;
+    }
+    if (!this.query.args.block) {
+      this.query.args.block = await this.block();
+    }
+
+    this.query.args.first = options?.first || 1000;
+
+    const formattedQuery = new GraphQLArgsBuilder(this.query.args).format(
+      new SubgraphArgsFormatter()
+    ) as PoolsQueryVariables;
+
+    const { pools } = await this.client.Pools(formattedQuery);
+
+    this.skip = (options?.skip || 0) + pools.length;
+
+    return pools.map(this.mapType.bind(this));
+  }
+
+  async find(id: string): Promise<Pool | undefined> {
+    return await this.findBy('id', id);
+  }
+
+  async findBy(param: PoolAttribute, value: string): Promise<Pool | undefined> {
+    if (!this.pools) {
+      this.pools = this.fetchDefault();
+    }
+
+    return (await this.pools).find((pool) => pool[param] == value);
+
+    // TODO: @Nma - Fetching pools outside of default query is causing a lot of requests
+    // on a frontend, because results aren't cached anywhere.
+    // For fetching pools directly from subgraph with custom queries please use the client not this repository.
+    // Code below kept for reference, to be removed later.
+    //
+    // if (this.pools) {
+    //   return (await this.pools).find((p) => p[param] === value);
+    // }
+    // const { pools } = await this.client.Pools({
+    //   where: {
+    //     [param]: value,
+    //     swapEnabled: true,
+    //     totalShares_gt: '0.000000000001',
+    //   },
+    //   block: await this.block(),
+    // });
+    // const poolsTab: Pool[] = pools.map(this.mapType.bind(this));
+    // return poolsTab.length > 0 ? poolsTab[0] : undefined;
+  }
+
+  async all(): Promise<Pool[]> {
+    if (!this.pools) {
+      this.pools = this.fetchDefault();
+    }
+    return this.pools;
+  }
+
+  async block(): Promise<{ number: number | undefined } | undefined> {
+    return this.blockHeight ? { number: await this.blockHeight() } : undefined;
+  }
+
+  async getDefaultFilter(args: GraphQLArgs): Promise<PoolsQueryVariables> {
+    const formattedQuery = new GraphQLArgsBuilder(args).format(
+      new SubgraphArgsFormatter()
+    ) as PoolsQueryVariables;
+    if (!formattedQuery.block) {
+      formattedQuery.block = await this.block();
+    }
+    return formattedQuery;
+  }
+
+  async where(filter: (pool: Pool) => boolean): Promise<Pool[]> {
+    if (!this.pools) {
+      this.pools = this.fetchDefault();
+    }
+
+    return (await this.pools).filter(filter);
+  }
+
+  private mapType(subgraphPool: SubgraphPool): Pool {
+    return {
+      id: subgraphPool.id,
+      name: subgraphPool.name || '',
+      address: subgraphPool.address,
+      chainId: this.chainId,
+      poolType: subgraphPool.poolType as PoolType,
+      poolTypeVersion: subgraphPool.poolTypeVersion || 1,
+      swapFee: subgraphPool.swapFee,
+      swapEnabled: subgraphPool.swapEnabled,
+      protocolYieldFeeCache: subgraphPool.protocolYieldFeeCache || '0',
+      amp: subgraphPool.amp ?? undefined,
+      owner: subgraphPool.owner ?? undefined,
+      factory: subgraphPool.factory ?? undefined,
+      symbol: subgraphPool.symbol ?? undefined,
+      tokens: (subgraphPool.tokens || []).map(this.mapToken.bind(this)),
+      tokensList: subgraphPool.tokensList,
+      tokenAddresses: (subgraphPool.tokens || []).map((t) => t.address),
+      totalLiquidity: subgraphPool.totalLiquidity,
+      totalShares: subgraphPool.totalShares,
+      totalSwapFee: subgraphPool.totalSwapFee,
+      totalSwapVolume: subgraphPool.totalSwapVolume,
+      priceRateProviders: subgraphPool.priceRateProviders ?? undefined,
+      // onchain: subgraphPool.onchain,
+      createTime: subgraphPool.createTime,
+      mainIndex: subgraphPool.mainIndex ?? undefined,
+      wrappedIndex: subgraphPool.wrappedIndex ?? undefined,
+      // mainTokens: subgraphPool.mainTokens,
+      // wrappedTokens: subgraphPool.wrappedTokens,
+      // unwrappedTokens: subgraphPool.unwrappedTokens,
+      // isNew: subgraphPool.isNew,
+      // volumeSnapshot: subgraphPool.volumeSnapshot,
+      // feesSnapshot: subgraphPool.???, // Approximated last 24h fees
+      // boost: subgraphPool.boost,
+      totalWeight: subgraphPool.totalWeight || '1',
+      lowerTarget: subgraphPool.lowerTarget ?? '0',
+      upperTarget: subgraphPool.upperTarget ?? '0',
+    };
+  }
+
+  private mapToken(subgraphToken: SubgraphPoolTokenFragment): PoolToken {
+    const subPoolInfo = this.mapSubPools(
+      // need to typecast as the fragment is 3 layers deep while the type is infinite levels deep
+      subgraphToken.token as SubgraphSubPoolMeta
+    );
+    return {
+      ...subgraphToken,
+      isExemptFromYieldProtocolFee:
+        subgraphToken.isExemptFromYieldProtocolFee || false,
+      token: subPoolInfo,
+    };
+  }
+
+  private mapSubPools(metadata: SubgraphSubPoolMeta): SubPoolMeta {
+    let subPool: SubPool | null = null;
+    if (metadata.pool) {
+      subPool = {
+        id: metadata.pool.id,
+        address: metadata.pool.address,
+        totalShares: metadata.pool.totalShares,
+        poolType: metadata.pool.poolType as PoolType,
+        mainIndex: metadata.pool.mainIndex || 0,
+      };
+
+      if (metadata?.pool.tokens) {
+        subPool.tokens = metadata.pool.tokens.map(
+          this.mapSubPoolToken.bind(this)
+        );
+      }
+    }
+
+    return {
+      pool: subPool,
+      latestUSDPrice: metadata.latestUSDPrice || undefined,
+    };
+  }
+
+  private mapSubPoolToken(token: SubgraphSubPoolToken) {
+    return {
+      address: token.address,
+      decimals: token.decimals,
+      symbol: token.symbol,
+      balance: token.balance,
+      priceRate: token.priceRate,
+      weight: token.weight,
+      isExemptFromYieldProtocolFee:
+        token.isExemptFromYieldProtocolFee || undefined,
+      token: token.token ? this.mapSubPools(token.token) : undefined,
+    };
+  }
+}
diff --git a/balancer-js/src/modules/graph/graph.ts b/balancer-js/src/modules/graph/graph.ts
index c2bc03cbc..ac24ade16 100644
--- a/balancer-js/src/modules/graph/graph.ts
+++ b/balancer-js/src/modules/graph/graph.ts
@@ -150,7 +150,7 @@ export class PoolGraph {
         decimals = token.decimals ? token.decimals : 18;
         return;
       }
-      const sp = controller.calcSpotPrice(token.address, pool.address, true);
+      const sp = controller.calcSpotPrice(token.address, pool.address, false);
       spotPrices[token.address] = sp;
     });
 
diff --git a/balancer-js/src/modules/joins/debug.module.integration.spec.ts b/balancer-js/src/modules/joins/debug.module.integration.spec.ts
index c54471efc..ad3e52f22 100644
--- a/balancer-js/src/modules/joins/debug.module.integration.spec.ts
+++ b/balancer-js/src/modules/joins/debug.module.integration.spec.ts
@@ -24,7 +24,7 @@ const TEST_BOOSTED = true;
  * - Uncomment section below:
  */
 const network = Network.MAINNET;
-const blockNumber = 16067738;
+const blockNumber = 16176441;
 const customSubgraphUrl =
   'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2';
 const { ALCHEMY_URL: jsonRpcUrl } = process.env;
diff --git a/balancer-js/src/modules/joins/joins.module.ts b/balancer-js/src/modules/joins/joins.module.ts
index 9b4f252de..d3e357775 100644
--- a/balancer-js/src/modules/joins/joins.module.ts
+++ b/balancer-js/src/modules/joins/joins.module.ts
@@ -122,9 +122,8 @@ export class Join {
       true
     ).toString();
 
-    console.log(totalMinAmountOut, `totalMinOut`);
+    console.log(totalAmountOut, `totalAmountOut`);
     console.log(totalBptZeroPi.toString(), `totalBptZeroPi`);
-
     // Create calls with minAmountsOut
     const { callData, deltas } = await this.createCalls(
       joinPaths,
diff --git a/balancer-js/src/modules/pools/index.ts b/balancer-js/src/modules/pools/index.ts
index 24a87cf07..c7bede9eb 100644
--- a/balancer-js/src/modules/pools/index.ts
+++ b/balancer-js/src/modules/pools/index.ts
@@ -48,8 +48,8 @@ export class Pools implements Findable<PoolWithMethods> {
       repositories.pools,
       repositories.tokenPrices
     );
-    this.joinService = new Join(this.repositories.pools, networkConfig);
-    this.exitService = new Exit(this.repositories.pools, networkConfig);
+    this.joinService = new Join(this.repositories.poolsOnChain, networkConfig);
+    this.exitService = new Exit(this.repositories.poolsOnChain, networkConfig);
     this.feesService = new PoolFees(repositories.yesterdaysPools);
     this.volumeService = new PoolVolume(repositories.yesterdaysPools);
     this.impermanentLossService = new ImpermanentLossService(
diff --git a/balancer-js/src/types.ts b/balancer-js/src/types.ts
index 4b4eaf6ef..ef36bee28 100644
--- a/balancer-js/src/types.ts
+++ b/balancer-js/src/types.ts
@@ -98,6 +98,7 @@ export interface BalancerNetworkConfig {
 
 export interface BalancerDataRepositories {
   pools: Findable<Pool, PoolAttribute> & Searchable<Pool>;
+  poolsOnChain: Findable<Pool, PoolAttribute> & Searchable<Pool>;
   yesterdaysPools?: Findable<Pool, PoolAttribute> & Searchable<Pool>;
   tokenPrices: Findable<Price>;
   tokenHistoricalPrices: Findable<Price>;
diff --git a/balancer-js/yarn.lock b/balancer-js/yarn.lock
index b5760cda8..4b34752df 100644
--- a/balancer-js/yarn.lock
+++ b/balancer-js/yarn.lock
@@ -503,10 +503,9 @@
     "@babel/helper-validator-identifier" "^7.19.1"
     to-fast-properties "^2.0.0"
 
-"@balancer-labs/sor@^4.0.1-beta.15":
-  version "4.0.1-beta.15"
-  resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.0.1-beta.15.tgz#4fc6ae8df195a20abf597babb5453a5d303bdcda"
-  integrity sha512-8BlaQqmV56gs4b2YFs6xjBFGIxthg7SEjuxDcb7Q45AUUdFutGKsX8glC2hI4ZDM5+7W0FmNwGnKF2OrzFsuiQ==
+"@balancer-labs/sor@/Users/jg/Documents/balancer-sor/balancer-labs-sor-v4.0.1-beta.22.tgz":
+  version "4.0.1-beta.22"
+  resolved "/Users/jg/Documents/balancer-sor/balancer-labs-sor-v4.0.1-beta.22.tgz#d159ee89feb9cbf01b4807fe402334f8a3b6dc89"
   dependencies:
     isomorphic-fetch "^2.2.1"
 

From 14baecda9b9188f5a1d7a83bc8ca6e48ab7855b0 Mon Sep 17 00:00:00 2001
From: Bruno Eidam Guerios <bruno@balancer.finance>
Date: Tue, 20 Dec 2022 16:00:02 -0300
Subject: [PATCH 03/25] Fix SubgraphPriceRepository overriding
 customSubgraphUrl provided on sdk config

---
 balancer-js/src/modules/data/index.ts                 | 1 +
 balancer-js/src/modules/data/token-prices/subgraph.ts | 4 +---
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/balancer-js/src/modules/data/index.ts b/balancer-js/src/modules/data/index.ts
index 57cc72428..fb4666a56 100644
--- a/balancer-js/src/modules/data/index.ts
+++ b/balancer-js/src/modules/data/index.ts
@@ -116,6 +116,7 @@ export class Data implements BalancerDataRepositories {
     );
 
     const subgraphPriceRepository = new SubgraphPriceRepository(
+      networkConfig.urls.subgraph,
       networkConfig.chainId
     );
 
diff --git a/balancer-js/src/modules/data/token-prices/subgraph.ts b/balancer-js/src/modules/data/token-prices/subgraph.ts
index af46361ba..c9ff89eb7 100644
--- a/balancer-js/src/modules/data/token-prices/subgraph.ts
+++ b/balancer-js/src/modules/data/token-prices/subgraph.ts
@@ -16,12 +16,10 @@ interface SubgraphPricesResponse {
 }
 
 export class SubgraphPriceRepository implements Findable<Price> {
-  private subgraphUrl: string;
   prices: { [key: string]: Promise<Price> } = {};
   debouncer: Debouncer<TokenPrices, string>;
 
-  constructor(private chainId: Network = 1) {
-    this.subgraphUrl = BALANCER_NETWORK_CONFIG[chainId].urls.subgraph;
+  constructor(private subgraphUrl: string, private chainId: Network = 1) {
     this.debouncer = new Debouncer<TokenPrices, string>(
       this.fetch.bind(this),
       200

From 47858c2897e94e4be27949112193f33607058ee8 Mon Sep 17 00:00:00 2001
From: Bruno Eidam Guerios <bruno@balancer.finance>
Date: Tue, 20 Dec 2022 16:08:32 -0300
Subject: [PATCH 04/25] Fix lint issue

---
 balancer-js/src/modules/data/token-prices/subgraph.ts | 1 -
 1 file changed, 1 deletion(-)

diff --git a/balancer-js/src/modules/data/token-prices/subgraph.ts b/balancer-js/src/modules/data/token-prices/subgraph.ts
index c9ff89eb7..b02590876 100644
--- a/balancer-js/src/modules/data/token-prices/subgraph.ts
+++ b/balancer-js/src/modules/data/token-prices/subgraph.ts
@@ -1,7 +1,6 @@
 /* eslint-disable @typescript-eslint/no-empty-function */
 import { Price, Findable, TokenPrices, Network } from '@/types';
 import axios from 'axios';
-import { BALANCER_NETWORK_CONFIG } from '@/lib/constants/config';
 import { Debouncer, tokenAddressForPricing } from '@/lib/utils';
 
 interface SubgraphPricesResponse {

From 1ae583431c61efbe8fa0a964faf47c9851436422 Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Wed, 4 Jan 2023 11:30:36 +0000
Subject: [PATCH 05/25] Fix factory.

---
 balancer-js/src/test/factories/data.ts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/balancer-js/src/test/factories/data.ts b/balancer-js/src/test/factories/data.ts
index 81267b072..5a489558f 100644
--- a/balancer-js/src/test/factories/data.ts
+++ b/balancer-js/src/test/factories/data.ts
@@ -78,6 +78,7 @@ export const repositores = ({
   ),
 }): BalancerDataRepositories => ({
   pools,
+  poolsOnChain: pools,
   yesterdaysPools,
   tokenPrices,
   tokenHistoricalPrices,

From a980b95ea0090ec56a0564ccc85f8dad50f4fbe2 Mon Sep 17 00:00:00 2001
From: bronco <rg3mvdb0@protonmail.com>
Date: Wed, 4 Jan 2023 13:29:52 +0100
Subject: [PATCH 06/25] new: emissions service

---
 balancer-js/examples/pools/emissions.ts       | 21 +++++++++++++
 balancer-js/src/modules/data/types.ts         |  1 +
 .../src/modules/pools/emissions/index.spec.ts | 30 +++++++++++++++++++
 .../src/modules/pools/emissions/index.ts      | 26 ++++++++++++++++
 balancer-js/src/modules/pools/index.ts        |  7 +++++
 balancer-js/src/test/factories/index.ts       |  3 +-
 .../src/test/factories/liquidity-gauges.ts    | 17 +++++++++++
 7 files changed, 104 insertions(+), 1 deletion(-)
 create mode 100644 balancer-js/examples/pools/emissions.ts
 create mode 100644 balancer-js/src/modules/pools/emissions/index.spec.ts
 create mode 100644 balancer-js/src/modules/pools/emissions/index.ts
 create mode 100644 balancer-js/src/test/factories/liquidity-gauges.ts

diff --git a/balancer-js/examples/pools/emissions.ts b/balancer-js/examples/pools/emissions.ts
new file mode 100644
index 000000000..4c405ee2d
--- /dev/null
+++ b/balancer-js/examples/pools/emissions.ts
@@ -0,0 +1,21 @@
+/**
+ * Display weekly BAL emissiosn for a pool
+ * Run command: yarn examples:run ./examples/pools/emissions.ts
+ */
+import { BalancerSDK } from '@/.'
+
+const sdk = new BalancerSDK({
+  network: 1,
+  rpcUrl: 'https://rpc.ankr.com/eth',
+})
+
+const { pools } = sdk
+
+const main = async () => {
+  if (pools.emissionsService) {
+    const emissions = await pools.emissionsService.weekly('0x334c96d792e4b26b841d28f53235281cec1be1f200020000000000000000038a')
+    console.log(emissions)
+  }
+}
+
+main()
diff --git a/balancer-js/src/modules/data/types.ts b/balancer-js/src/modules/data/types.ts
index 939d5a9f2..5a0150f14 100644
--- a/balancer-js/src/modules/data/types.ts
+++ b/balancer-js/src/modules/data/types.ts
@@ -1,6 +1,7 @@
 /* eslint-disable @typescript-eslint/no-explicit-any */
 
 export { LiquidityGauge } from './liquidity-gauges/provider';
+export { RewardData } from './liquidity-gauges/multicall';
 export { PoolAttribute } from './pool/types';
 export { TokenAttribute } from './token/types';
 export { ProtocolFees } from './protocol-fees/provider';
diff --git a/balancer-js/src/modules/pools/emissions/index.spec.ts b/balancer-js/src/modules/pools/emissions/index.spec.ts
new file mode 100644
index 000000000..1b336c468
--- /dev/null
+++ b/balancer-js/src/modules/pools/emissions/index.spec.ts
@@ -0,0 +1,30 @@
+import * as emissions from '@/modules/data/bal/emissions';
+import { factories } from '@/test/factories';
+import { LiquidityGauge } from '@/types';
+import { expect } from 'chai';
+import { EmissionsService } from './';
+
+const poolId = '1';
+const relativeWeight = 0.1;
+const gauge = factories.gaugesFactory.build({ poolId, relativeWeight });
+
+const gaugesMap = new Map([['1', gauge]]);
+const gauges = factories.data.findable<LiquidityGauge>(gaugesMap);
+const service = new EmissionsService(gauges);
+const total = emissions.weekly();
+
+describe('EmissionsService', () => {
+  context('with liquidity gauge', () => {
+    it('.weekly returns a value', async () => {
+      const bal = await service.weekly(poolId);
+      expect(bal).to.eq(total * relativeWeight);
+    });
+  });
+
+  context('without liquidity gauge', () => {
+    it('.weekly returns 0', async () => {
+      const bal = await service.weekly('abc');
+      expect(bal).to.eq(0);
+    });
+  });
+});
diff --git a/balancer-js/src/modules/pools/emissions/index.ts b/balancer-js/src/modules/pools/emissions/index.ts
new file mode 100644
index 000000000..3fbe06195
--- /dev/null
+++ b/balancer-js/src/modules/pools/emissions/index.ts
@@ -0,0 +1,26 @@
+import * as emissions from '@/modules/data/bal/emissions';
+import { Findable, LiquidityGauge } from '@/types';
+
+/**
+ * Returns BAL emissions per pool
+ */
+export class EmissionsService {
+  constructor(private liquidityGaugesRepository: Findable<LiquidityGauge>) {}
+
+  async relativeWeight(poolId: string): Promise<number> {
+    const gauge = await this.liquidityGaugesRepository.findBy('poolId', poolId);
+
+    if (gauge) {
+      return gauge.relativeWeight;
+    }
+
+    return 0;
+  }
+
+  async weekly(poolId: string): Promise<number> {
+    const perWeek = emissions.weekly();
+    const relativeWeight = await this.relativeWeight(poolId);
+
+    return perWeek * relativeWeight;
+  }
+}
diff --git a/balancer-js/src/modules/pools/index.ts b/balancer-js/src/modules/pools/index.ts
index 93e100561..086a986a2 100644
--- a/balancer-js/src/modules/pools/index.ts
+++ b/balancer-js/src/modules/pools/index.ts
@@ -19,6 +19,7 @@ import { PoolVolume } from './volume/volume';
 import { PoolFees } from './fees/fees';
 import * as Queries from './queries';
 import { BalancerError } from '@/balancerErrors';
+import { EmissionsService } from './emissions';
 
 const notImplemented = (poolType: string, name: string) => () => {
   throw `${name} for poolType ${poolType} not implemented`;
@@ -35,6 +36,7 @@ export class Pools implements Findable<PoolWithMethods> {
   feesService;
   volumeService;
   impermanentLossService;
+  emissionsService;
 
   constructor(
     private networkConfig: BalancerNetworkConfig,
@@ -62,6 +64,11 @@ export class Pools implements Findable<PoolWithMethods> {
       repositories.tokenPrices,
       repositories.tokenHistoricalPrices
     );
+    if (repositories.liquidityGauges) {
+      this.emissionsService = new EmissionsService(
+        repositories.liquidityGauges
+      );
+    }
   }
 
   dataSource(): Findable<Pool, PoolAttribute> & Searchable<Pool> {
diff --git a/balancer-js/src/test/factories/index.ts b/balancer-js/src/test/factories/index.ts
index 11f0d81aa..7d3846f95 100644
--- a/balancer-js/src/test/factories/index.ts
+++ b/balancer-js/src/test/factories/index.ts
@@ -1,8 +1,9 @@
 import * as sor from './sor';
 import * as pools from './pools';
+import * as liquidityGauges from './liquidity-gauges';
 import * as sdk from './sdk';
 import * as data from './data';
 
-const factories = { ...sor, ...pools, ...sdk, data };
+const factories = { ...sor, ...pools, ...sdk, ...liquidityGauges, data };
 
 export { factories };
diff --git a/balancer-js/src/test/factories/liquidity-gauges.ts b/balancer-js/src/test/factories/liquidity-gauges.ts
new file mode 100644
index 000000000..fa6ae966e
--- /dev/null
+++ b/balancer-js/src/test/factories/liquidity-gauges.ts
@@ -0,0 +1,17 @@
+import { Factory } from 'fishery';
+import { LiquidityGauge, RewardData } from '@/types';
+
+export const gaugesFactory = Factory.define<LiquidityGauge>(({ params }) => {
+  return {
+    id: params.id || '1',
+    address: params.address || '1',
+    name: params.name || 'gauge',
+    poolId: params.poolId || '1',
+    poolAddress: params.poolAddress || '1',
+    totalSupply: params.totalSupply || 1,
+    workingSupply: params.workingSupply || 1,
+    relativeWeight: params.relativeWeight || 1,
+    rewardTokens:
+      (params.rewardTokens as { [tokenAddress: string]: RewardData }) || [],
+  };
+});

From dd018a40f92b79beb4090211a22c6b0e96e41b03 Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Wed, 4 Jan 2023 13:13:27 +0000
Subject: [PATCH 07/25] Add custom sg query to Data module.

---
 balancer-js/src/modules/data/index.ts         | 36 ++++++-------------
 .../exits/exits.module.integration.spec.ts    | 33 +++++++++++++++--
 .../joins/debug.module.integration.spec.ts    | 26 +++++++++++++-
 .../joins/joins.module.integration.spec.ts    | 33 +++++++++++++++--
 .../concerns/metaStable/spotPrice.spec.ts     |  2 +-
 .../concerns/stable/spotPrice.spec.ts         |  2 +-
 .../concerns/stablePhantom/spotPrice.spec.ts  |  2 +-
 balancer-js/src/modules/sdk.module.ts         |  6 +++-
 balancer-js/src/types.ts                      |  1 +
 9 files changed, 106 insertions(+), 35 deletions(-)

diff --git a/balancer-js/src/modules/data/index.ts b/balancer-js/src/modules/data/index.ts
index d44911131..a1261df12 100644
--- a/balancer-js/src/modules/data/index.ts
+++ b/balancer-js/src/modules/data/index.ts
@@ -14,8 +14,11 @@ export * from './protocol-fees/provider';
 export * from './token-yields/repository';
 export * from './block-number';
 
-import { GraphQLArgs } from '@/.';
-import { BalancerNetworkConfig, BalancerDataRepositories } from '@/types';
+import {
+  BalancerNetworkConfig,
+  BalancerDataRepositories,
+  GraphQLQuery,
+} from '@/types';
 import { PoolsSubgraphRepository } from './pool/subgraph';
 import { PoolSharesRepository } from './pool-shares/repository';
 import { PoolJoinExitRepository } from './pool-joinExit/repository';
@@ -61,35 +64,16 @@ export class Data implements BalancerDataRepositories {
   blockNumbers;
   poolJoinExits;
 
-  constructor(networkConfig: BalancerNetworkConfig, provider: Provider) {
+  constructor(
+    networkConfig: BalancerNetworkConfig,
+    provider: Provider,
+    subgraphQuery?: GraphQLQuery
+  ) {
     this.pools = new PoolsSubgraphRepository({
       url: networkConfig.urls.subgraph,
       chainId: networkConfig.chainId,
     });
 
-    const subgraphArgs: GraphQLArgs = {
-      where: {
-        swapEnabled: {
-          eq: true,
-        },
-        totalShares: {
-          gt: 0.000000000001,
-        },
-        id: {
-          in: [
-            '0xa13a9247ea42d743238089903570127dda72fe4400000000000000000000035d',
-            '0x2F4EB100552EF93840D5ADC30560E5513DFFFACB000000000000000000000334'.toLowerCase(),
-            '0xAE37D54AE477268B9997D4161B96B8200755935C000000000000000000000337'.toLowerCase(),
-            '0x82698AECC9E28E9BB27608BD52CF57F704BD1B83000000000000000000000336'.toLowerCase(),
-          ],
-        },
-      },
-      orderBy: 'totalLiquidity',
-      orderDirection: 'desc',
-      block: { number: 16176441 },
-    };
-    const subgraphQuery = { args: subgraphArgs, attrs: {} };
-
     this.poolsOnChain = new PoolsSubgraphOnChainRepository({
       url: networkConfig.urls.subgraph,
       chainId: networkConfig.chainId,
diff --git a/balancer-js/src/modules/exits/exits.module.integration.spec.ts b/balancer-js/src/modules/exits/exits.module.integration.spec.ts
index 9cdb66a29..4a5564b97 100644
--- a/balancer-js/src/modules/exits/exits.module.integration.spec.ts
+++ b/balancer-js/src/modules/exits/exits.module.integration.spec.ts
@@ -3,7 +3,13 @@ import dotenv from 'dotenv';
 import { expect } from 'chai';
 import hardhat from 'hardhat';
 
-import { BalancerSDK, BalancerTenderlyConfig, Network } from '@/.';
+import {
+  BalancerSDK,
+  BalancerTenderlyConfig,
+  Network,
+  GraphQLQuery,
+  GraphQLArgs,
+} from '@/.';
 import { BigNumber, parseFixed } from '@ethersproject/bignumber';
 import { Contracts } from '@/modules/contracts/contracts.module';
 import { forkSetup, getBalances } from '@/test/lib/utils';
@@ -50,6 +56,7 @@ const rpcUrl = 'http://127.0.0.1:8000';
 const { TENDERLY_ACCESS_KEY, TENDERLY_USER, TENDERLY_PROJECT } = process.env;
 const { ethers } = hardhat;
 const MAX_GAS_LIMIT = 8e6;
+const addresses = ADDRESSES[network];
 
 // Custom Tenderly configuration parameters - remove in order to use default values
 const tenderlyConfig: BalancerTenderlyConfig = {
@@ -59,11 +66,34 @@ const tenderlyConfig: BalancerTenderlyConfig = {
   blockNumber,
 };
 
+const poolAddresses = Object.values(addresses).map(
+  (address) => address.address
+);
+
+const subgraphArgs: GraphQLArgs = {
+  where: {
+    swapEnabled: {
+      eq: true,
+    },
+    totalShares: {
+      gt: 0.000000000001,
+    },
+    address: {
+      in: poolAddresses,
+    },
+  },
+  orderBy: 'totalLiquidity',
+  orderDirection: 'desc',
+  block: { number: blockNumber },
+};
+const subgraphQuery: GraphQLQuery = { args: subgraphArgs, attrs: {} };
+
 const sdk = new BalancerSDK({
   network,
   rpcUrl,
   customSubgraphUrl,
   tenderly: tenderlyConfig,
+  subgraphQuery,
 });
 const { pools } = sdk;
 const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network);
@@ -73,7 +103,6 @@ const { contracts, contractAddresses } = new Contracts(
   provider
 );
 const relayer = contractAddresses.relayerV4 as string;
-const addresses = ADDRESSES[network];
 
 interface Test {
   signer: JsonRpcSigner;
diff --git a/balancer-js/src/modules/joins/debug.module.integration.spec.ts b/balancer-js/src/modules/joins/debug.module.integration.spec.ts
index ad3e52f22..c2a43a242 100644
--- a/balancer-js/src/modules/joins/debug.module.integration.spec.ts
+++ b/balancer-js/src/modules/joins/debug.module.integration.spec.ts
@@ -3,7 +3,7 @@ import dotenv from 'dotenv';
 import { expect } from 'chai';
 import hardhat from 'hardhat';
 
-import { BalancerSDK, BalancerTenderlyConfig, Network } from '@/.';
+import { BalancerSDK, BalancerTenderlyConfig, Network, GraphQLArgs } from '@/.';
 import { BigNumber, formatFixed, parseFixed } from '@ethersproject/bignumber';
 import { Contracts } from '@/modules/contracts/contracts.module';
 import { forkSetup, getBalances } from '@/test/lib/utils';
@@ -41,11 +41,35 @@ const tenderlyConfig: BalancerTenderlyConfig = {
   blockNumber,
 };
 
+const subgraphArgs: GraphQLArgs = {
+  where: {
+    swapEnabled: {
+      eq: true,
+    },
+    totalShares: {
+      gt: 0.000000000001,
+    },
+    id: {
+      in: [
+        '0xa13a9247ea42d743238089903570127dda72fe4400000000000000000000035d',
+        '0x2F4EB100552EF93840D5ADC30560E5513DFFFACB000000000000000000000334'.toLowerCase(),
+        '0xAE37D54AE477268B9997D4161B96B8200755935C000000000000000000000337'.toLowerCase(),
+        '0x82698AECC9E28E9BB27608BD52CF57F704BD1B83000000000000000000000336'.toLowerCase(),
+      ],
+    },
+  },
+  orderBy: 'totalLiquidity',
+  orderDirection: 'desc',
+  block: { number: 16176441 },
+};
+const subgraphQuery = { args: subgraphArgs, attrs: {} };
+
 const sdk = new BalancerSDK({
   network,
   rpcUrl,
   customSubgraphUrl,
   tenderly: tenderlyConfig,
+  subgraphQuery,
 });
 const { pools } = sdk;
 const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network);
diff --git a/balancer-js/src/modules/joins/joins.module.integration.spec.ts b/balancer-js/src/modules/joins/joins.module.integration.spec.ts
index cfca3b54c..3c20f706e 100644
--- a/balancer-js/src/modules/joins/joins.module.integration.spec.ts
+++ b/balancer-js/src/modules/joins/joins.module.integration.spec.ts
@@ -3,7 +3,13 @@ import dotenv from 'dotenv';
 import { expect } from 'chai';
 import hardhat from 'hardhat';
 
-import { BalancerSDK, BalancerTenderlyConfig, Network } from '@/.';
+import {
+  BalancerSDK,
+  BalancerTenderlyConfig,
+  Network,
+  GraphQLQuery,
+  GraphQLArgs,
+} from '@/.';
 import { BigNumber, parseFixed } from '@ethersproject/bignumber';
 import { Contracts } from '@/modules/contracts/contracts.module';
 import { forkSetup, getBalances } from '@/test/lib/utils';
@@ -54,6 +60,7 @@ const rpcUrl = 'http://127.0.0.1:8000';
 const { TENDERLY_ACCESS_KEY, TENDERLY_USER, TENDERLY_PROJECT } = process.env;
 const { ethers } = hardhat;
 const MAX_GAS_LIMIT = 8e6;
+const addresses = ADDRESSES[network];
 
 // Custom Tenderly configuration parameters - remove in order to use default values
 const tenderlyConfig: BalancerTenderlyConfig = {
@@ -63,11 +70,34 @@ const tenderlyConfig: BalancerTenderlyConfig = {
   blockNumber,
 };
 
+const poolAddresses = Object.values(addresses).map(
+  (address) => address.address
+);
+
+const subgraphArgs: GraphQLArgs = {
+  where: {
+    swapEnabled: {
+      eq: true,
+    },
+    totalShares: {
+      gt: 0.000000000001,
+    },
+    address: {
+      in: poolAddresses,
+    },
+  },
+  orderBy: 'totalLiquidity',
+  orderDirection: 'desc',
+  block: { number: blockNumber },
+};
+const subgraphQuery: GraphQLQuery = { args: subgraphArgs, attrs: {} };
+
 const sdk = new BalancerSDK({
   network,
   rpcUrl,
   customSubgraphUrl,
   tenderly: tenderlyConfig,
+  subgraphQuery,
 });
 const { pools } = sdk;
 const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network);
@@ -77,7 +107,6 @@ const { contracts, contractAddresses } = new Contracts(
   provider
 );
 const relayer = contractAddresses.relayerV4 as string;
-const addresses = ADDRESSES[network];
 
 interface Test {
   signer: JsonRpcSigner;
diff --git a/balancer-js/src/modules/pools/pool-types/concerns/metaStable/spotPrice.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/metaStable/spotPrice.spec.ts
index 3595663bb..54a34146a 100644
--- a/balancer-js/src/modules/pools/pool-types/concerns/metaStable/spotPrice.spec.ts
+++ b/balancer-js/src/modules/pools/pool-types/concerns/metaStable/spotPrice.spec.ts
@@ -22,7 +22,7 @@ describe('metaStable pool spot price', () => {
         ADDRESSES[network].wSTETH.address,
         pool
       );
-      expect(spotPrice).to.eq('1.070497605163895290828158545877174735');
+      expect(spotPrice).to.eq('1.070296441642066094033346842555222521');
     });
   });
 });
diff --git a/balancer-js/src/modules/pools/pool-types/concerns/stable/spotPrice.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/stable/spotPrice.spec.ts
index aaaa65e16..fcccdad0c 100644
--- a/balancer-js/src/modules/pools/pool-types/concerns/stable/spotPrice.spec.ts
+++ b/balancer-js/src/modules/pools/pool-types/concerns/stable/spotPrice.spec.ts
@@ -22,7 +22,7 @@ describe('stable pool spot price', () => {
         ADDRESSES[network].USDC.address,
         pool
       );
-      expect(spotPrice).to.eq('1.000051911328148725');
+      expect(spotPrice).to.eq('1.000067171032243145');
     });
   });
 });
diff --git a/balancer-js/src/modules/pools/pool-types/concerns/stablePhantom/spotPrice.spec.ts b/balancer-js/src/modules/pools/pool-types/concerns/stablePhantom/spotPrice.spec.ts
index 6b7638ee7..545c5546d 100644
--- a/balancer-js/src/modules/pools/pool-types/concerns/stablePhantom/spotPrice.spec.ts
+++ b/balancer-js/src/modules/pools/pool-types/concerns/stablePhantom/spotPrice.spec.ts
@@ -22,7 +22,7 @@ describe('phantomStable pool spot price', () => {
         ADDRESSES[network].bbausdc.address,
         pool
       );
-      expect(spotPrice).to.eq('0.997873677414938406552928560423740375');
+      expect(spotPrice).to.eq('0.997841372993511964077587098034000689');
     });
   });
 });
diff --git a/balancer-js/src/modules/sdk.module.ts b/balancer-js/src/modules/sdk.module.ts
index 7b01f0a12..74c41b806 100644
--- a/balancer-js/src/modules/sdk.module.ts
+++ b/balancer-js/src/modules/sdk.module.ts
@@ -42,7 +42,11 @@ export class BalancerSDK implements BalancerSDKRoot {
     this.networkConfig = getNetworkConfig(config);
     this.provider = sor.provider;
 
-    this.data = new Data(this.networkConfig, sor.provider);
+    this.data = new Data(
+      this.networkConfig,
+      sor.provider,
+      config.subgraphQuery
+    );
     this.swaps = new Swaps(this.config);
     this.relayer = new Relayer(this.swaps);
     this.pricing = new Pricing(config, this.swaps);
diff --git a/balancer-js/src/types.ts b/balancer-js/src/types.ts
index 9b5131ae6..6cd132a68 100644
--- a/balancer-js/src/types.ts
+++ b/balancer-js/src/types.ts
@@ -35,6 +35,7 @@ export interface BalancerSdkConfig {
   rpcUrl: string;
   //overwrite the subgraph url if you don't want to use the balancer labs maintained version
   customSubgraphUrl?: string;
+  subgraphQuery?: GraphQLQuery;
   //optionally overwrite parts of the standard SOR config
   sor?: Partial<BalancerSdkSorConfig>;
   tenderly?: BalancerTenderlyConfig;

From f01052debfd7fb4f690689aa5ef3a4951a71cb84 Mon Sep 17 00:00:00 2001
From: Bruno Eidam Guerios <bruno@balancer.finance>
Date: Wed, 4 Jan 2023 14:24:16 -0300
Subject: [PATCH 08/25] Fix subgraph price repository test not passing

---
 balancer-js/src/modules/data/token-prices/subgraph.spec.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/balancer-js/src/modules/data/token-prices/subgraph.spec.ts b/balancer-js/src/modules/data/token-prices/subgraph.spec.ts
index b80053bb3..462d2980a 100644
--- a/balancer-js/src/modules/data/token-prices/subgraph.spec.ts
+++ b/balancer-js/src/modules/data/token-prices/subgraph.spec.ts
@@ -31,7 +31,7 @@ const mockedResponse = {
 
 const addresses = mockedResponse.data.tokens.map((t) => t.address);
 
-const repository = new SubgraphPriceRepository(1);
+const repository = new SubgraphPriceRepository(url, 1);
 
 describe('subgraph price repository', () => {
   let mock: MockAdapter;

From 71f5c10889820ec5eab2459bd9cb877c2bdeae50 Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Thu, 5 Jan 2023 11:58:46 +0000
Subject: [PATCH 09/25] Reuse existing onchain methods.

---
 .../src/modules/data/pool/onChainData.ts      | 277 ------------------
 .../src/modules/data/pool/subgraphOnChain.ts  |   2 +-
 .../src/modules/sor/pool-data/onChainData.ts  |  18 +-
 3 files changed, 11 insertions(+), 286 deletions(-)
 delete mode 100644 balancer-js/src/modules/data/pool/onChainData.ts

diff --git a/balancer-js/src/modules/data/pool/onChainData.ts b/balancer-js/src/modules/data/pool/onChainData.ts
deleted file mode 100644
index 484515d3c..000000000
--- a/balancer-js/src/modules/data/pool/onChainData.ts
+++ /dev/null
@@ -1,277 +0,0 @@
-import { formatFixed } from '@ethersproject/bignumber';
-import { Provider } from '@ethersproject/providers';
-import { PoolFilter } from '@balancer-labs/sor';
-import { Multicaller } from '@/lib/utils/multiCaller';
-import { isSameAddress } from '@/lib/utils';
-import { Vault__factory } from '@balancer-labs/typechain';
-import { Pool } from '@/types';
-
-// TODO: decide whether we want to trim these ABIs down to the relevant functions
-import aTokenRateProvider from '@/lib/abi/StaticATokenRateProvider.json';
-import weightedPoolAbi from '@/lib/abi/WeightedPool.json';
-import stablePoolAbi from '@/lib/abi/StablePool.json';
-import elementPoolAbi from '@/lib/abi/ConvergentCurvePool.json';
-import linearPoolAbi from '@/lib/abi/LinearPool.json';
-import composableStableAbi from '@/lib/abi/ComposableStable.json';
-
-export async function getOnChainBalances(
-  subgraphPoolsOriginal: Pool[],
-  multiAddress: string,
-  vaultAddress: string,
-  provider: Provider
-): Promise<Pool[]> {
-  if (subgraphPoolsOriginal.length === 0) return subgraphPoolsOriginal;
-
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  const abis: any = Object.values(
-    // Remove duplicate entries using their names
-    Object.fromEntries(
-      [
-        ...Vault__factory.abi,
-        ...aTokenRateProvider,
-        ...weightedPoolAbi,
-        ...stablePoolAbi,
-        ...elementPoolAbi,
-        ...linearPoolAbi,
-        ...composableStableAbi,
-      ].map((row) => [row.name, row])
-    )
-  );
-
-  const multiPool = new Multicaller(multiAddress, provider, abis);
-
-  const supportedPoolTypes: string[] = Object.values(PoolFilter);
-  const subgraphPools: Pool[] = [];
-  subgraphPoolsOriginal.forEach((pool) => {
-    if (!supportedPoolTypes.includes(pool.poolType)) {
-      console.error(`Unknown pool type: ${pool.poolType} ${pool.id}`);
-      return;
-    }
-
-    subgraphPools.push(pool);
-
-    multiPool.call(`${pool.id}.poolTokens`, vaultAddress, 'getPoolTokens', [
-      pool.id,
-    ]);
-    multiPool.call(`${pool.id}.totalSupply`, pool.address, 'totalSupply');
-
-    // Pools with pre minted BPT
-    if (pool.poolType.includes('Linear') || pool.poolType === 'StablePhantom') {
-      multiPool.call(
-        `${pool.id}.virtualSupply`,
-        pool.address,
-        'getVirtualSupply'
-      );
-    }
-
-    /**
-     * Returns the effective BPT supply.
-     * In other pools, this would be the same as `totalSupply`, but there are two key differences here:
-     *  - this pool pre-mints BPT and holds it in the Vault as a token, and as such we need to subtract the Vault's
-     *    balance to get the total "circulating supply". This is called the 'virtualSupply'.
-     *  - the Pool owes debt to the Protocol in the form of unminted BPT, which will be minted immediately before the
-     *    next join or exit. We need to take these into account since, even if they don't yet exist, they will
-     *    effectively be included in any Pool operation that involves BPT.
-     * In the vast majority of cases, this function should be used instead of `totalSupply()`.
-     */
-    if (pool.poolType === 'ComposableStable')
-      multiPool.call(
-        `${pool.id}.actualSupply`,
-        pool.address,
-        'getActualSupply'
-      );
-
-    // TO DO - Make this part of class to make more flexible?
-    if (
-      pool.poolType === 'Weighted' ||
-      pool.poolType === 'LiquidityBootstrapping' ||
-      pool.poolType === 'Investment'
-    ) {
-      multiPool.call(
-        `${pool.id}.weights`,
-        pool.address,
-        'getNormalizedWeights'
-      );
-      multiPool.call(
-        `${pool.id}.swapFee`,
-        pool.address,
-        'getSwapFeePercentage'
-      );
-    } else if (
-      pool.poolType === 'Stable' ||
-      pool.poolType === 'MetaStable' ||
-      pool.poolType === 'StablePhantom' ||
-      pool.poolType === 'ComposableStable'
-    ) {
-      // MetaStable & StablePhantom is the same as Stable for multicall purposes
-      multiPool.call(
-        `${pool.id}.amp`,
-        pool.address,
-        'getAmplificationParameter'
-      );
-      multiPool.call(
-        `${pool.id}.swapFee`,
-        pool.address,
-        'getSwapFeePercentage'
-      );
-    } else if (pool.poolType === 'Element') {
-      multiPool.call(`${pool.id}.swapFee`, pool.address, 'percentFee');
-    } else if (pool.poolType.toString().includes('Linear')) {
-      multiPool.call(
-        `${pool.id}.swapFee`,
-        pool.address,
-        'getSwapFeePercentage'
-      );
-
-      multiPool.call(`${pool.id}.targets`, pool.address, 'getTargets');
-      multiPool.call(`${pool.id}.rate`, pool.address, 'getWrappedTokenRate');
-    } else if (pool.poolType.toString().includes('Gyro')) {
-      multiPool.call(
-        `${pool.id}.swapFee`,
-        pool.address,
-        'getSwapFeePercentage'
-      );
-    }
-  });
-
-  let pools = {} as Record<
-    string,
-    {
-      amp?: string[];
-      swapFee: string;
-      weights?: string[];
-      targets?: string[];
-      poolTokens: {
-        tokens: string[];
-        balances: string[];
-      };
-      totalSupply: string;
-      virtualSupply?: string;
-      rate?: string;
-      actualSupply?: string;
-    }
-  >;
-
-  try {
-    pools = (await multiPool.execute()) as Record<
-      string,
-      {
-        amp?: string[];
-        swapFee: string;
-        weights?: string[];
-        poolTokens: {
-          tokens: string[];
-          balances: string[];
-        };
-        totalSupply: string;
-        virtualSupply?: string;
-        rate?: string;
-        actualSupply?: string;
-      }
-    >;
-  } catch (err) {
-    throw `Issue with multicall execution.`;
-  }
-
-  const onChainPools: Pool[] = [];
-
-  Object.entries(pools).forEach(([poolId, onchainData], index) => {
-    try {
-      const {
-        poolTokens,
-        swapFee,
-        weights,
-        totalSupply,
-        virtualSupply,
-        actualSupply,
-      } = onchainData;
-
-      if (
-        subgraphPools[index].poolType === 'Stable' ||
-        subgraphPools[index].poolType === 'MetaStable' ||
-        subgraphPools[index].poolType === 'StablePhantom' ||
-        subgraphPools[index].poolType === 'ComposableStable'
-      ) {
-        if (!onchainData.amp) {
-          console.error(`Stable Pool Missing Amp: ${poolId}`);
-          return;
-        } else {
-          // Need to scale amp by precision to match expected Subgraph scale
-          // amp is stored with 3 decimals of precision
-          subgraphPools[index].amp = formatFixed(onchainData.amp[0], 3);
-        }
-      }
-
-      if (subgraphPools[index].poolType.includes('Linear')) {
-        if (!onchainData.targets) {
-          console.error(`Linear Pool Missing Targets: ${poolId}`);
-          return;
-        } else {
-          subgraphPools[index].lowerTarget = formatFixed(
-            onchainData.targets[0],
-            18
-          );
-          subgraphPools[index].upperTarget = formatFixed(
-            onchainData.targets[1],
-            18
-          );
-        }
-
-        const wrappedIndex = subgraphPools[index].wrappedIndex;
-        if (wrappedIndex === undefined || onchainData.rate === undefined) {
-          console.error(
-            `Linear Pool Missing WrappedIndex or PriceRate: ${poolId}`
-          );
-          return;
-        }
-        // Update priceRate of wrappedToken
-        subgraphPools[index].tokens[wrappedIndex].priceRate = formatFixed(
-          onchainData.rate,
-          18
-        );
-      }
-
-      subgraphPools[index].swapFee = formatFixed(swapFee, 18);
-
-      poolTokens.tokens.forEach((token, i) => {
-        const T = subgraphPools[index].tokens.find((t) =>
-          isSameAddress(t.address, token)
-        );
-        if (!T) throw `Pool Missing Expected Token: ${poolId} ${token}`;
-        T.balance = formatFixed(poolTokens.balances[i], T.decimals);
-        if (weights) {
-          // Only expected for WeightedPools
-          T.weight = formatFixed(weights[i], 18);
-        }
-      });
-
-      // Pools with pre minted BPT
-      if (
-        subgraphPools[index].poolType.includes('Linear') ||
-        subgraphPools[index].poolType === 'StablePhantom'
-      ) {
-        if (virtualSupply === undefined) {
-          console.error(
-            `Pool with pre-minted BPT missing Virtual Supply: ${poolId}`
-          );
-          return;
-        }
-        subgraphPools[index].totalShares = formatFixed(virtualSupply, 18);
-      } else if (subgraphPools[index].poolType === 'ComposableStable') {
-        if (actualSupply === undefined) {
-          console.error(`ComposableStable missing Actual Supply: ${poolId}`);
-          return;
-        }
-        subgraphPools[index].totalShares = formatFixed(actualSupply, 18);
-      } else {
-        subgraphPools[index].totalShares = formatFixed(totalSupply, 18);
-      }
-
-      onChainPools.push(subgraphPools[index]);
-    } catch (err) {
-      throw `Issue with pool onchain data: ${err}`;
-    }
-  });
-
-  return onChainPools;
-}
diff --git a/balancer-js/src/modules/data/pool/subgraphOnChain.ts b/balancer-js/src/modules/data/pool/subgraphOnChain.ts
index dea17d097..bce6e0194 100644
--- a/balancer-js/src/modules/data/pool/subgraphOnChain.ts
+++ b/balancer-js/src/modules/data/pool/subgraphOnChain.ts
@@ -24,7 +24,7 @@ import {
 } from '@/types';
 import { Network } from '@/lib/constants/network';
 import { PoolsQueryVariables } from '../../subgraph/subgraph';
-import { getOnChainBalances } from './onChainData';
+import { getOnChainBalances } from '../../../modules/sor/pool-data/onChainData';
 import { SubgraphSubPoolMeta, SubgraphSubPoolToken } from './subgraph';
 
 interface PoolsSubgraphOnChainRepositoryOptions {
diff --git a/balancer-js/src/modules/sor/pool-data/onChainData.ts b/balancer-js/src/modules/sor/pool-data/onChainData.ts
index 7ad54f1f5..6bf623b9e 100644
--- a/balancer-js/src/modules/sor/pool-data/onChainData.ts
+++ b/balancer-js/src/modules/sor/pool-data/onChainData.ts
@@ -4,6 +4,7 @@ import { PoolFilter, SubgraphPoolBase } from '@balancer-labs/sor';
 import { Multicaller } from '@/lib/utils/multiCaller';
 import { isSameAddress } from '@/lib/utils';
 import { Vault__factory } from '@balancer-labs/typechain';
+import { Pool } from '@/types';
 
 // TODO: decide whether we want to trim these ABIs down to the relevant functions
 import aTokenRateProvider from '@/lib/abi/StaticATokenRateProvider.json';
@@ -13,12 +14,12 @@ import elementPoolAbi from '@/lib/abi/ConvergentCurvePool.json';
 import linearPoolAbi from '@/lib/abi/LinearPool.json';
 import composableStableAbi from '@/lib/abi/ComposableStable.json';
 
-export async function getOnChainBalances(
-  subgraphPoolsOriginal: SubgraphPoolBase[],
+export async function getOnChainBalances<Type extends SubgraphPoolBase | Pool>(
+  subgraphPoolsOriginal: Type[],
   multiAddress: string,
   vaultAddress: string,
   provider: Provider
-): Promise<SubgraphPoolBase[]> {
+): Promise<Type[]> {
   if (subgraphPoolsOriginal.length === 0) return subgraphPoolsOriginal;
 
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -40,7 +41,7 @@ export async function getOnChainBalances(
   const multiPool = new Multicaller(multiAddress, provider, abis);
 
   const supportedPoolTypes: string[] = Object.values(PoolFilter);
-  const subgraphPools: SubgraphPoolBase[] = [];
+  const subgraphPools: Type[] = [];
   subgraphPoolsOriginal.forEach((pool) => {
     if (!supportedPoolTypes.includes(pool.poolType)) {
       console.error(`Unknown pool type: ${pool.poolType} ${pool.id}`);
@@ -172,7 +173,7 @@ export async function getOnChainBalances(
     throw `Issue with multicall execution.`;
   }
 
-  const onChainPools: SubgraphPoolBase[] = [];
+  const onChainPools: Type[] = [];
 
   Object.entries(pools).forEach(([poolId, onchainData], index) => {
     try {
@@ -233,9 +234,10 @@ export async function getOnChainBalances(
       subgraphPools[index].swapFee = formatFixed(swapFee, 18);
 
       poolTokens.tokens.forEach((token, i) => {
-        const T = subgraphPools[index].tokens.find((t) =>
-          isSameAddress(t.address, token)
-        );
+        // Looks like there's a TS issue that means find doesn't work on unions: https://stackoverflow.com/questions/58772314/typescript-array-prototype-map-has-error-expression-is-not-callable-when-th
+        // eslint-disable-next-line @typescript-eslint/no-explicit-any
+        const tokens = subgraphPools[index].tokens as any[];
+        const T = tokens.find((t) => isSameAddress(t.address, token));
         if (!T) throw `Pool Missing Expected Token: ${poolId} ${token}`;
         T.balance = formatFixed(poolTokens.balances[i], T.decimals);
         if (weights) {

From c30d5e747ef809b0dc36876db7126b152792a3ac Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Thu, 5 Jan 2023 13:42:23 +0000
Subject: [PATCH 10/25] Onchain SG repo reuses non-onchain functions.

---
 .../src/modules/data/pool/subgraphOnChain.ts  | 223 ++----------------
 1 file changed, 20 insertions(+), 203 deletions(-)

diff --git a/balancer-js/src/modules/data/pool/subgraphOnChain.ts b/balancer-js/src/modules/data/pool/subgraphOnChain.ts
index bce6e0194..78bba7aa9 100644
--- a/balancer-js/src/modules/data/pool/subgraphOnChain.ts
+++ b/balancer-js/src/modules/data/pool/subgraphOnChain.ts
@@ -1,31 +1,10 @@
 import { Findable, Searchable } from '../types';
-import {
-  createSubgraphClient,
-  SubgraphClient,
-  SubgraphPool,
-  Pool_OrderBy,
-  OrderDirection,
-  SubgraphPoolTokenFragment,
-} from '@/modules/subgraph/subgraph';
-import {
-  GraphQLArgsBuilder,
-  SubgraphArgsFormatter,
-} from '@/lib/graphql/args-builder';
-import { GraphQLArgs } from '@/lib/graphql/types';
 import { Provider } from '@ethersproject/providers';
 import { PoolAttribute, PoolsRepositoryFetchOptions } from './types';
-import {
-  GraphQLQuery,
-  Pool,
-  PoolType,
-  PoolToken,
-  SubPool,
-  SubPoolMeta,
-} from '@/types';
+import { GraphQLQuery, Pool } from '@/types';
 import { Network } from '@/lib/constants/network';
-import { PoolsQueryVariables } from '../../subgraph/subgraph';
 import { getOnChainBalances } from '../../../modules/sor/pool-data/onChainData';
-import { SubgraphSubPoolMeta, SubgraphSubPoolToken } from './subgraph';
+import { PoolsSubgraphRepository } from './subgraph';
 
 interface PoolsSubgraphOnChainRepositoryOptions {
   url: string;
@@ -38,25 +17,20 @@ interface PoolsSubgraphOnChainRepositoryOptions {
 }
 
 /**
- * Access pools using generated subgraph client.
- *
- * Balancer's subgraph URL: https://thegraph.com/hosted-service/subgraph/balancer-labs/balancer-v2
+ * Access pools using generated subgraph client and multicall.
  */
 export class PoolsSubgraphOnChainRepository
   implements Findable<Pool, PoolAttribute>, Searchable<Pool>
 {
-  private client: SubgraphClient;
-  private chainId: Network;
+  private poolsSubgraph: PoolsSubgraphRepository;
   private provider: Provider;
   private pools?: Promise<Pool[]>;
   private multicall: string;
   private vault: string;
   public skip = 0;
-  private blockHeight: undefined | (() => Promise<number | undefined>);
-  private query: GraphQLQuery;
 
   /**
-   * Repository with optional lazy loaded blockHeight
+   * Repository using multicall to get onchain data.
    *
    * @param url subgraph URL
    * @param chainId current network, needed for L2s logic
@@ -65,33 +39,15 @@ export class PoolsSubgraphOnChainRepository
    * @param valt vault address
    */
   constructor(options: PoolsSubgraphOnChainRepositoryOptions) {
-    this.client = createSubgraphClient(options.url);
-    this.blockHeight = options.blockHeight;
-    this.chainId = options.chainId;
+    this.poolsSubgraph = new PoolsSubgraphRepository({
+      url: options.url,
+      chainId: options.chainId,
+      blockHeight: options.blockHeight,
+      query: options.query,
+    });
     this.provider = options.provider;
     this.multicall = options.multicall;
     this.vault = options.vault;
-
-    const defaultArgs: GraphQLArgs = {
-      orderBy: Pool_OrderBy.TotalLiquidity,
-      orderDirection: OrderDirection.Desc,
-      where: {
-        swapEnabled: {
-          eq: true,
-        },
-        totalShares: {
-          gt: 0.000000000001,
-        },
-      },
-    };
-
-    const args = options.query?.args || defaultArgs;
-    const attrs = options.query?.attrs || {};
-
-    this.query = {
-      args,
-      attrs,
-    };
   }
 
   /**
@@ -102,12 +58,7 @@ export class PoolsSubgraphOnChainRepository
    */
   private async fetchDefault(): Promise<Pool[]> {
     console.time('fetching pools');
-    const { pool0, pool1000, pool2000 } = await this.client.AllPools(
-      await this.getDefaultFilter(this.query.args)
-    );
-    const pools = [...pool0, ...pool1000, ...pool2000].map(
-      this.mapType.bind(this)
-    );
+    const pools = await this.poolsSubgraph.fetch();
     console.timeEnd('fetching pools');
     console.log(pools.length, 'Example filter should limit the pools length');
     console.log('Fetching onchain!');
@@ -122,24 +73,14 @@ export class PoolsSubgraphOnChainRepository
   }
 
   async fetch(options?: PoolsRepositoryFetchOptions): Promise<Pool[]> {
-    if (options?.skip) {
-      this.query.args.skip = options.skip;
-    }
-    if (!this.query.args.block) {
-      this.query.args.block = await this.block();
-    }
-
-    this.query.args.first = options?.first || 1000;
-
-    const formattedQuery = new GraphQLArgsBuilder(this.query.args).format(
-      new SubgraphArgsFormatter()
-    ) as PoolsQueryVariables;
-
-    const { pools } = await this.client.Pools(formattedQuery);
-
-    this.skip = (options?.skip || 0) + pools.length;
-
-    return pools.map(this.mapType.bind(this));
+    const pools = await this.poolsSubgraph.fetch(options);
+    const onchainPools = await getOnChainBalances(
+      pools,
+      this.multicall,
+      this.vault,
+      this.provider
+    );
+    return onchainPools;
   }
 
   async find(id: string): Promise<Pool | undefined> {
@@ -152,25 +93,6 @@ export class PoolsSubgraphOnChainRepository
     }
 
     return (await this.pools).find((pool) => pool[param] == value);
-
-    // TODO: @Nma - Fetching pools outside of default query is causing a lot of requests
-    // on a frontend, because results aren't cached anywhere.
-    // For fetching pools directly from subgraph with custom queries please use the client not this repository.
-    // Code below kept for reference, to be removed later.
-    //
-    // if (this.pools) {
-    //   return (await this.pools).find((p) => p[param] === value);
-    // }
-    // const { pools } = await this.client.Pools({
-    //   where: {
-    //     [param]: value,
-    //     swapEnabled: true,
-    //     totalShares_gt: '0.000000000001',
-    //   },
-    //   block: await this.block(),
-    // });
-    // const poolsTab: Pool[] = pools.map(this.mapType.bind(this));
-    // return poolsTab.length > 0 ? poolsTab[0] : undefined;
   }
 
   async all(): Promise<Pool[]> {
@@ -180,20 +102,6 @@ export class PoolsSubgraphOnChainRepository
     return this.pools;
   }
 
-  async block(): Promise<{ number: number | undefined } | undefined> {
-    return this.blockHeight ? { number: await this.blockHeight() } : undefined;
-  }
-
-  async getDefaultFilter(args: GraphQLArgs): Promise<PoolsQueryVariables> {
-    const formattedQuery = new GraphQLArgsBuilder(args).format(
-      new SubgraphArgsFormatter()
-    ) as PoolsQueryVariables;
-    if (!formattedQuery.block) {
-      formattedQuery.block = await this.block();
-    }
-    return formattedQuery;
-  }
-
   async where(filter: (pool: Pool) => boolean): Promise<Pool[]> {
     if (!this.pools) {
       this.pools = this.fetchDefault();
@@ -201,95 +109,4 @@ export class PoolsSubgraphOnChainRepository
 
     return (await this.pools).filter(filter);
   }
-
-  private mapType(subgraphPool: SubgraphPool): Pool {
-    return {
-      id: subgraphPool.id,
-      name: subgraphPool.name || '',
-      address: subgraphPool.address,
-      chainId: this.chainId,
-      poolType: subgraphPool.poolType as PoolType,
-      poolTypeVersion: subgraphPool.poolTypeVersion || 1,
-      swapFee: subgraphPool.swapFee,
-      swapEnabled: subgraphPool.swapEnabled,
-      protocolYieldFeeCache: subgraphPool.protocolYieldFeeCache || '0',
-      amp: subgraphPool.amp ?? undefined,
-      owner: subgraphPool.owner ?? undefined,
-      factory: subgraphPool.factory ?? undefined,
-      symbol: subgraphPool.symbol ?? undefined,
-      tokens: (subgraphPool.tokens || []).map(this.mapToken.bind(this)),
-      tokensList: subgraphPool.tokensList,
-      tokenAddresses: (subgraphPool.tokens || []).map((t) => t.address),
-      totalLiquidity: subgraphPool.totalLiquidity,
-      totalShares: subgraphPool.totalShares,
-      totalSwapFee: subgraphPool.totalSwapFee,
-      totalSwapVolume: subgraphPool.totalSwapVolume,
-      priceRateProviders: subgraphPool.priceRateProviders ?? undefined,
-      // onchain: subgraphPool.onchain,
-      createTime: subgraphPool.createTime,
-      mainIndex: subgraphPool.mainIndex ?? undefined,
-      wrappedIndex: subgraphPool.wrappedIndex ?? undefined,
-      // mainTokens: subgraphPool.mainTokens,
-      // wrappedTokens: subgraphPool.wrappedTokens,
-      // unwrappedTokens: subgraphPool.unwrappedTokens,
-      // isNew: subgraphPool.isNew,
-      // volumeSnapshot: subgraphPool.volumeSnapshot,
-      // feesSnapshot: subgraphPool.???, // Approximated last 24h fees
-      // boost: subgraphPool.boost,
-      totalWeight: subgraphPool.totalWeight || '1',
-      lowerTarget: subgraphPool.lowerTarget ?? '0',
-      upperTarget: subgraphPool.upperTarget ?? '0',
-    };
-  }
-
-  private mapToken(subgraphToken: SubgraphPoolTokenFragment): PoolToken {
-    const subPoolInfo = this.mapSubPools(
-      // need to typecast as the fragment is 3 layers deep while the type is infinite levels deep
-      subgraphToken.token as SubgraphSubPoolMeta
-    );
-    return {
-      ...subgraphToken,
-      isExemptFromYieldProtocolFee:
-        subgraphToken.isExemptFromYieldProtocolFee || false,
-      token: subPoolInfo,
-    };
-  }
-
-  private mapSubPools(metadata: SubgraphSubPoolMeta): SubPoolMeta {
-    let subPool: SubPool | null = null;
-    if (metadata.pool) {
-      subPool = {
-        id: metadata.pool.id,
-        address: metadata.pool.address,
-        totalShares: metadata.pool.totalShares,
-        poolType: metadata.pool.poolType as PoolType,
-        mainIndex: metadata.pool.mainIndex || 0,
-      };
-
-      if (metadata?.pool.tokens) {
-        subPool.tokens = metadata.pool.tokens.map(
-          this.mapSubPoolToken.bind(this)
-        );
-      }
-    }
-
-    return {
-      pool: subPool,
-      latestUSDPrice: metadata.latestUSDPrice || undefined,
-    };
-  }
-
-  private mapSubPoolToken(token: SubgraphSubPoolToken) {
-    return {
-      address: token.address,
-      decimals: token.decimals,
-      symbol: token.symbol,
-      balance: token.balance,
-      priceRate: token.priceRate,
-      weight: token.weight,
-      isExemptFromYieldProtocolFee:
-        token.isExemptFromYieldProtocolFee || undefined,
-      token: token.token ? this.mapSubPools(token.token) : undefined,
-    };
-  }
 }

From aeb7d691becaffad0d6df271604190e27f99e61d Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Thu, 5 Jan 2023 14:34:27 +0000
Subject: [PATCH 11/25] Remove SP default flag.

---
 .../src/modules/data/pool/subgraphOnChain.ts   |  7 ++++---
 balancer-js/src/modules/graph/graph.ts         |  3 +--
 balancer-js/src/modules/joins/joins.module.ts  |  6 ------
 balancer-js/src/modules/pools/index.ts         |  9 ++-------
 .../concerns/linear/spotPrice.concern.ts       | 18 +++++-------------
 .../modules/pools/pool-types/concerns/types.ts |  7 +------
 balancer-js/src/types.ts                       |  6 +-----
 7 files changed, 14 insertions(+), 42 deletions(-)

diff --git a/balancer-js/src/modules/data/pool/subgraphOnChain.ts b/balancer-js/src/modules/data/pool/subgraphOnChain.ts
index 78bba7aa9..a331c79a3 100644
--- a/balancer-js/src/modules/data/pool/subgraphOnChain.ts
+++ b/balancer-js/src/modules/data/pool/subgraphOnChain.ts
@@ -57,17 +57,18 @@ export class PoolsSubgraphOnChainRepository
    * @returns Promise resolving to pools list
    */
   private async fetchDefault(): Promise<Pool[]> {
-    console.time('fetching pools');
+    console.time('fetching pools SG');
     const pools = await this.poolsSubgraph.fetch();
-    console.timeEnd('fetching pools');
+    console.timeEnd('fetching pools SG');
     console.log(pools.length, 'Example filter should limit the pools length');
-    console.log('Fetching onchain!');
+    console.time('fetching pools onchain');
     const onchainPools = await getOnChainBalances(
       pools,
       this.multicall,
       this.vault,
       this.provider
     );
+    console.timeEnd('fetching pools onchain');
 
     return onchainPools;
   }
diff --git a/balancer-js/src/modules/graph/graph.ts b/balancer-js/src/modules/graph/graph.ts
index b19a8c629..c6a33aded 100644
--- a/balancer-js/src/modules/graph/graph.ts
+++ b/balancer-js/src/modules/graph/graph.ts
@@ -149,8 +149,7 @@ export class PoolGraph {
       const sp = spotPriceCalculator.calcPoolSpotPrice(
         token.address,
         pool.address,
-        pool,
-        false
+        pool
       );
       spotPrices[token.address] = sp;
     });
diff --git a/balancer-js/src/modules/joins/joins.module.ts b/balancer-js/src/modules/joins/joins.module.ts
index 05d7bd9b2..2b1abc58c 100644
--- a/balancer-js/src/modules/joins/joins.module.ts
+++ b/balancer-js/src/modules/joins/joins.module.ts
@@ -409,10 +409,6 @@ export class Join {
         parentNode.joinAction === 'joinPool'
       ) {
         const sp = parentNode.spotPrices[childAddress.toLowerCase()];
-        console.log(
-          `Spot price ${childAddress.toLowerCase()}: `,
-          sp.toString()
-        );
         spProduct = spProduct * parseFloat(sp);
         childAddress = parentNode.address;
       }
@@ -425,8 +421,6 @@ export class Join {
       inputAmountScaled,
       spPriceScaled.toBigInt()
     );
-    console.log('sp product: ', spProduct.toString());
-    console.log('zeroPriceImpact amount for path: ', bptOut.toString(), '\n');
     return bptOut;
   };
 
diff --git a/balancer-js/src/modules/pools/index.ts b/balancer-js/src/modules/pools/index.ts
index de5f55498..c84ceadad 100644
--- a/balancer-js/src/modules/pools/index.ts
+++ b/balancer-js/src/modules/pools/index.ts
@@ -266,16 +266,11 @@ export class Pools implements Findable<PoolWithMethods> {
         // either we refetch or it needs a type transformation from SDK internal to SOR (subgraph)
         // spotPrice: async (tokenIn: string, tokenOut: string) =>
         //   methods.spotPriceCalculator.calcPoolSpotPrice(tokenIn, tokenOut, data),
-        calcSpotPrice: (
-          tokenIn: string,
-          tokenOut: string,
-          isDefault?: boolean
-        ) =>
+        calcSpotPrice: (tokenIn: string, tokenOut: string) =>
           concerns.spotPriceCalculator.calcPoolSpotPrice(
             tokenIn,
             tokenOut,
-            pool,
-            isDefault
+            pool
           ),
       };
     } catch (error) {
diff --git a/balancer-js/src/modules/pools/pool-types/concerns/linear/spotPrice.concern.ts b/balancer-js/src/modules/pools/pool-types/concerns/linear/spotPrice.concern.ts
index 8ff606a9e..0848123db 100644
--- a/balancer-js/src/modules/pools/pool-types/concerns/linear/spotPrice.concern.ts
+++ b/balancer-js/src/modules/pools/pool-types/concerns/linear/spotPrice.concern.ts
@@ -3,19 +3,11 @@ import { SubgraphPoolBase, LinearPool, ZERO } from '@balancer-labs/sor';
 import { Pool } from '@/types';
 
 export class LinearPoolSpotPrice implements SpotPriceConcern {
-  calcPoolSpotPrice(
-    tokenIn: string,
-    tokenOut: string,
-    pool: Pool,
-    isDefault = false
-  ): string {
+  calcPoolSpotPrice(tokenIn: string, tokenOut: string, pool: Pool): string {
     const linearPool = LinearPool.fromPool(pool as SubgraphPoolBase);
-    if (isDefault) return '1';
-    else {
-      const poolPairData = linearPool.parsePoolPairData(tokenIn, tokenOut);
-      return linearPool
-        ._spotPriceAfterSwapExactTokenInForTokenOut(poolPairData, ZERO)
-        .toString();
-    }
+    const poolPairData = linearPool.parsePoolPairData(tokenIn, tokenOut);
+    return linearPool
+      ._spotPriceAfterSwapExactTokenInForTokenOut(poolPairData, ZERO)
+      .toString();
   }
 }
diff --git a/balancer-js/src/modules/pools/pool-types/concerns/types.ts b/balancer-js/src/modules/pools/pool-types/concerns/types.ts
index abcc52bab..016ce5530 100644
--- a/balancer-js/src/modules/pools/pool-types/concerns/types.ts
+++ b/balancer-js/src/modules/pools/pool-types/concerns/types.ts
@@ -7,12 +7,7 @@ export interface LiquidityConcern {
 }
 
 export interface SpotPriceConcern {
-  calcPoolSpotPrice: (
-    tokenIn: string,
-    tokenOut: string,
-    pool: Pool,
-    isDefault?: boolean
-  ) => string;
+  calcPoolSpotPrice: (tokenIn: string, tokenOut: string, pool: Pool) => string;
 }
 
 export interface PriceImpactConcern {
diff --git a/balancer-js/src/types.ts b/balancer-js/src/types.ts
index 6cd132a68..3902cbcac 100644
--- a/balancer-js/src/types.ts
+++ b/balancer-js/src/types.ts
@@ -337,11 +337,7 @@ export interface PoolWithMethods extends Pool, Queries.ParamsBuilder {
     amountsOut: string[],
     slippage: string
   ) => ExitPoolAttributes;
-  calcSpotPrice: (
-    tokenIn: string,
-    tokenOut: string,
-    isDefault?: boolean
-  ) => string;
+  calcSpotPrice: (tokenIn: string, tokenOut: string) => string;
 }
 
 export interface GraphQLQuery {

From c46f4b7c16212ef83d193690911808e860ac34a7 Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Thu, 5 Jan 2023 15:21:29 +0000
Subject: [PATCH 12/25] Handle PI<0. Remove debug logs and tests.

---
 balancer-js/package.json                      |   2 +-
 .../src/modules/data/pool/subgraphOnChain.ts  |   1 -
 .../joins/debug.module.integration.spec.ts    | 266 ------------------
 balancer-js/src/modules/joins/joins.module.ts |   2 -
 .../src/modules/pricing/priceImpact.ts        |   6 +-
 balancer-js/yarn.lock                         |   6 +-
 6 files changed, 8 insertions(+), 275 deletions(-)
 delete mode 100644 balancer-js/src/modules/joins/debug.module.integration.spec.ts

diff --git a/balancer-js/package.json b/balancer-js/package.json
index 81ca855b7..0fc284998 100644
--- a/balancer-js/package.json
+++ b/balancer-js/package.json
@@ -89,7 +89,7 @@
     "typescript": "^4.0.2"
   },
   "dependencies": {
-    "@balancer-labs/sor": "/Users/jg/Documents/balancer-sor/balancer-labs-sor-v4.0.1-beta.22.tgz",
+    "@balancer-labs/sor": "/Users/jg/Documents/balancer-sor/balancer-labs-sor-v4.0.1-beta.16010.tgz",
     "@balancer-labs/typechain": "^1.0.0",
     "axios": "^0.24.0",
     "graphql": "^15.6.1",
diff --git a/balancer-js/src/modules/data/pool/subgraphOnChain.ts b/balancer-js/src/modules/data/pool/subgraphOnChain.ts
index a331c79a3..be7037313 100644
--- a/balancer-js/src/modules/data/pool/subgraphOnChain.ts
+++ b/balancer-js/src/modules/data/pool/subgraphOnChain.ts
@@ -60,7 +60,6 @@ export class PoolsSubgraphOnChainRepository
     console.time('fetching pools SG');
     const pools = await this.poolsSubgraph.fetch();
     console.timeEnd('fetching pools SG');
-    console.log(pools.length, 'Example filter should limit the pools length');
     console.time('fetching pools onchain');
     const onchainPools = await getOnChainBalances(
       pools,
diff --git a/balancer-js/src/modules/joins/debug.module.integration.spec.ts b/balancer-js/src/modules/joins/debug.module.integration.spec.ts
deleted file mode 100644
index c2a43a242..000000000
--- a/balancer-js/src/modules/joins/debug.module.integration.spec.ts
+++ /dev/null
@@ -1,266 +0,0 @@
-// yarn test:only ./src/modules/joins/debug.module.integration.spec.ts
-import dotenv from 'dotenv';
-import { expect } from 'chai';
-import hardhat from 'hardhat';
-
-import { BalancerSDK, BalancerTenderlyConfig, Network, GraphQLArgs } from '@/.';
-import { BigNumber, formatFixed, parseFixed } from '@ethersproject/bignumber';
-import { Contracts } from '@/modules/contracts/contracts.module';
-import { forkSetup, getBalances } from '@/test/lib/utils';
-import { ADDRESSES } from '@/test/lib/constants';
-import { Relayer } from '@/modules/relayer/relayer.module';
-import { JsonRpcSigner } from '@ethersproject/providers';
-import { SolidityMaths } from '@/lib/utils/solidityMaths';
-
-dotenv.config();
-
-const TEST_BOOSTED = true;
-
-/*
- * Testing on MAINNET
- * - Update hardhat.config.js with chainId = 1
- * - Update ALCHEMY_URL on .env with a mainnet api key
- * - Run node on terminal: yarn run node
- * - Uncomment section below:
- */
-const network = Network.MAINNET;
-const blockNumber = 16176441;
-const customSubgraphUrl =
-  'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-v2';
-const { ALCHEMY_URL: jsonRpcUrl } = process.env;
-const rpcUrl = 'http://127.0.0.1:8545';
-
-const { TENDERLY_ACCESS_KEY, TENDERLY_USER, TENDERLY_PROJECT } = process.env;
-const { ethers } = hardhat;
-const MAX_GAS_LIMIT = 8e6;
-
-const tenderlyConfig: BalancerTenderlyConfig = {
-  accessKey: TENDERLY_ACCESS_KEY as string,
-  user: TENDERLY_USER as string,
-  project: TENDERLY_PROJECT as string,
-  blockNumber,
-};
-
-const subgraphArgs: GraphQLArgs = {
-  where: {
-    swapEnabled: {
-      eq: true,
-    },
-    totalShares: {
-      gt: 0.000000000001,
-    },
-    id: {
-      in: [
-        '0xa13a9247ea42d743238089903570127dda72fe4400000000000000000000035d',
-        '0x2F4EB100552EF93840D5ADC30560E5513DFFFACB000000000000000000000334'.toLowerCase(),
-        '0xAE37D54AE477268B9997D4161B96B8200755935C000000000000000000000337'.toLowerCase(),
-        '0x82698AECC9E28E9BB27608BD52CF57F704BD1B83000000000000000000000336'.toLowerCase(),
-      ],
-    },
-  },
-  orderBy: 'totalLiquidity',
-  orderDirection: 'desc',
-  block: { number: 16176441 },
-};
-const subgraphQuery = { args: subgraphArgs, attrs: {} };
-
-const sdk = new BalancerSDK({
-  network,
-  rpcUrl,
-  customSubgraphUrl,
-  tenderly: tenderlyConfig,
-  subgraphQuery,
-});
-const { pools } = sdk;
-const provider = new ethers.providers.JsonRpcProvider(rpcUrl, network);
-const signer = provider.getSigner();
-const { contracts, contractAddresses } = new Contracts(
-  network as number,
-  provider
-);
-const relayer = contractAddresses.relayerV4 as string;
-const addresses = ADDRESSES[network];
-
-interface Test {
-  signer: JsonRpcSigner;
-  description: string;
-  pool: {
-    id: string;
-    address: string;
-  };
-  tokensIn: string[];
-  amountsIn: string[];
-  authorisation: string | undefined;
-  wrapMainTokens: boolean;
-}
-
-const runTests = async (tests: Test[]) => {
-  for (let i = 0; i < tests.length; i++) {
-    const test = tests[i];
-    it(test.description, async () => {
-      const userAddress = await test.signer.getAddress();
-      const authorisation = await Relayer.signRelayerApproval(
-        relayer,
-        userAddress,
-        signer,
-        contracts.vault
-      );
-      await testFlow(
-        userAddress,
-        test.pool,
-        test.tokensIn,
-        test.amountsIn,
-        test.wrapMainTokens,
-        authorisation
-      );
-    }).timeout(120000);
-  }
-};
-
-const testFlow = async (
-  userAddress: string,
-  pool: { id: string; address: string },
-  tokensIn: string[],
-  amountsIn: string[],
-  wrapMainTokens: boolean,
-  authorisation: string | undefined
-) => {
-  const [bptBalanceBefore, ...tokensInBalanceBefore] = await getBalances(
-    [pool.address, ...tokensIn],
-    signer,
-    userAddress
-  );
-
-  const gasLimit = MAX_GAS_LIMIT;
-  const slippage = '10'; // 10 bps = 0.1%
-
-  const query = await pools.generalisedJoin(
-    pool.id,
-    tokensIn,
-    amountsIn,
-    userAddress,
-    wrapMainTokens,
-    slippage,
-    authorisation
-  );
-
-  console.log(query.priceImpact, 'priceImpact Raw');
-  const piPercent = SolidityMaths.mulDownFixed(
-    BigInt(query.priceImpact),
-    BigInt('100000000000000000000')
-  );
-  console.log(formatFixed(piPercent, 18), 'priceImpact %');
-
-  const response = await signer.sendTransaction({
-    to: query.to,
-    data: query.callData,
-    gasLimit,
-  });
-
-  const receipt = await response.wait();
-  console.log('Gas used', receipt.gasUsed.toString());
-
-  const [bptBalanceAfter, ...tokensInBalanceAfter] = await getBalances(
-    [pool.address, ...tokensIn],
-    signer,
-    userAddress
-  );
-  expect(receipt.status).to.eql(1);
-  expect(BigNumber.from(query.minOut).gte('0')).to.be.true;
-  expect(BigNumber.from(query.expectedOut).gt(query.minOut)).to.be.true;
-  tokensInBalanceAfter.forEach((balanceAfter, i) => {
-    expect(balanceAfter.toString()).to.eq(
-      tokensInBalanceBefore[i].sub(amountsIn[i]).toString()
-    );
-  });
-  expect(bptBalanceBefore.eq(0)).to.be.true;
-  expect(bptBalanceAfter.gte(query.minOut)).to.be.true;
-  console.log(bptBalanceAfter.toString(), 'bpt after');
-  console.log(query.minOut, 'minOut');
-  console.log(query.expectedOut, 'expectedOut');
-};
-
-describe('generalised join execution', async () => {
-  context('bbausd', async () => {
-    if (!TEST_BOOSTED) return true;
-    let authorisation: string | undefined;
-    beforeEach(async () => {
-      const tokens = [
-        addresses.USDC.address,
-        addresses.DAI.address,
-        addresses.USDT.address,
-      ];
-      const slots = [
-        addresses.USDC.slot,
-        addresses.DAI.slot,
-        addresses.USDT.slot,
-      ];
-      const balances = [
-        parseFixed('1000000', 6).toString(),
-        parseFixed('1000000', 18).toString(),
-        parseFixed('1000000', 6).toString(),
-      ];
-      await forkSetup(
-        signer,
-        tokens,
-        slots,
-        balances,
-        jsonRpcUrl as string,
-        blockNumber
-      );
-    });
-
-    await runTests([
-      {
-        signer,
-        description: 'join with leaf tokens',
-        pool: {
-          id: addresses.bbausd2.id,
-          address: addresses.bbausd2.address,
-        },
-        tokensIn: [
-          addresses.USDC.address,
-          addresses.DAI.address,
-          addresses.USDT.address,
-        ],
-        amountsIn: [
-          parseFixed('10', 6).toString(),
-          parseFixed('10', 18).toString(),
-          parseFixed('10', 6).toString(),
-        ],
-        authorisation: authorisation,
-        wrapMainTokens: false,
-      },
-      {
-        signer,
-        description: 'join with leaf tokens',
-        pool: {
-          id: addresses.bbausd2.id,
-          address: addresses.bbausd2.address,
-        },
-        tokensIn: [addresses.USDC.address, addresses.DAI.address],
-        amountsIn: [
-          parseFixed('0.1', 6).toString(),
-          parseFixed('0.001', 18).toString(),
-        ],
-        authorisation: authorisation,
-        wrapMainTokens: false,
-      },
-      {
-        signer,
-        description: 'join with leaf tokens',
-        pool: {
-          id: addresses.bbausd2.id,
-          address: addresses.bbausd2.address,
-        },
-        tokensIn: [addresses.USDC.address, addresses.DAI.address],
-        amountsIn: [
-          parseFixed('900000', 6).toString(),
-          parseFixed('0.001', 18).toString(),
-        ],
-        authorisation: authorisation,
-        wrapMainTokens: false,
-      },
-    ]);
-  });
-});
diff --git a/balancer-js/src/modules/joins/joins.module.ts b/balancer-js/src/modules/joins/joins.module.ts
index 2b1abc58c..7feba4fa0 100644
--- a/balancer-js/src/modules/joins/joins.module.ts
+++ b/balancer-js/src/modules/joins/joins.module.ts
@@ -121,8 +121,6 @@ export class Join {
       true
     ).toString();
 
-    console.log(totalAmountOut, `totalAmountOut`);
-    console.log(totalBptZeroPi.toString(), `totalBptZeroPi`);
     // Create calls with minAmountsOut
     const { callData, deltas } = await this.createCalls(
       joinPaths,
diff --git a/balancer-js/src/modules/pricing/priceImpact.ts b/balancer-js/src/modules/pricing/priceImpact.ts
index d28c125a1..eb55c09ff 100644
--- a/balancer-js/src/modules/pricing/priceImpact.ts
+++ b/balancer-js/src/modules/pricing/priceImpact.ts
@@ -14,12 +14,14 @@ function calcPriceImpactJoin(
   bptZeroPriceImpact: bigint
 ): bigint {
   // 1 - (bptAmount/bptZeroPI)
-  return ONE - SolidityMaths.divDownFixed(bptAmount, bptZeroPriceImpact);
+  const pi = ONE - SolidityMaths.divDownFixed(bptAmount, bptZeroPriceImpact);
+  return pi < 0 ? BigInt(0) : pi;
 }
 function calcPriceImpactExit(
   bptAmount: bigint,
   bptZeroPriceImpact: bigint
 ): bigint {
   // (bptAmount/bptZeroPI) - 1
-  return SolidityMaths.divDownFixed(bptAmount, bptZeroPriceImpact) - ONE;
+  const pi = SolidityMaths.divDownFixed(bptAmount, bptZeroPriceImpact) - ONE;
+  return pi < 0 ? BigInt(0) : pi;
 }
diff --git a/balancer-js/yarn.lock b/balancer-js/yarn.lock
index 4b34752df..e494689e2 100644
--- a/balancer-js/yarn.lock
+++ b/balancer-js/yarn.lock
@@ -503,9 +503,9 @@
     "@babel/helper-validator-identifier" "^7.19.1"
     to-fast-properties "^2.0.0"
 
-"@balancer-labs/sor@/Users/jg/Documents/balancer-sor/balancer-labs-sor-v4.0.1-beta.22.tgz":
-  version "4.0.1-beta.22"
-  resolved "/Users/jg/Documents/balancer-sor/balancer-labs-sor-v4.0.1-beta.22.tgz#d159ee89feb9cbf01b4807fe402334f8a3b6dc89"
+"@balancer-labs/sor@/Users/jg/Documents/balancer-sor/balancer-labs-sor-v4.0.1-beta.16010.tgz":
+  version "4.0.1-beta.16010"
+  resolved "/Users/jg/Documents/balancer-sor/balancer-labs-sor-v4.0.1-beta.16010.tgz#bbcef0e873f7662f76e9e0aaf3d17ef1202c4795"
   dependencies:
     isomorphic-fetch "^2.2.1"
 

From 79181828f33212e363e95c1412344694f8c0f4e2 Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Thu, 5 Jan 2023 15:22:48 +0000
Subject: [PATCH 13/25] Update SOR to 4.0.1-beta.17.

---
 balancer-js/package.json | 2 +-
 balancer-js/yarn.lock    | 7 ++++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/balancer-js/package.json b/balancer-js/package.json
index 0fc284998..02230b322 100644
--- a/balancer-js/package.json
+++ b/balancer-js/package.json
@@ -89,7 +89,7 @@
     "typescript": "^4.0.2"
   },
   "dependencies": {
-    "@balancer-labs/sor": "/Users/jg/Documents/balancer-sor/balancer-labs-sor-v4.0.1-beta.16010.tgz",
+    "@balancer-labs/sor": "^4.0.1-beta.17",
     "@balancer-labs/typechain": "^1.0.0",
     "axios": "^0.24.0",
     "graphql": "^15.6.1",
diff --git a/balancer-js/yarn.lock b/balancer-js/yarn.lock
index e494689e2..fdfd4f10e 100644
--- a/balancer-js/yarn.lock
+++ b/balancer-js/yarn.lock
@@ -503,9 +503,10 @@
     "@babel/helper-validator-identifier" "^7.19.1"
     to-fast-properties "^2.0.0"
 
-"@balancer-labs/sor@/Users/jg/Documents/balancer-sor/balancer-labs-sor-v4.0.1-beta.16010.tgz":
-  version "4.0.1-beta.16010"
-  resolved "/Users/jg/Documents/balancer-sor/balancer-labs-sor-v4.0.1-beta.16010.tgz#bbcef0e873f7662f76e9e0aaf3d17ef1202c4795"
+"@balancer-labs/sor@^4.0.1-beta.17":
+  version "4.0.1-beta.17"
+  resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.0.1-beta.17.tgz#b78d67ba4107d4ec366015532d34b5c7af3b0169"
+  integrity sha512-KSkPs8Rxn/MPLNeO51uQWffvCJCjLjZCSFpBrWrSpC0lY536sfmmtmt89GF2Ocin8cnZg01UEg/0JYGOnMj1Og==
   dependencies:
     isomorphic-fetch "^2.2.1"
 

From 8f1ba8df830ec452eea97ac627d931ea126a799c Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Thu, 5 Jan 2023 15:25:52 +0000
Subject: [PATCH 14/25] Remove unnecessary exports.

---
 balancer-js/src/modules/data/pool/subgraph.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/balancer-js/src/modules/data/pool/subgraph.ts b/balancer-js/src/modules/data/pool/subgraph.ts
index 18ad56425..d54613f00 100644
--- a/balancer-js/src/modules/data/pool/subgraph.ts
+++ b/balancer-js/src/modules/data/pool/subgraph.ts
@@ -33,11 +33,11 @@ interface PoolsSubgraphRepositoryOptions {
   query?: GraphQLQuery;
 }
 
-export interface SubgraphSubPoolToken extends SubgraphSubPoolTokenFragment {
+interface SubgraphSubPoolToken extends SubgraphSubPoolTokenFragment {
   token?: SubgraphSubPoolMeta | null;
 }
 
-export interface SubgraphSubPoolMeta {
+interface SubgraphSubPoolMeta {
   latestUSDPrice?: string | null;
   pool?: SubgraphSubPool | null;
 }

From b72f6b5ec0b854fdc851b602a8c2090e838a4986 Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Thu, 5 Jan 2023 15:29:10 +0000
Subject: [PATCH 15/25] Update default args totalShares to filter more.

---
 balancer-js/src/modules/data/pool/subgraph.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/balancer-js/src/modules/data/pool/subgraph.ts b/balancer-js/src/modules/data/pool/subgraph.ts
index d54613f00..a03e0893d 100644
--- a/balancer-js/src/modules/data/pool/subgraph.ts
+++ b/balancer-js/src/modules/data/pool/subgraph.ts
@@ -81,7 +81,7 @@ export class PoolsSubgraphRepository
           eq: true,
         },
         totalShares: {
-          gt: 0,
+          gt: 0.000000000001,
         },
       },
     };

From 272a9949b22978e70be3dabf1e0603ea77a73009 Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Thu, 5 Jan 2023 15:30:53 +0000
Subject: [PATCH 16/25] Add comments for pool filtering.

---
 balancer-js/src/modules/exits/exits.module.integration.spec.ts | 1 +
 balancer-js/src/modules/joins/joins.module.integration.spec.ts | 1 +
 2 files changed, 2 insertions(+)

diff --git a/balancer-js/src/modules/exits/exits.module.integration.spec.ts b/balancer-js/src/modules/exits/exits.module.integration.spec.ts
index 4a5564b97..ca58becb3 100644
--- a/balancer-js/src/modules/exits/exits.module.integration.spec.ts
+++ b/balancer-js/src/modules/exits/exits.module.integration.spec.ts
@@ -66,6 +66,7 @@ const tenderlyConfig: BalancerTenderlyConfig = {
   blockNumber,
 };
 
+// This filters to pool addresses of interest to avoid too many onchain calls during tests
 const poolAddresses = Object.values(addresses).map(
   (address) => address.address
 );
diff --git a/balancer-js/src/modules/joins/joins.module.integration.spec.ts b/balancer-js/src/modules/joins/joins.module.integration.spec.ts
index 3c20f706e..98a8b97a5 100644
--- a/balancer-js/src/modules/joins/joins.module.integration.spec.ts
+++ b/balancer-js/src/modules/joins/joins.module.integration.spec.ts
@@ -70,6 +70,7 @@ const tenderlyConfig: BalancerTenderlyConfig = {
   blockNumber,
 };
 
+// This filters to pool addresses of interest to avoid too many onchain calls during tests
 const poolAddresses = Object.values(addresses).map(
   (address) => address.address
 );

From b5a67ac187447b560b28ad7437556296cf4ae88e Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Mon, 9 Jan 2023 10:56:21 +0000
Subject: [PATCH 17/25] Move peer dependencies into dependencies to improve dev
 UX.

---
 balancer-js/package.json     | 26 ++++++++------------------
 balancer-js/rollup.config.ts |  3 +--
 2 files changed, 9 insertions(+), 20 deletions(-)

diff --git a/balancer-js/package.json b/balancer-js/package.json
index c7f62cb6f..694d7a367 100644
--- a/balancer-js/package.json
+++ b/balancer-js/package.json
@@ -32,14 +32,6 @@
     "node:goerli": "npx hardhat --tsconfig tsconfig.testing.json --config hardhat.config.goerli.ts node --fork $(grep ALCHEMY_URL_GOERLI .env | cut -d '=' -f2 | tail -1) --port 8000"
   },
   "devDependencies": {
-    "@ethersproject/abi": "^5.4.0",
-    "@ethersproject/abstract-signer": "^5.4.0",
-    "@ethersproject/address": "^5.4.0",
-    "@ethersproject/bignumber": "^5.4.0",
-    "@ethersproject/bytes": "^5.4.0",
-    "@ethersproject/constants": "^5.4.0",
-    "@ethersproject/contracts": "^5.4.0",
-    "@ethersproject/providers": "^5.4.5",
     "@ethersproject/solidity": "^5.6.1",
     "@ethersproject/units": "^5.7.0",
     "@ethersproject/wallet": "^5.5.0",
@@ -89,15 +81,6 @@
     "typescript": "^4.0.2"
   },
   "dependencies": {
-    "@balancer-labs/sor": "^4.0.1-beta.16",
-    "@balancer-labs/typechain": "^1.0.0",
-    "axios": "^0.24.0",
-    "graphql": "^15.6.1",
-    "graphql-request": "^3.5.0",
-    "json-to-graphql-query": "^2.2.4",
-    "lodash": "^4.17.21"
-  },
-  "peerDependencies": {
     "@ethersproject/abi": "^5.4.0",
     "@ethersproject/abstract-signer": "^5.4.0",
     "@ethersproject/address": "^5.4.0",
@@ -105,6 +88,13 @@
     "@ethersproject/bytes": "^5.4.0",
     "@ethersproject/constants": "^5.4.0",
     "@ethersproject/contracts": "^5.4.0",
-    "@ethersproject/providers": "^5.4.5"
+    "@ethersproject/providers": "^5.4.5",
+    "@balancer-labs/sor": "^4.0.1-beta.16",
+    "@balancer-labs/typechain": "^1.0.0",
+    "axios": "^0.24.0",
+    "graphql": "^15.6.1",
+    "graphql-request": "^3.5.0",
+    "json-to-graphql-query": "^2.2.4",
+    "lodash": "^4.17.21"
   }
 }
diff --git a/balancer-js/rollup.config.ts b/balancer-js/rollup.config.ts
index c51c421e0..7402fbb83 100644
--- a/balancer-js/rollup.config.ts
+++ b/balancer-js/rollup.config.ts
@@ -7,8 +7,7 @@ import dts from 'rollup-plugin-dts';
 import pkg from './package.json';
 
 const external = [
-  ...Object.keys(pkg.dependencies),
-  ...Object.keys(pkg.peerDependencies),
+  ...Object.keys(pkg.dependencies)
 ];
 
 export default [

From 4afd56878922ac8d3d0c717943324574a3aa3cf1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?F=C3=A1bio=20Mendes?= <ms.fabiomendes@gmail.com>
Date: Mon, 9 Jan 2023 09:46:07 -0300
Subject: [PATCH 18/25] add gnosis to networks

---
 balancer-js/src/lib/constants/config.ts  | 20 ++++++++++++++++++++
 balancer-js/src/lib/constants/network.ts |  1 +
 2 files changed, 21 insertions(+)

diff --git a/balancer-js/src/lib/constants/config.ts b/balancer-js/src/lib/constants/config.ts
index d875025f2..1a1cb0420 100644
--- a/balancer-js/src/lib/constants/config.ts
+++ b/balancer-js/src/lib/constants/config.ts
@@ -209,6 +209,26 @@ export const BALANCER_NETWORK_CONFIG: Record<Network, BalancerNetworkConfig> = {
     },
     pools: {},
   },
+  [Network.GNOSIS]: {
+    chainId: Network.GNOSIS, //100
+    addresses: {
+      contracts: {
+        vault: '0xBA12222222228d8Ba445958a75a0704d566BF2C8',
+        multicall: '0xb5b692a88bdfc81ca69dcb1d924f59f0413a602a',
+        relayerV4: '0xeF606F58A4FD0fCcb066c6203d0994694d3eB2D3',
+        balancerHelpers: '0x8E9aa87E45e92bad84D5F8DD1bff34Fb92637dE9',
+      },
+      tokens: {
+        wrappedNativeAsset: '0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d',
+      },
+    },
+    urls: {
+      subgraph:
+        'https://api.thegraph.com/subgraphs/name/balancer-labs/balancer-gnosis-chain-v2',
+      gaugesSubgraph: '',
+    },
+    pools: {},
+  },
 };
 
 export const networkAddresses = (
diff --git a/balancer-js/src/lib/constants/network.ts b/balancer-js/src/lib/constants/network.ts
index fd009b33e..0e78f617d 100644
--- a/balancer-js/src/lib/constants/network.ts
+++ b/balancer-js/src/lib/constants/network.ts
@@ -6,6 +6,7 @@ export enum Network {
   GĂ–RLI = 5,
   OPTIMISM = 10,
   KOVAN = 42,
+  GNOSIS = 100,
   POLYGON = 137,
   ARBITRUM = 42161,
 }

From 55956f8e29e7ce9a3da30544e114e8d2b15020bd Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk+bot@users.noreply.github.com>
Date: Mon, 9 Jan 2023 13:27:53 +0000
Subject: [PATCH 19/25] chore: version bump v0.1.44-beta.0

---
 balancer-js/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/balancer-js/package.json b/balancer-js/package.json
index c7f62cb6f..90be87ed6 100644
--- a/balancer-js/package.json
+++ b/balancer-js/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@balancer-labs/sdk",
-  "version": "0.1.43",
+  "version": "0.1.44-beta.0",
   "description": "JavaScript SDK for interacting with the Balancer Protocol V2",
   "license": "GPL-3.0-only",
   "homepage": "https://github.com/balancer-labs/balancer-sdk#readme",

From e1ca821edfca8e261b707920f81f9cb15a01bbaa Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Mon, 9 Jan 2023 14:20:13 +0000
Subject: [PATCH 20/25] Improve Generic var name.

---
 balancer-js/src/modules/sor/pool-data/onChainData.ts | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/balancer-js/src/modules/sor/pool-data/onChainData.ts b/balancer-js/src/modules/sor/pool-data/onChainData.ts
index 6bf623b9e..02888139d 100644
--- a/balancer-js/src/modules/sor/pool-data/onChainData.ts
+++ b/balancer-js/src/modules/sor/pool-data/onChainData.ts
@@ -14,12 +14,14 @@ import elementPoolAbi from '@/lib/abi/ConvergentCurvePool.json';
 import linearPoolAbi from '@/lib/abi/LinearPool.json';
 import composableStableAbi from '@/lib/abi/ComposableStable.json';
 
-export async function getOnChainBalances<Type extends SubgraphPoolBase | Pool>(
-  subgraphPoolsOriginal: Type[],
+export async function getOnChainBalances<
+  GenericPool extends SubgraphPoolBase | Pool
+>(
+  subgraphPoolsOriginal: GenericPool[],
   multiAddress: string,
   vaultAddress: string,
   provider: Provider
-): Promise<Type[]> {
+): Promise<GenericPool[]> {
   if (subgraphPoolsOriginal.length === 0) return subgraphPoolsOriginal;
 
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -41,7 +43,7 @@ export async function getOnChainBalances<Type extends SubgraphPoolBase | Pool>(
   const multiPool = new Multicaller(multiAddress, provider, abis);
 
   const supportedPoolTypes: string[] = Object.values(PoolFilter);
-  const subgraphPools: Type[] = [];
+  const subgraphPools: GenericPool[] = [];
   subgraphPoolsOriginal.forEach((pool) => {
     if (!supportedPoolTypes.includes(pool.poolType)) {
       console.error(`Unknown pool type: ${pool.poolType} ${pool.id}`);
@@ -173,7 +175,7 @@ export async function getOnChainBalances<Type extends SubgraphPoolBase | Pool>(
     throw `Issue with multicall execution.`;
   }
 
-  const onChainPools: Type[] = [];
+  const onChainPools: GenericPool[] = [];
 
   Object.entries(pools).forEach(([poolId, onchainData], index) => {
     try {

From 9b841ea4f73689af91055edc031da76b60acbff0 Mon Sep 17 00:00:00 2001
From: sssmi <simeon.kerkola@gmail.com>
Date: Mon, 9 Jan 2023 22:05:55 +0200
Subject: [PATCH 21/25] Fix: Ignore casing when comparing pool token addresses
 in exit concerns

---
 .../pools/pool-types/concerns/metaStable/exit.concern.ts    | 6 ++++--
 .../pools/pool-types/concerns/stable/exit.concern.ts        | 6 ++++--
 .../pools/pool-types/concerns/weighted/exit.concern.ts      | 6 ++++--
 3 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/balancer-js/src/modules/pools/pool-types/concerns/metaStable/exit.concern.ts b/balancer-js/src/modules/pools/pool-types/concerns/metaStable/exit.concern.ts
index c10860dfd..b3693d42f 100644
--- a/balancer-js/src/modules/pools/pool-types/concerns/metaStable/exit.concern.ts
+++ b/balancer-js/src/modules/pools/pool-types/concerns/metaStable/exit.concern.ts
@@ -7,7 +7,7 @@ import {
   ExitPool,
   ExitPoolAttributes,
 } from '../types';
-import { AssetHelpers, parsePoolInfo } from '@/lib/utils';
+import { AssetHelpers, isSameAddress, parsePoolInfo } from '@/lib/utils';
 import { Vault__factory } from '@balancer-labs/typechain';
 import { addSlippage, subSlippage } from '@/lib/utils/slippageHelper';
 import { balancerVault } from '@/lib/constants/config';
@@ -31,7 +31,9 @@ export class MetaStablePoolExit implements ExitConcern {
     if (
       singleTokenMaxOut &&
       singleTokenMaxOut !== AddressZero &&
-      !pool.tokens.map((t) => t.address).some((a) => a === singleTokenMaxOut)
+      !pool.tokens
+        .map((t) => t.address)
+        .some((a) => isSameAddress(a, singleTokenMaxOut))
     ) {
       throw new BalancerError(BalancerErrorCode.TOKEN_MISMATCH);
     }
diff --git a/balancer-js/src/modules/pools/pool-types/concerns/stable/exit.concern.ts b/balancer-js/src/modules/pools/pool-types/concerns/stable/exit.concern.ts
index f193e36ca..eaa04b477 100644
--- a/balancer-js/src/modules/pools/pool-types/concerns/stable/exit.concern.ts
+++ b/balancer-js/src/modules/pools/pool-types/concerns/stable/exit.concern.ts
@@ -8,7 +8,7 @@ import {
   ExitPool,
   ExitPoolAttributes,
 } from '../types';
-import { AssetHelpers, parsePoolInfo } from '@/lib/utils';
+import { AssetHelpers, isSameAddress, parsePoolInfo } from '@/lib/utils';
 import { Vault__factory } from '@balancer-labs/typechain';
 import { addSlippage, subSlippage } from '@/lib/utils/slippageHelper';
 import { balancerVault } from '@/lib/constants/config';
@@ -32,7 +32,9 @@ export class StablePoolExit implements ExitConcern {
     if (
       singleTokenMaxOut &&
       singleTokenMaxOut !== AddressZero &&
-      !pool.tokens.map((t) => t.address).some((a) => a === singleTokenMaxOut)
+      !pool.tokens
+        .map((t) => t.address)
+        .some((a) => isSameAddress(a, singleTokenMaxOut))
     ) {
       throw new BalancerError(BalancerErrorCode.TOKEN_MISMATCH);
     }
diff --git a/balancer-js/src/modules/pools/pool-types/concerns/weighted/exit.concern.ts b/balancer-js/src/modules/pools/pool-types/concerns/weighted/exit.concern.ts
index abf7b5d13..e8d602719 100644
--- a/balancer-js/src/modules/pools/pool-types/concerns/weighted/exit.concern.ts
+++ b/balancer-js/src/modules/pools/pool-types/concerns/weighted/exit.concern.ts
@@ -7,7 +7,7 @@ import {
   ExitPool,
   ExitPoolAttributes,
 } from '../types';
-import { AssetHelpers, parsePoolInfo } from '@/lib/utils';
+import { AssetHelpers, isSameAddress, parsePoolInfo } from '@/lib/utils';
 import { Vault__factory } from '@balancer-labs/typechain';
 import { WeightedPoolEncoder } from '@/pool-weighted';
 import { addSlippage, subSlippage } from '@/lib/utils/slippageHelper';
@@ -31,7 +31,9 @@ export class WeightedPoolExit implements ExitConcern {
     if (
       singleTokenMaxOut &&
       singleTokenMaxOut !== AddressZero &&
-      !pool.tokens.map((t) => t.address).some((a) => a === singleTokenMaxOut)
+      !pool.tokens
+        .map((t) => t.address)
+        .some((a) => isSameAddress(a, singleTokenMaxOut))
     ) {
       throw new BalancerError(BalancerErrorCode.TOKEN_MISMATCH);
     }

From e8765ec9aa78bc0e1fbb8688a9ad96ddf4ec6333 Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk+bot@users.noreply.github.com>
Date: Tue, 10 Jan 2023 11:32:35 +0000
Subject: [PATCH 22/25] chore: version bump v0.1.44-beta.1

---
 balancer-js/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/balancer-js/package.json b/balancer-js/package.json
index 6388312a3..cb55f7810 100644
--- a/balancer-js/package.json
+++ b/balancer-js/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@balancer-labs/sdk",
-  "version": "0.1.44-beta.0",
+  "version": "0.1.44-beta.1",
   "description": "JavaScript SDK for interacting with the Balancer Protocol V2",
   "license": "GPL-3.0-only",
   "homepage": "https://github.com/balancer-labs/balancer-sdk#readme",

From eac4575ac051d0b6c1bf4528626162c75923c2fc Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Tue, 10 Jan 2023 11:35:14 +0000
Subject: [PATCH 23/25] Update SOR.

---
 balancer-js/package.json | 4 ++--
 balancer-js/yarn.lock    | 8 ++++----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/balancer-js/package.json b/balancer-js/package.json
index 237662ac1..4cf11e23f 100644
--- a/balancer-js/package.json
+++ b/balancer-js/package.json
@@ -81,6 +81,8 @@
     "typescript": "^4.0.2"
   },
   "dependencies": {
+    "@balancer-labs/sor": "^4.0.1-beta.18",
+    "@balancer-labs/typechain": "^1.0.0",
     "@ethersproject/abi": "^5.4.0",
     "@ethersproject/abstract-signer": "^5.4.0",
     "@ethersproject/address": "^5.4.0",
@@ -89,8 +91,6 @@
     "@ethersproject/constants": "^5.4.0",
     "@ethersproject/contracts": "^5.4.0",
     "@ethersproject/providers": "^5.4.5",
-    "@balancer-labs/sor": "^4.0.1-beta.16",
-    "@balancer-labs/typechain": "^1.0.0",
     "axios": "^0.24.0",
     "graphql": "^15.6.1",
     "graphql-request": "^3.5.0",
diff --git a/balancer-js/yarn.lock b/balancer-js/yarn.lock
index fdfd4f10e..00ffc3ce4 100644
--- a/balancer-js/yarn.lock
+++ b/balancer-js/yarn.lock
@@ -503,10 +503,10 @@
     "@babel/helper-validator-identifier" "^7.19.1"
     to-fast-properties "^2.0.0"
 
-"@balancer-labs/sor@^4.0.1-beta.17":
-  version "4.0.1-beta.17"
-  resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.0.1-beta.17.tgz#b78d67ba4107d4ec366015532d34b5c7af3b0169"
-  integrity sha512-KSkPs8Rxn/MPLNeO51uQWffvCJCjLjZCSFpBrWrSpC0lY536sfmmtmt89GF2Ocin8cnZg01UEg/0JYGOnMj1Og==
+"@balancer-labs/sor@^4.0.1-beta.18":
+  version "4.0.1-beta.18"
+  resolved "https://registry.yarnpkg.com/@balancer-labs/sor/-/sor-4.0.1-beta.18.tgz#811af4b41f8e9f670c1a38e5f5f2f131d28178ed"
+  integrity sha512-tNY9OIptCVCysSYY6QKBIpJleM66DMKRK78t1WOG1boJbay3kCm+x9R4+6LN5n05gDYM0PE2QwCPytOxzkrCfA==
   dependencies:
     isomorphic-fetch "^2.2.1"
 

From 883a3822270c232f2f22e599f08e7ce5288d8d0f Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk+bot@users.noreply.github.com>
Date: Tue, 10 Jan 2023 11:44:00 +0000
Subject: [PATCH 24/25] chore: version bump v0.1.44-beta.2

---
 balancer-js/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/balancer-js/package.json b/balancer-js/package.json
index 4cf11e23f..f6cfe5c7b 100644
--- a/balancer-js/package.json
+++ b/balancer-js/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@balancer-labs/sdk",
-  "version": "0.1.44-beta.1",
+  "version": "0.1.44-beta.2",
   "description": "JavaScript SDK for interacting with the Balancer Protocol V2",
   "license": "GPL-3.0-only",
   "homepage": "https://github.com/balancer-labs/balancer-sdk#readme",

From b1964352326c8b534a2d3c3a019df98bba876144 Mon Sep 17 00:00:00 2001
From: johngrantuk <johngrantuk@googlemail.com>
Date: Tue, 10 Jan 2023 11:46:17 +0000
Subject: [PATCH 25/25] Update to version 0.1.44.

---
 balancer-js/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/balancer-js/package.json b/balancer-js/package.json
index f6cfe5c7b..16aa1300a 100644
--- a/balancer-js/package.json
+++ b/balancer-js/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@balancer-labs/sdk",
-  "version": "0.1.44-beta.2",
+  "version": "0.1.44",
   "description": "JavaScript SDK for interacting with the Balancer Protocol V2",
   "license": "GPL-3.0-only",
   "homepage": "https://github.com/balancer-labs/balancer-sdk#readme",