Comment on page
How to build an adapter
And adapter is just some code that:
- 1.Collects data on a protocol by calling some endpoints or making some blockchain calls
- 2.Computes a response and returns it.
That's just a typescript file that exports an async function that given a timestamp and/or block numbers returns an object with some information.
A really simplified version of an adapter could be the following lines:
export default {
adapter: {
ethereum: {
fetch: (timestamp: number) => {
const { dayVolume, totalVolume } = await getVolumeStats();
return {
timestamp,
dailyVolume: dayVolume,
totalVolume: totalVolume,
};
},
},
optimism: {
...
}
},
};
The above adapter is for a protocol that is deployed on
ethereum
and optimism
, and will return the daily and total volume of the protocol. Depends on which dashboard the adapter is aiming for, it should return different attributes. We call those attributes dimensions. In the next page you will find a detailed list of all supported dimensions.In the above example, the object under the key
ethereum
is what we call a BaseAdapter
and it contains all the methods and information needed to list, collect data and enable your project.The attribute
fetch
is the most important part of the BaseAdapter but not the only attribute needed to list your project. Other important attributes needed for an optimal listing are:fetch
: Promise that returns different dimensions of a protocol given a timestamp and a block number. The dimensions returned depends on which adapter you would like to list your project (e.g. `dailyVolume` and `totalVolume` for the dexs dashboard).start
: Promise that returns a timestamp pointing to the earliest timestamp we can pass to the fetch function. This tells our servers how far can we get historical data.runAtCurrTime
: Boolean that flags if the adapter takes into account the timestamp and block passed to the fetch function (runAtCurrTime: false
) or if it can only return the latest data, for example there are some adapters that are only able to return the volume of the past 24h from the moment the adapter is executed (runAtCurrTime: true
).meta
: Object that contains metadata of the BaseAdapter. The possible attributes are:
The example we have seen before is a
SimpleAdapter
of a protocol deployed on different chains, but...- What if we have multiple versions of our protocol deployed in the same chain?
- What if our protocol has different products? For example a DEX can provide spot trading as well as derivatives trading to their users.
For this situations you can create a
BreakdownAdapter
to have a BaseAdapter
for each version and chain. Here's a real example:const adapter: BreakdownAdapter = {
breakdown: {
v1: {
[CHAIN.ETHEREUM]: {
fetch: v1Graph(CHAIN.ETHEREUM),
start: async () => 1541203200,
},
},
v2: {
[CHAIN.ETHEREUM]: {
fetch: v2Graph(CHAIN.ETHEREUM),
start: getStartTimestamp({
endpoints: v2Endpoints,
chain: CHAIN.ETHEREUM,
}),
},
},
v3: Object.keys(v3Endpoints).reduce((acc, chain) => {
acc[chain] = {
fetch: v3Graphs(chain),
start: getStartTimestamp({
endpoints: v3Endpoints,
chain: chain,
volumeField: VOLUME_USD,
})
}
return acc
}, {} as BaseAdapter)
}
}
Keys of the breakdown object should be the name of the protocol version. E.g.: "v1" and "v2" or "swap" and "derivatives" or "elastic" and "classic".
By using the above structure (
BreakdownAdapter
) your protocol will be listed as an aggregated of all versions and will include a subrow for each version (see this ranking for some examples).As you can see in the above example the adapter is using the
BreakdownAdapter
type to make sure the types of the exported adapter is correct. Please use the appropriate types for a smooth listing.Since most adapters follow a similar structure, we've written some helper functions that you might help you writing your adapter. You will find information about these functions in the next pages.
Last modified 10mo ago