How to code an adapter?

You can code an adapter for your project by simply following these steps.

Step #1: Repository setup

Step #2: Project setup Step #2: Project setup

Now you have to set up your project directory inside src/projects. The file structure of the project directory will look like this.

│   └── abis
│   │   ├── contract1.json
│   │   └── contract2.json
│   ├── types
│   ├── index.test.ts
│   ├── index.ts
|   ├── tvl.ts
│   └── utils.ts
└── index.ts

First of all, create an abis folder in your project directory and add all the required abis of JSON format in it.

After that, you have to execute the command yarn generate PROJECT_NAME which will generate the types of abis through typechain. Now you are ready to code the core logic of your adapter.

Step # 03: Code transformer

Let's start coding from the transformer. For that, you have to create event handler functions in the index.ts file and add them to the adapter object which will be exported in the end.

Here we have an example of a Uniswap V3 mint event handler.

export async function mintEvent(event: types.Event<MintEventObject>) {
  const pool = await uniswapV3Pool.getPool(event.address, event.chain);
  if (pool) {
    const [block, transaction] = await Promise.all([event.block, event.transaction]);
    const totalSum = await sumBalancesUSD(
        { token: pool.token0, balance: event.params.amount0 },
        { token: pool.token1, balance: event.params.amount1 },
    return utils.ProtocolValue.contribution({
      label: Label.DEPOSIT,
      value: parseFloat(totalSum.toString()),
      user: transaction.from,

In the end, return these events handlers w.r.t to their contract and chain in transformers.

const uniswapAdapter: types.Adapter = {
  appKey: "70dbe55c4987d9ac9d84605d9edb8e6781bae2d631d649e176656e6bd3642fd9",
  transformers: {
    [constants.Chain.ETHEREUM]: [
        contract: pool,
        eventHandlers: {
          [MINT]: mintEvent,
          [BURN]: burnEvent,
        startBlock: 12369621,

export default uniswapAdapter;

You can add all the helper functions, constants, types, and other coding stuff in the utils.tsof your project to keep them separate from more transformer codes.

Step #4: Code TVL Extractor

For the TVL tracking of your protocol, you have to create an extractor function in the tvl.ts which will return the balances of the asset locked inside your protocol. Here we have an example of BullionFx TVL computation.

export async function computeTVL(chain: constants.Chain, block: number, timestamp: number) {
  const balances: SummedBalances = {};

  const pairs = await pairAddresses(chain, block);
  if (pairs) {
    const calls = pairs.flatMap((pair) => [
      new abi.Call<BullPair>({ address: pair, contractInterface: bullPair, fragment: "token0" }),
      new abi.Call<BullPair>({ address: pair, contractInterface: bullPair, fragment: "token1" }),
      new abi.Call<BullPair>({ address: pair, contractInterface: bullPair, fragment: "getReserves" }),

    const results = await abi.Multicall.execute({ chain, calls, blockNumber: block });

    utils.chunk(results, 3).forEach((result) => {
      sumSingleBalance(balances, result[0].output, result[2].output[0]);
      sumSingleBalance(balances, result[1].output, result[2].output[1]);

  return balances;

Step #5: Testing

In the end, after you are done with the adapter development, you can write tests for validating the transformers and TVL extractors' logic. For that, you have to write tests in the index.test.ts file of your project.

Step #6: Submit a PR

Once all the above steps are completed, your adapter is ready for syncing, push the code and create PR on the main branch of xorddotcom/spock-adapters.

A member of our team will then review and merge your code with the main branch.

Need Help? Contact Our Team

If you encounter any difficulties, have suggestions, or would like to provide feedback, feel free to contact us here or email our team at

Last updated