loadContracts: (toBlock: number) => Promise<void>;
This function is used to populate the following variables.
/**
* Metadata
*/
defiPools: IDefiPool[];
/**
* List of contracts holding LRTs e.g. UniswapV3 Pool, Pendle SY, Zircuit ZtakingPool
*/
vaultContracts: { [vault: string]: string[] };
Async function to load user shares between 2 blocks (inclusive).
loadUserShares: (contract: string, fromBlock: number, toBlock: number) =>
Promise<IDeFiUserShare[]>;
A user share represents the amount of LRT owned by an address pro-rata to others.
User shares are sorted by block and a new entry must be added each time LRT ratios change.
import { PublicClient } from "viem";
export class ZircuitDeFiCollector implements IDeFiCollector {
chainId: number;
client: PublicClient;
vaultContracts = {};
defiPools: IDefiPool[] = [];
constructor(chainId: number, client: PublicClient) {
this.chainId = chainId;
this.client = client;
}
public async loadContracts() {
if (this.chainId === 1) {
this.vaultContracts = {
"0x7a4EffD87C2f3C55CA251080b1343b605f327E3a": [
"0xF047ab4c75cebf0eB9ed34Ae2c186f3611aEAfa6",
],
"0x84631c0d0081FDe56DeB72F6DE77abBbF6A9f93a": [
"0x84631c0d0081FDe56DeB72F6DE77abBbF6A9f93a",
],
// ...
};
this.defiPools = [
{
id: "pool-zircuit-rstETH",
name: "rstETH",
protocol: "Zircuit",
vault: "0x7a4EffD87C2f3C55CA251080b1343b605f327E3a",
protocol_address: "0xF047ab4c75cebf0eB9ed34Ae2c186f3611aEAfa6",
url: "https://stake.zircuit.com/",
boost: 2,
},
{
id: "pool-zircuit-re7lrt",
name: "Re7LRT",
protocol: "Zircuit",
vault: "0x84631c0d0081FDe56DeB72F6DE77abBbF6A9f93a",
protocol_address: "0xF047ab4c75cebf0eB9ed34Ae2c186f3611aEAfa6",
url: "https://stake.zircuit.com/",
boost: 2,
},
// ...
];
}
}
public async loadUserShares(
contract: string, // ZtakingPool
fromBlock: number,
toBlock: number
) {
const userShares: IDeFiUserShare[] = [];
const vaults = Object.keys(this.vaultContracts);
const depositEvents = await getDepositEvents(contract);
const withdrawalEvents = await getWithdrawalEvents(contract);
// balance changes events
const events = [...depositEvents, ...withdrawalEvents].sort(
(a, b) => a.block - b.block
);
for (const event of events) {
// get user vaults balances at this block
const balances = await this.client.getMulticallBalance(
event.block,
event.user,
vaults
);
for (const balance of balances) {
userShares.push({
block: event.block,
user: event.user,
vault: balance.vault,
protocol_address: contract,
});
}
}
return userShares;
}
}
interface IDeFiUserShare {
block: number;
/**
* User address (checksummed)
*/
user: string;
/**
* Share amount
*/
amount: bigint;
/**
* Vault address (checksummed)
*/
vault: string;
/**
* Protocol address (checksummed) e.g. LP, SY, Credit Account
*/
protocol_address: string;
}
/**
* Pool metadata
*/
export interface IDefiPool {
/**
* Unique pool identifier
*/
id: string;
/**
* Pool display name
*/
name: string;
/**
* Protocol display name
*/
protocol: string;
/**
* Vault address (checksummed)
*/
vault: string;
/**
* Protocol address (checksummed) e.g. LP, SY, Credit Account
*/
protocol_address: string;
/**
* Link to protocol pool page
*/
url: string;
/**
* Mellow points multiplier e.g. 2, 3 for 2x or 3x boost
*/
boost: number;
}
export interface IDeFiCollector {
/**
* Metadata
*/
defiPools: IDefiPool[];
/**
* LRT holders e.g. UniswapV3 Pool, Pendle SY
*/
vaultContracts: { [vault: string]: string[] };
loadContracts: (toBlock: number) => Promise<void>;
loadUserShares: (
contract: string,
fromBlock: number,
toBlock: number
) => Promise<IDeFiUserShare[]>;
}