Skip to content

Commit

Permalink
Merge branch 'delta-hq:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
byeongsu-hong authored Aug 26, 2024
2 parents c8eb42f + c65fb3f commit 9533cbe
Show file tree
Hide file tree
Showing 75 changed files with 209,036 additions and 5,481 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ Ds_Store
.Ds_Store
package-lock.json
bun.lockb
outputData.csv
outputData.csv
.env
2 changes: 2 additions & 0 deletions adapters/affine/hourly_blocks.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
number,timestamp
8516509,1722948881
22 changes: 22 additions & 0 deletions adapters/affine/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "affine-adapter",
"version": "1.0.0",
"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"
},
"dependencies": {
"csv-parser": "^3.0.0",
"fast-csv": "^4.3.6",
"graphql": "^15.5.0",
"node-fetch": "^2.6.1"
},
"devDependencies": {
"ts-node": "^9.1.1",
"typescript": "^4.1.3"
}
}
157 changes: 157 additions & 0 deletions adapters/affine/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import fs from "fs";
import { write } from "fast-csv";
import csv from "csv-parser";

const assetWhitelist = ["ultraETHs"];

const GRAPHQL_ENDPOINT =
"https://api.goldsky.com/api/public/project_clzblgfi61ub601wncxx3bbit/subgraphs/affine-subgraph/prod/gn";

const makeBalancesQuery = (blockNumber: number, next = "") => `query {
tokenBalances(
block: {number: ${blockNumber}},
first: 1000,
where: { id_gt: "${next}", value_gt: 0 }
) {
token {
id
symbol
}
account {
id
}
value
id
}
}`;

interface BlockData {
blockNumber: number;
blockTimestamp: number;
}

interface TokenBalance {
token: {
id: string;
symbol: string;
};
account: {
id: string;
};
value: string;
id: string;
}

interface TokenBalancesResponse {
tokenBalances: TokenBalance[];
}

type OutputDataSchemaRow = {
block_number: number;
timestamp: number;
user_address: string;
token_address: string;
token_balance: bigint;
token_symbol: string; //token symbol should be empty string if it is not available
usd_price: number; //assign 0 if not available
};

async function post<T = any>(url: string, query: any): Promise<{ data: T }> {
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({ query }),
});

return response.json();
}

const toOutput = (
{ blockNumber, blockTimestamp }: BlockData,
{ tokenBalances }: TokenBalancesResponse
): OutputDataSchemaRow[] =>
tokenBalances
.map((v) => ({
block_number: blockNumber,
timestamp: blockTimestamp,
user_address: v.account.id,
token_address: v.token.id,
token_balance: BigInt(v.value),
token_symbol: v.token.symbol,
usd_price: 0,
}))
.filter((v) => assetWhitelist.includes(v.token_symbol));

export const getUserTVLByBlock = async (
blocks: BlockData
): Promise<OutputDataSchemaRow[]> => {
let next = "";
let output: OutputDataSchemaRow[] = [];

while (true) {
const { data: resp } = await post<TokenBalancesResponse>(
GRAPHQL_ENDPOINT,
makeBalancesQuery(blocks.blockNumber, next)
);
if (resp.tokenBalances.length === 0) break;

output = output.concat(toOutput(blocks, resp));
next = resp.tokenBalances[resp.tokenBalances.length - 1].id;
}

return output;
};

const readBlocksFromCSV = async (filePath: string): Promise<BlockData[]> => {
const blocks: BlockData[] = [];

await new Promise<void>((resolve, reject) => {
fs.createReadStream(filePath)
.pipe(csv()) // Specify the separator as '\t' for TSV files
.on("data", (row) => {
const blockNumber = parseInt(row.number, 10);
const blockTimestamp = parseInt(row.timestamp, 10);
if (!isNaN(blockNumber) && blockTimestamp) {
blocks.push({ blockNumber: blockNumber, blockTimestamp });
}
})
.on("end", () => {
resolve();
})
.on("error", (err) => {
reject(err);
});
});

return blocks;
};

readBlocksFromCSV("hourly_blocks.csv")
.then(async (blocks: any[]) => {
console.log(blocks);
const allCsvRows: any[] = [];

for (const block of blocks) {
try {
const result = await getUserTVLByBlock(block);
allCsvRows.push(...result);
} catch (error) {
console.error(`An error occurred for block ${block}:`, error);
}
}
await new Promise((resolve, reject) => {
const ws = fs.createWriteStream(`outputData.csv`, { flags: "w" });
write(allCsvRows, { headers: true })
.pipe(ws)
.on("finish", () => {
console.log(`CSV file has been written.`);
resolve;
});
});
})
.catch((err) => {
console.error("Error reading CSV file:", err);
});
2 changes: 2 additions & 0 deletions adapters/affine/test/sample_hourly_blocks.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
number,timestamp
8431382,1722948881
3 changes: 3 additions & 0 deletions adapters/affine/test/sample_output_data.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
block_number,timestamp,user_address,token_address,token_balance,token_symbol,usd_price
8431382,1722948881,0x46d886361d6b7ba0d28080132b6ec70e2e49f332,0xb838eb4f224c2454f2529213721500faf732bf4d,12979194952477146,ultraETHs,0
8431382,1722948881,0xdc956b7135aa7a99f8080e54def4148f8e54bca4,0xb838eb4f224c2454f2529213721500faf732bf4d,8495882945019253,ultraETHs,0
13 changes: 13 additions & 0 deletions adapters/affine/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["./**/*.ts"],
"exclude": ["node_modules"]
}
Loading

0 comments on commit 9533cbe

Please sign in to comment.