Comment on page
Adapter
Your dApp or protocol needs adapters if you need to transform the raw on-chain data into meaningful information relevant to the protocol's core logic.
To have more control over the kind of data you want to collect, you can code an adapter that listens to on-chain events of your protocol. You need an adapter if you want to:
- Calculate the total value locked (TVL) in your protocol,
- Value extractions from the protocol,
- Value contributions in the protocol,
- Average protocol activity,
- Average transactions per user,
- And much more.
The adapter uses two approaches for transforming the raw on-chain data. The first are the transformers that track the contributions (USD value deposited in the protocol) and extraction (USD value withdrawn from protocol), and the second are the TVL extractors that are responsible to calculate the asset in terms of USD locked in a protocol.
Each adapter basically returns the following object.
type Adapter = {
appKey: string;
transformers?: Record<Chain, Array<Transformer>>;
tvlExtractors?: Record<Chain, Array<TvlExtractor>>;
};
Below you can see the basic example of an adapter, one that we have coded for Uniswap v3 on Ethereum. It basically marks add liquidity as contribution and remove liquidity as extraction.
projects/uniswap/index.ts
1
import { sumBalancesUSD } from "../../utils/sumBalances";
2
import { BurnEventObject, MintEventObject } from "./types/Pool";
3
import { pool, BURN, MINT, uniswapV3Pool, Label } from "./utils";
4
import { constants, types, utils } from "@spockanalytics/base";
5
6
export async function mintEvent(event: types.Event<MintEventObject>) {
7
const pool = await uniswapV3Pool.getPool(event.address, event.chain);
8
if (pool) {
9
const [block, transaction] = await Promise.all([event.block, event.transaction]);
10
const totalSum = await sumBalancesUSD(
11
[
12
{ token: pool.token0, balance: event.params.amount0 },
13
{ token: pool.token1, balance: event.params.amount1 },
14
],
15
event.chain,
16
block.timestamp,
17
);
18
return utils.ProtocolValue.contribution({
19
label: Label.DEPOSIT,
20
value: parseFloat(totalSum.toString()),
21
user: transaction.from,
22
});
23
}
24
}
25
26
export async function burnEvent(event: types.Event<BurnEventObject>) {
27
const pool = await uniswapV3Pool.getPool(event.address, event.chain);
28
if (pool) {
29
const [block, transaction] = await Promise.all([event.block, event.transaction]);
30
const totalSum = await sumBalancesUSD(
31
[
32
{ token: pool.token0, balance: event.params.amount0 },
33
{ token: pool.token1, balance: event.params.amount1 },
34
],
35
event.chain,
36
block.timestamp,
37
);
38
return utils.ProtocolValue.extraction({
39
label: Label.WITHDRAW,
40
value: parseFloat(totalSum.toString()),
41
user: transaction.from,
42
});
43
}
44
}
45
46
const uniswapAdapter: types.Adapter = {
47
appKey: "70dbe55c4987d9ac9d84605d9edb8e6781bae2d631d649e176656e6bd3642fd9",
48
transformers: {
49
[constants.Chain.ETHEREUM]: [
50
{
51
contract: pool,
52
eventHandlers: {
53
[MINT]: mintEvent,
54
[BURN]: burnEvent,
55
},
56
startBlock: 12369621,
57
},
58
],
59
},
60
};
61
62
export default uniswapAdapter;ja
In this example, we have one transformer for the Uniswap pool contract with two event handlers
mint
for contribution and burn
for extraction.The adapter collects data from the events that are responsible for contributions and extractions.
Yes, if there are multiple contracts with the same event signatures like uniswap-v3 pools you can universally sync data by just removing the field of
address
in the transformer. Also if you have maintained address mapping you can also pass it in the
getAddresses
field to sync data for all the specified addresses.You can write tests in the file
index.test.ts
inside your project directory. In each test, you have to pass the transaction hash to verify that the logic is working as expected.In order to read something from the contract you can use our built-in class.
If you are stuck anywhere or have a suggestion or feedback, you can fill out the form here, or reach out to our team at [email protected].
Last modified 3mo ago