Skip to content

Commit

Permalink
Merge pull request #14 from Lynexfi/main
Browse files Browse the repository at this point in the history
Lynex adapter
  • Loading branch information
RamonReis authored Apr 14, 2024
2 parents 96769ad + ed7e2e9 commit d97c690
Show file tree
Hide file tree
Showing 11 changed files with 3,145 additions and 0 deletions.
32 changes: 32 additions & 0 deletions adapters/lynex/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "lynex-adapter",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node dist/index.js",
"compile": "tsc",
"watch": "tsc -w",
"clear": "rm -rf dist"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@types/big.js": "^6.2.2",
"big.js": "^6.2.1",
"bignumber.js": "^9.1.2",
"csv-parser": "^3.0.0",
"decimal.js-light": "^2.5.1",
"fast-csv": "^5.0.1",
"jsbi": "^4.3.0",
"tiny-invariant": "^1.3.1",
"toformat": "^2.0.0",
"viem": "^2.8.13"
},
"devDependencies": {
"@types/node": "^20.11.17",
"typescript": "^5.3.3"
}
}
201 changes: 201 additions & 0 deletions adapters/lynex/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import fs from "fs";
import { write } from "fast-csv";
import { getTimestampAtBlock, getUserAddresses } from "./sdk/subgraphDetails";
import {
VE_LYNX_ADDRESS,
fetchUserPools,
fetchUserVotes,
} from "./sdk/lensDetails";
import BigNumber from "bignumber.js";
import { BlockData, OutputSchemaRow } from "./sdk/types";
import {
getV2UserPositionsAtBlock,
getV3UserPositionsAtBlock,
} from "./sdk/pools";

const getData = async () => {
const snapshotBlocks = [3460121];

const csvRows: OutputSchemaRow[] = [];

for (let block of snapshotBlocks) {
const timestamp = await getTimestampAtBlock(block);
csvRows.push(
...(await getUserTVLByBlock({
blockNumber: block,
blockTimestamp: timestamp,
}))
);
}

const ws = fs.createWriteStream("outputData.csv");
write(csvRows, { headers: true })
.pipe(ws)
.on("finish", () => {
console.log("CSV file has been written.");
});
};

export const getUserTVLByBlock = async ({
blockNumber,
blockTimestamp,
}: BlockData): Promise<OutputSchemaRow[]> => {
const result: OutputSchemaRow[] = [];

const [stakedTvl, liquidityTvl] = await Promise.all([
getUserStakedTVLByBlock({ blockNumber, blockTimestamp }),
getUserLiquidityTVLByBlock({ blockNumber, blockTimestamp }),
]);

// combine staked & unstaked
const combinedPositions = [...stakedTvl, ...liquidityTvl];
const balances: Record<string, Record<string, bigint>> = {};
for (const position of combinedPositions) {
balances[position.user_address] = balances[position.user_address] || {};

if (position.token_balance > 0n)
balances[position.user_address][position.token_address] =
(balances?.[position.user_address]?.[position.token_address] ?? 0n) +
position.token_balance;
}

for (const [user, tokenBalances] of Object.entries(balances)) {
for (const [token, balance] of Object.entries(tokenBalances)) {
result.push({
block_number: blockNumber,
timestamp: blockTimestamp,
user_address: user,
token_address: token,
token_balance: balance,
});
}
}

return result;
};

export const getUserStakedTVLByBlock = async ({
blockNumber,
blockTimestamp,
}: BlockData): Promise<OutputSchemaRow[]> => {
const result: OutputSchemaRow[] = [];
const [userAddresses] = await Promise.all([getUserAddresses(blockNumber)]);
console.log(`Block: ${blockNumber}`);
console.log("UserAddresses: ", userAddresses.length);

const tokenBalanceMap = {} as {
[userAddress: string]: { [tokenAddress: string]: BigNumber };
};

const userPoolFetch = [];
const userVotesFetch = [];

for (const user of userAddresses) {
userPoolFetch.push(
fetchUserPools(BigInt(blockNumber), user.id, user.pools)
);
userVotesFetch.push(fetchUserVotes(BigInt(blockNumber), user.id));
}

const userFetchResult = await Promise.all(userPoolFetch);
const userVotesResult = await Promise.all(userVotesFetch);

for (const userFetchedPools of userFetchResult) {
for (const userPool of userFetchedPools) {
const user_address = userPool.result.userAddress.toLowerCase();
const totalLPBalance = userPool.result.account_gauge_balance;
const total0 =
(totalLPBalance * userPool.result.reserve0) /
userPool.result.total_supply;
const total1 =
(totalLPBalance * userPool.result.reserve1) /
userPool.result.total_supply;
const token0Address = userPool.result.token0.toLowerCase();
const token1Address = userPool.result.token1.toLowerCase();

// Aggregate tokens
tokenBalanceMap[user_address] = tokenBalanceMap[user_address] ?? {};
tokenBalanceMap[user_address][token0Address] = BigNumber(
tokenBalanceMap[user_address][token0Address] ?? 0
).plus(total0.toString());
tokenBalanceMap[user_address] = tokenBalanceMap[user_address] ?? {};
tokenBalanceMap[user_address][token1Address] = BigNumber(
tokenBalanceMap[user_address][token1Address] ?? 0
).plus(total1.toString());
}
}

for (const userFecthedVotes of userVotesResult) {
for (const userVote of userFecthedVotes) {
const user_address = userVote.result.userAddress.toLowerCase();
const token0Address = VE_LYNX_ADDRESS.toLowerCase();
tokenBalanceMap[user_address] = tokenBalanceMap[user_address] ?? {};
tokenBalanceMap[user_address][token0Address] = BigNumber(
tokenBalanceMap[user_address][token0Address] ?? 0
).plus(userVote.result.amount.toString());
}
}

Object.entries(tokenBalanceMap).forEach(([user_address, balances]) => {
Object.entries(balances).forEach(([token_address, token_balance]) => {
if (token_balance.dp(0).lte(0)) {
return;
}
result.push({
block_number: blockNumber,
timestamp: blockTimestamp,
user_address,
token_address,
token_balance: BigInt(token_balance.dp(0).toNumber()),
});
});
});
return result;
};

export const getUserLiquidityTVLByBlock = async ({
blockNumber,
blockTimestamp,
}: BlockData): Promise<OutputSchemaRow[]> => {
const result: OutputSchemaRow[] = [];

const [v2Positions, v3Positions] = await Promise.all([
getV2UserPositionsAtBlock(blockNumber),
getV3UserPositionsAtBlock(blockNumber),
]);

// combine v2 & v3
const combinedPositions = [...v2Positions, ...v3Positions];
const balances: Record<string, Record<string, bigint>> = {};
for (const position of combinedPositions) {
balances[position.user] = balances[position.user] || {};

if (position.token0.balance > 0n)
balances[position.user][position.token0.address] =
(balances?.[position.user]?.[position.token0.address] ?? 0n) +
position.token0.balance;

if (position.token1.balance > 0n)
balances[position.user][position.token1.address] =
(balances?.[position.user]?.[position.token1.address] ?? 0n) +
position.token1.balance;
}

for (const [user, tokenBalances] of Object.entries(balances)) {
for (const [token, balance] of Object.entries(tokenBalances)) {
result.push({
block_number: blockNumber,
timestamp: blockTimestamp,
user_address: user,
token_address: token,
token_balance: balance,
});
}
}

return result;
};

getData().then(() => {
console.log("Done");
});
Loading

0 comments on commit d97c690

Please sign in to comment.