From b1ba28927d71b22a108f9dd0e86eaa20e6607d2f Mon Sep 17 00:00:00 2001 From: marsclimber0109 Date: Mon, 20 May 2024 19:26:49 +0900 Subject: [PATCH 1/5] index on main: 9c237b5 Merge pull request #138 from delta-hq/nitish/clip_name_change --- adapters/layerbank/package.json | 32 ++++++++++++++++++++++++++++++++ adapters/layerbank/tsconfig.json | 12 ++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 adapters/layerbank/package.json create mode 100644 adapters/layerbank/tsconfig.json diff --git a/adapters/layerbank/package.json b/adapters/layerbank/package.json new file mode 100644 index 00000000..e3dad046 --- /dev/null +++ b/adapters/layerbank/package.json @@ -0,0 +1,32 @@ +{ + "name": "layerbank-tvl", + "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" + } +} diff --git a/adapters/layerbank/tsconfig.json b/adapters/layerbank/tsconfig.json new file mode 100644 index 00000000..599cd43f --- /dev/null +++ b/adapters/layerbank/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "commonjs", + "rootDir": "src/", + "outDir": "dist/", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + } +} From bd1396b16d08b3eb0982759ae97a45eca840c53a Mon Sep 17 00:00:00 2001 From: marsclimber0109 Date: Mon, 20 May 2024 19:27:56 +0900 Subject: [PATCH 2/5] feat: layerbank subgraph init --- adapters/layerbank/src/index.ts | 132 +++ adapters/layerbank/src/sdk/abi/core.abi.ts | 812 ++++++++++++++++++ adapters/layerbank/src/sdk/abi/helpers.ts | 20 + adapters/layerbank/src/sdk/abi/ltoken.abi.ts | 656 ++++++++++++++ adapters/layerbank/src/sdk/config.ts | 19 + adapters/layerbank/src/sdk/marketDetails.ts | 163 ++++ adapters/layerbank/src/sdk/subgraphDetails.ts | 126 +++ 7 files changed, 1928 insertions(+) create mode 100644 adapters/layerbank/src/index.ts create mode 100644 adapters/layerbank/src/sdk/abi/core.abi.ts create mode 100644 adapters/layerbank/src/sdk/abi/helpers.ts create mode 100644 adapters/layerbank/src/sdk/abi/ltoken.abi.ts create mode 100644 adapters/layerbank/src/sdk/config.ts create mode 100644 adapters/layerbank/src/sdk/marketDetails.ts create mode 100644 adapters/layerbank/src/sdk/subgraphDetails.ts diff --git a/adapters/layerbank/src/index.ts b/adapters/layerbank/src/index.ts new file mode 100644 index 00000000..ca4b27e2 --- /dev/null +++ b/adapters/layerbank/src/index.ts @@ -0,0 +1,132 @@ +import { CHAINS, PROTOCOLS } from "./sdk/config"; +import { + getAccountStatesForAddressByPoolAtBlock, + getTimestampAtBlock, +} from "./sdk/subgraphDetails"; + +(BigInt.prototype as any).toJSON = function () { + return this.toString(); +}; + +import fs from "fs"; +import csv from "csv-parser"; +import { write } from "fast-csv"; +import { getMarketInfos, updateBorrowBalances } from "./sdk/marketDetails"; +import { bigMath } from "./sdk/abi/helpers"; +import { exit } from "process"; + +interface BlockData { + blockNumber: number; + blockTimestamp: number; +} + +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 +}; + +export const getUserTVLByBlock = async (blocks: BlockData) => { + const marketInfos = await getMarketInfos( + "0x43Eac5BFEa14531B8DE0B334E123eA98325de866" + ); + + const csvRows: OutputDataSchemaRow[] = []; + const block = blocks.blockNumber; + + let states = await getAccountStatesForAddressByPoolAtBlock( + block, + "", + "", + CHAINS.LINEA, + PROTOCOLS.LAYERBANK + ); + states = states.filter( + (s) => marketInfos.findIndex((mi) => mi.address == s.account) == -1 + ); + + console.log(`Block: ${block}`); + console.log("States: ", states.length); + + await updateBorrowBalances(states); + + states.forEach((state) => { + const amount = state.lentAmount - state.borrowAmount; + + if (bigMath.abs(amount) < 1) return; + + const marketInfo = marketInfos.find( + (mi) => mi.underlyingAddress == state.token.toLowerCase() + ); + + // Accumulate CSV row data + csvRows.push({ + block_number: blocks.blockNumber, + timestamp: blocks.blockTimestamp, + user_address: state.account, + token_address: state.token, + token_balance: amount, + token_symbol: marketInfo?.underlyingSymbol ?? "", + usd_price: 0, + }); + }); + + return csvRows; +}; + +const readBlocksFromCSV = async (filePath: string): Promise => { + const blocks: BlockData[] = []; + + await new Promise((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[] = []; // Array to accumulate CSV rows for all blocks + + for (const block of blocks) { + try { + const result = await getUserTVLByBlock(block); + for (let i = 0; i < result.length; i++) { + allCsvRows.push(result[i]); + } + } 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); + }); diff --git a/adapters/layerbank/src/sdk/abi/core.abi.ts b/adapters/layerbank/src/sdk/abi/core.abi.ts new file mode 100644 index 00000000..144fe2db --- /dev/null +++ b/adapters/layerbank/src/sdk/abi/core.abi.ts @@ -0,0 +1,812 @@ +export default [ + { inputs: [], stateMutability: "nonpayable", type: "constructor" }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "lToken", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "newBorrowCap", + type: "uint256", + }, + ], + name: "BorrowCapUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "newCloseFactor", + type: "uint256", + }, + ], + name: "CloseFactorUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "lToken", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "newCollateralFactor", + type: "uint256", + }, + ], + name: "CollateralFactorUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "target", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "initiator", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "asset", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "premium", + type: "uint256", + }, + ], + name: "FlashLoan", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "newKeeper", + type: "address", + }, + ], + name: "KeeperUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "newLABDistributor", + type: "address", + }, + ], + name: "LABDistributorUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "newLeverager", + type: "address", + }, + ], + name: "LeveragerUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint256", + name: "newLiquidationIncentive", + type: "uint256", + }, + ], + name: "LiquidationIncentiveUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "lToken", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "MarketEntered", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "lToken", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "MarketExited", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "lToken", + type: "address", + }, + ], + name: "MarketListed", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "user", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "lToken", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "uAmount", + type: "uint256", + }, + ], + name: "MarketRedeem", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "user", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "lToken", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "uAmount", + type: "uint256", + }, + ], + name: "MarketSupply", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "Paused", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "newRebateDistributor", + type: "address", + }, + ], + name: "RebateDistributorUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "lToken", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "newSupplyCap", + type: "uint256", + }, + ], + name: "SupplyCapUpdated", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "Unpaused", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "newValidator", + type: "address", + }, + ], + name: "ValidatorUpdated", + type: "event", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "accountLiquidityOf", + outputs: [ + { internalType: "uint256", name: "collateralInUSD", type: "uint256" }, + { internalType: "uint256", name: "supplyInUSD", type: "uint256" }, + { internalType: "uint256", name: "borrowInUSD", type: "uint256" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "allMarkets", + outputs: [{ internalType: "address[]", name: "", type: "address[]" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "lToken", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "borrow", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "borrower", type: "address" }, + { internalType: "address", name: "lToken", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "borrowBehalf", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "address", name: "lToken", type: "address" }, + ], + name: "checkMembership", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "claimLab", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "market", type: "address" }], + name: "claimLab", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "accounts", type: "address[]" }, + ], + name: "claimLabBehalf", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "closeFactor", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "lockDuration", type: "uint256" }, + ], + name: "compoundLab", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address[]", name: "lTokens", type: "address[]" }], + name: "enterMarkets", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "lToken", type: "address" }], + name: "exitMarket", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_priceCalculator", type: "address" }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "initialized", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "keeper", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "labDistributor", + outputs: [ + { internalType: "contract ILABDistributor", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "leverager", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "lTokenBorrowed", type: "address" }, + { internalType: "address", name: "lTokenCollateral", type: "address" }, + { internalType: "address", name: "borrower", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "liquidateBorrow", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "liquidationIncentive", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address payable", name: "lToken", type: "address" }, + { internalType: "uint256", name: "supplyCap", type: "uint256" }, + { internalType: "uint256", name: "borrowCap", type: "uint256" }, + { internalType: "uint256", name: "collateralFactor", type: "uint256" }, + ], + name: "listMarket", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "lToken", type: "address" }], + name: "marketInfoOf", + outputs: [ + { + components: [ + { internalType: "bool", name: "isListed", type: "bool" }, + { internalType: "uint256", name: "supplyCap", type: "uint256" }, + { internalType: "uint256", name: "borrowCap", type: "uint256" }, + { + internalType: "uint256", + name: "collateralFactor", + type: "uint256", + }, + ], + internalType: "struct Constant.MarketInfo", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "", type: "address" }], + name: "marketInfos", + outputs: [ + { internalType: "bool", name: "isListed", type: "bool" }, + { internalType: "uint256", name: "supplyCap", type: "uint256" }, + { internalType: "uint256", name: "borrowCap", type: "uint256" }, + { internalType: "uint256", name: "collateralFactor", type: "uint256" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "marketListOf", + outputs: [{ internalType: "address[]", name: "", type: "address[]" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "uint256", name: "", type: "uint256" }, + ], + name: "marketListOfUsers", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "uint256", name: "", type: "uint256" }], + name: "markets", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "pause", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "paused", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "priceCalculator", + outputs: [ + { internalType: "contract IPriceCalculator", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "rebateDistributor", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "lToken", type: "address" }, + { internalType: "uint256", name: "lAmount", type: "uint256" }, + ], + name: "redeemToken", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "lToken", type: "address" }, + { internalType: "uint256", name: "uAmount", type: "uint256" }, + ], + name: "redeemUnderlying", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address payable", name: "lToken", type: "address" }, + ], + name: "removeMarket", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "lToken", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "repayBorrow", + outputs: [], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "newCloseFactor", type: "uint256" }, + ], + name: "setCloseFactor", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "lToken", type: "address" }, + { internalType: "uint256", name: "newCollateralFactor", type: "uint256" }, + ], + name: "setCollateralFactor", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "_keeper", type: "address" }], + name: "setKeeper", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_labDistributor", type: "address" }, + ], + name: "setLABDistributor", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "_leverager", type: "address" }], + name: "setLeverager", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "newLiquidationIncentive", + type: "uint256", + }, + ], + name: "setLiquidationIncentive", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "lTokens", type: "address[]" }, + { internalType: "uint256[]", name: "newBorrowCaps", type: "uint256[]" }, + ], + name: "setMarketBorrowCaps", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address[]", name: "lTokens", type: "address[]" }, + { internalType: "uint256[]", name: "newSupplyCaps", type: "uint256[]" }, + ], + name: "setMarketSupplyCaps", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_priceCalculator", type: "address" }, + ], + name: "setPriceCalculator", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_rebateDistributor", type: "address" }, + ], + name: "setRebateDistributor", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "_validator", type: "address" }], + name: "setValidator", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "lToken", type: "address" }, + { internalType: "uint256", name: "uAmount", type: "uint256" }, + ], + name: "supply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "supplier", type: "address" }, + { internalType: "address", name: "lToken", type: "address" }, + { internalType: "uint256", name: "uAmount", type: "uint256" }, + ], + name: "supplyBehalf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "newOwner", type: "address" }], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "address", name: "src", type: "address" }, + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "transferTokens", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "unpause", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "", type: "address" }, + { internalType: "address", name: "", type: "address" }, + ], + name: "usersOfMarket", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "validator", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, +] as const; diff --git a/adapters/layerbank/src/sdk/abi/helpers.ts b/adapters/layerbank/src/sdk/abi/helpers.ts new file mode 100644 index 00000000..ab08dcc2 --- /dev/null +++ b/adapters/layerbank/src/sdk/abi/helpers.ts @@ -0,0 +1,20 @@ +export const bigMath = { + abs(x: bigint) { + return x < 0n ? -x : x; + }, + sign(x: bigint) { + if (x === 0n) return 0n; + return x < 0n ? -1n : 1n; + }, + pow(base: bigint, exponent: bigint) { + return base ** exponent; + }, + min(value: bigint, ...values: bigint[]) { + for (const v of values) if (v < value) value = v; + return value; + }, + max(value: bigint, ...values: bigint[]) { + for (const v of values) if (v > value) value = v; + return value; + }, +}; diff --git a/adapters/layerbank/src/sdk/abi/ltoken.abi.ts b/adapters/layerbank/src/sdk/abi/ltoken.abi.ts new file mode 100644 index 00000000..e1ddce61 --- /dev/null +++ b/adapters/layerbank/src/sdk/abi/ltoken.abi.ts @@ -0,0 +1,656 @@ +export default [ + { inputs: [], stateMutability: "nonpayable", type: "constructor" }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "ammount", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "accountBorrow", + type: "uint256", + }, + ], + name: "Borrow", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "liquidator", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "borrower", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "address", + name: "lTokenCollateral", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "seizeAmount", + type: "uint256", + }, + ], + name: "LiquidateBorrow", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "minter", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "mintAmount", + type: "uint256", + }, + ], + name: "Mint", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "underlyingAmount", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "lTokenAmount", + type: "uint256", + }, + ], + name: "Redeem", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "payer", + type: "address", + }, + { + indexed: false, + internalType: "address", + name: "borrower", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + { + indexed: false, + internalType: "uint256", + name: "accountBorrow", + type: "uint256", + }, + ], + name: "RepayBorrow", + type: "event", + }, + { + anonymous: false, + inputs: [ + { indexed: true, internalType: "address", name: "from", type: "address" }, + { indexed: true, internalType: "address", name: "to", type: "address" }, + { + indexed: false, + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + inputs: [], + name: "_totalBorrow", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "accInterestIndex", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "accountSnapshot", + outputs: [ + { + components: [ + { internalType: "uint256", name: "lTokenBalance", type: "uint256" }, + { internalType: "uint256", name: "borrowBalance", type: "uint256" }, + { internalType: "uint256", name: "exchangeRate", type: "uint256" }, + ], + internalType: "struct Constant.AccountSnapshot", + name: "", + type: "tuple", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "accruedAccountSnapshot", + outputs: [ + { + components: [ + { internalType: "uint256", name: "lTokenBalance", type: "uint256" }, + { internalType: "uint256", name: "borrowBalance", type: "uint256" }, + { internalType: "uint256", name: "exchangeRate", type: "uint256" }, + ], + internalType: "struct Constant.AccountSnapshot", + name: "", + type: "tuple", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "accruedBorrowBalanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "accruedExchangeRate", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "accruedTotalBorrow", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "address", name: "spender", type: "address" }, + ], + name: "allowance", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "approve", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "balanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "borrow", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "borrowBalanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "address", name: "borrower", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "borrowBehalf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "core", + outputs: [{ internalType: "contract ICore", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [{ internalType: "uint8", name: "", type: "uint8" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "exchangeRate", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getAccInterestIndex", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getCash", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getOwner", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getRateModel", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "string", name: "_name", type: "string" }, + { internalType: "string", name: "_symbol", type: "string" }, + { internalType: "uint8", name: "_decimals", type: "uint8" }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "initialized", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "lastAccruedTime", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "lTokenCollateral", type: "address" }, + { internalType: "address", name: "liquidator", type: "address" }, + { internalType: "address", name: "borrower", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "liquidateBorrow", + outputs: [ + { internalType: "uint256", name: "seizeLAmount", type: "uint256" }, + { internalType: "uint256", name: "rebateLAmount", type: "uint256" }, + { internalType: "uint256", name: "liquidatorLAmount", type: "uint256" }, + ], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "rateModel", + outputs: [ + { internalType: "contract IRateModel", name: "", type: "address" }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "rebateDistributor", + outputs: [ + { + internalType: "contract IRebateDistributor", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "redeemer", type: "address" }, + { internalType: "uint256", name: "lAmount", type: "uint256" }, + ], + name: "redeemToken", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "redeemer", type: "address" }, + { internalType: "uint256", name: "uAmount", type: "uint256" }, + ], + name: "redeemUnderlying", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "repayBorrow", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "reserveFactor", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "liquidator", type: "address" }, + { internalType: "address", name: "borrower", type: "address" }, + { internalType: "uint256", name: "lAmount", type: "uint256" }, + ], + name: "seize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "_core", type: "address" }], + name: "setCore", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "_rateModel", type: "address" }], + name: "setRateModel", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "_rebateDistributor", type: "address" }, + ], + name: "setRebateDistributor", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "uint256", name: "_reserveFactor", type: "uint256" }, + ], + name: "setReserveFactor", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "_underlying", type: "address" }], + name: "setUnderlying", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "uint256", name: "uAmount", type: "uint256" }, + ], + name: "supply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "account", type: "address" }, + { internalType: "address", name: "supplier", type: "address" }, + { internalType: "uint256", name: "uAmount", type: "uint256" }, + ], + name: "supplyBehalf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "payable", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [{ internalType: "string", name: "", type: "string" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalBorrow", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalReserve", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalSupply", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "transfer", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "src", type: "address" }, + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "transferFrom", + outputs: [{ internalType: "bool", name: "", type: "bool" }], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "newOwner", type: "address" }], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { internalType: "address", name: "spender", type: "address" }, + { internalType: "address", name: "src", type: "address" }, + { internalType: "address", name: "dst", type: "address" }, + { internalType: "uint256", name: "amount", type: "uint256" }, + ], + name: "transferTokensInternal", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "underlying", + outputs: [{ internalType: "address", name: "", type: "address" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [{ internalType: "address", name: "account", type: "address" }], + name: "underlyingBalanceOf", + outputs: [{ internalType: "uint256", name: "", type: "uint256" }], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "withdrawReserves", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { stateMutability: "payable", type: "receive" }, +] as const; diff --git a/adapters/layerbank/src/sdk/config.ts b/adapters/layerbank/src/sdk/config.ts new file mode 100644 index 00000000..dcec93dd --- /dev/null +++ b/adapters/layerbank/src/sdk/config.ts @@ -0,0 +1,19 @@ +export const enum CHAINS { + LINEA = 59144, +} + +export const enum PROTOCOLS { + LAYERBANK = 1, +} + +export const SUBGRAPH_URLS = { + [CHAINS.LINEA]: { + [PROTOCOLS.LAYERBANK]: { + url: "https://api.goldsky.com/api/public/project_clwadadu5rddf01xa3m0m8ep0/subgraphs/layerbank/1.0.0/gn", + }, + }, +}; + +export const RPC_URLS = { + [CHAINS.LINEA]: "https://rpc.linea.build", +}; diff --git a/adapters/layerbank/src/sdk/marketDetails.ts b/adapters/layerbank/src/sdk/marketDetails.ts new file mode 100644 index 00000000..f6f937ac --- /dev/null +++ b/adapters/layerbank/src/sdk/marketDetails.ts @@ -0,0 +1,163 @@ +import { createPublicClient, extractChain, http, getContract } from "viem"; +import { CHAINS, RPC_URLS } from "./config"; +import { linea } from "viem/chains"; +import coreAbi from "./abi/core.abi"; +import ltokenAbi from "./abi/ltoken.abi"; +import { AccountState } from "./subgraphDetails"; + +export interface MarketInfo { + address: string; + underlyingAddress: string; + underlyingSymbol: string; + exchangeRateStored: bigint; +} +export const getMarketInfos = async ( + coreAddress: `0x${string}`, + blockNumber?: bigint +) => { + const publicClient = createPublicClient({ + chain: extractChain({ chains: [linea], id: CHAINS.LINEA }), + transport: http(RPC_URLS[CHAINS.LINEA]), + }); + + const core = getContract({ + address: coreAddress, + abi: coreAbi, + client: publicClient, + }); + + const marketAddresses = await core.read.allMarkets(); + const markets = marketAddresses.map((m) => + getContract({ + address: m, + abi: ltokenAbi, + client: publicClient, + }) + ); + + const underlyingResults = await publicClient.multicall({ + contracts: markets.map((m) => ({ + address: m.address, + abi: m.abi, + functionName: "underlying", + })) as any, + }); + + const underlyingAddresses = underlyingResults.map( + (v) => v.result as `0x${string}` + ); + + const underlyings = underlyingAddresses.map((m) => { + if (m === "0x0000000000000000000000000000000000000000") { + return null; + } else { + return getContract({ + address: m, + abi: ltokenAbi, + client: publicClient, + }); + } + }); + + const underlyingSymbolResults = await publicClient.multicall({ + contracts: underlyings + .filter((m) => m !== null) + .map((m) => ({ + address: (m as any).address, + abi: (m as any).abi, + functionName: "symbol", + })) as any, + }); + + const exchangeRateResults = await publicClient.multicall({ + contracts: markets.map((m) => ({ + address: m.address, + abi: m.abi, + functionName: "exchangeRate", + })) as any, + blockNumber, + }); + + const marketInfos: MarketInfo[] = []; + let symbolIndex = 0; + + for (let i = 0; i < markets.length; i++) { + const marketAddress = markets[i].address.toLowerCase(); + const underlyingAddress = underlyingResults[i].result?.toLowerCase(); + + if (underlyingAddress === "0x0000000000000000000000000000000000000000") { + marketInfos.push({ + address: marketAddress, + underlyingAddress, + underlyingSymbol: "ETH", + exchangeRateStored: BigInt( + exchangeRateResults[i].status === "success" + ? (exchangeRateResults[i].result as any) + : 0 + ), + }); + } else { + marketInfos.push({ + address: marketAddress, + underlyingAddress, + underlyingSymbol: underlyingSymbolResults[symbolIndex].result as any, + exchangeRateStored: BigInt( + exchangeRateResults[i].status === "success" + ? (exchangeRateResults[i].result as any) + : 0 + ), + }); + symbolIndex++; + } + } + + return marketInfos; +}; + +export const updateBorrowBalances = async ( + states: AccountState[], + blockNumber?: bigint +) => { + const marketInfos = await getMarketInfos( + "0x43Eac5BFEa14531B8DE0B334E123eA98325de866" + ); + const marketsByUnderlying: any = {}; + for (let marketInfo of marketInfos) { + marketsByUnderlying[marketInfo.underlyingAddress] = marketInfo.address; + } + + const publicClient = createPublicClient({ + chain: extractChain({ chains: [linea], id: CHAINS.LINEA }), + transport: http(RPC_URLS[CHAINS.LINEA]), + }); + + states = states.filter((x) => x.borrowAmount > 0); + + console.log(`Will update all borrow balances for ${states.length} states`); + for (var i = 0; i < states.length; i += 500) { + const start = i; + const end = i + 500; + var subStates = states.slice(start, end); + console.log(`Updating borrow balances for ${start} - ${end}`); + + const borrowBalanceResults = await publicClient.multicall({ + contracts: subStates + .map((m) => [ + { + address: marketsByUnderlying[m.token], + abi: ltokenAbi, + functionName: "borrowBalanceOf", + args: [m.account], + }, + ]) + .flat() as any, + blockNumber, + }); + + for (var j = 0; j < subStates.length; j++) { + subStates[j].borrowAmount = BigInt( + borrowBalanceResults[j].result?.toString() ?? 0 + ); + } + } +}; diff --git a/adapters/layerbank/src/sdk/subgraphDetails.ts b/adapters/layerbank/src/sdk/subgraphDetails.ts new file mode 100644 index 00000000..34de541a --- /dev/null +++ b/adapters/layerbank/src/sdk/subgraphDetails.ts @@ -0,0 +1,126 @@ +import { Account, createPublicClient, extractChain, http } from "viem"; +import { linea } from "viem/chains"; +import { CHAINS, PROTOCOLS, RPC_URLS, SUBGRAPH_URLS } from "./config"; +import { getMarketInfos } from "./marketDetails"; + +export interface AccountState { + id: string; + account: string; + token: string; + lentAmount: bigint; + borrowAmount: bigint; +} + +export const getAccountStatesForAddressByPoolAtBlock = async ( + blockNumber: number, + address: string, + poolId: string, + chainId: CHAINS, + protocol: PROTOCOLS +): Promise => { + const marketInfos = await getMarketInfos( + "0x43Eac5BFEa14531B8DE0B334E123eA98325de866", + BigInt(blockNumber) + ); + address = address?.toLowerCase(); + + let accountWhereQuery = address ? `account: "${address}" \n` : ""; + let amountWhereQuery = orWhere("supplied_gt: 0", "borrowed_gt: 0"); + + let skip = 0; + let fetchNext = true; + + const pageSize = 1000; + const url = SUBGRAPH_URLS[chainId][protocol].url; + + let states: AccountState[] = []; + + while (fetchNext) { + let query = ` + query TVLQuery { + accountStates( + block: {number: ${blockNumber}} + where: { + ${andWhere(accountWhereQuery, amountWhereQuery)} + } + orderBy: id + first: ${pageSize} + skip: ${skip} + ) { + id + account + token + supplied + borrowed + } + } + `; + console.log(`Fetching ${skip} - ${skip + pageSize} / unknown`); + + let response = await fetch(url, { + method: "POST", + body: JSON.stringify({ query }), + headers: { "Content-Type": "application/json" }, + }); + let data = await response.json(); + + states.push( + ...data.data.accountStates.map((m: any) => ({ + id: m.id, + account: m.account, + token: m.token, + lentAmount: BigInt(m.supplied), + borrowAmount: BigInt(m.borrowed), + })) + ); + + if (data.data.accountStates.length == 0) { + fetchNext = false; + } else { + skip += pageSize; + } + } + + states = states + .map((state: AccountState) => { + const marketInfo = marketInfos.find( + (mi) => mi.underlyingAddress == state.token.toLowerCase() + ); + if (!marketInfo) { + console.log(`${state.token} not found`); + return undefined; + } + + return { + ...state, + lentAmount: + (state.lentAmount * marketInfo.exchangeRateStored) / BigInt(1e18), + }; + }) + .filter((x) => x !== undefined) as AccountState[]; + + return states; +}; + +export const getTimestampAtBlock = async (blockNumber: number) => { + const publicClient = createPublicClient({ + chain: extractChain({ chains: [linea], id: CHAINS.LINEA }), + transport: http(RPC_URLS[CHAINS.LINEA]), + }); + + const block = await publicClient.getBlock({ + blockNumber: BigInt(blockNumber), + }); + return Number(block.timestamp * 1000n); +}; + +const andWhere = (...queries: string[]) => { + return `and: [ + ${queries.map((q) => `{ ${q} }`).join("\n")} + ]`; +}; +const orWhere = (...queries: string[]) => { + return `or: [ + ${queries.map((q) => `{ ${q} }`).join("\n")} +]`; +}; From ac4d8e1d67c2310875138f156203b884186aa5e1 Mon Sep 17 00:00:00 2001 From: marsclimber0109 Date: Tue, 21 May 2024 22:28:43 +0900 Subject: [PATCH 3/5] fix: update eth address from zero to weth --- adapters/layerbank/src/sdk/marketDetails.ts | 53 ++++++++------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/adapters/layerbank/src/sdk/marketDetails.ts b/adapters/layerbank/src/sdk/marketDetails.ts index f6f937ac..a1cdf8de 100644 --- a/adapters/layerbank/src/sdk/marketDetails.ts +++ b/adapters/layerbank/src/sdk/marketDetails.ts @@ -49,7 +49,11 @@ export const getMarketInfos = async ( const underlyings = underlyingAddresses.map((m) => { if (m === "0x0000000000000000000000000000000000000000") { - return null; + return getContract({ + address: "0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f", + abi: ltokenAbi, + client: publicClient, + }); } else { return getContract({ address: m, @@ -60,13 +64,11 @@ export const getMarketInfos = async ( }); const underlyingSymbolResults = await publicClient.multicall({ - contracts: underlyings - .filter((m) => m !== null) - .map((m) => ({ - address: (m as any).address, - abi: (m as any).abi, - functionName: "symbol", - })) as any, + contracts: underlyings.map((m) => ({ + address: (m as any).address, + abi: (m as any).abi, + functionName: "symbol", + })) as any, }); const exchangeRateResults = await publicClient.multicall({ @@ -79,36 +81,21 @@ export const getMarketInfos = async ( }); const marketInfos: MarketInfo[] = []; - let symbolIndex = 0; for (let i = 0; i < markets.length; i++) { const marketAddress = markets[i].address.toLowerCase(); const underlyingAddress = underlyingResults[i].result?.toLowerCase(); - if (underlyingAddress === "0x0000000000000000000000000000000000000000") { - marketInfos.push({ - address: marketAddress, - underlyingAddress, - underlyingSymbol: "ETH", - exchangeRateStored: BigInt( - exchangeRateResults[i].status === "success" - ? (exchangeRateResults[i].result as any) - : 0 - ), - }); - } else { - marketInfos.push({ - address: marketAddress, - underlyingAddress, - underlyingSymbol: underlyingSymbolResults[symbolIndex].result as any, - exchangeRateStored: BigInt( - exchangeRateResults[i].status === "success" - ? (exchangeRateResults[i].result as any) - : 0 - ), - }); - symbolIndex++; - } + marketInfos.push({ + address: marketAddress, + underlyingAddress, + underlyingSymbol: underlyingSymbolResults[i].result as any, + exchangeRateStored: BigInt( + exchangeRateResults[i].status === "success" + ? (exchangeRateResults[i].result as any) + : 0 + ), + }); } return marketInfos; From 287a5fd7e7b3a3fff49b11f8370814da2af8037e Mon Sep 17 00:00:00 2001 From: marsclimber0109 Date: Tue, 21 May 2024 22:29:09 +0900 Subject: [PATCH 4/5] chore: filter zero and burn address for account states --- adapters/layerbank/src/sdk/subgraphDetails.ts | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/adapters/layerbank/src/sdk/subgraphDetails.ts b/adapters/layerbank/src/sdk/subgraphDetails.ts index 34de541a..037ab80c 100644 --- a/adapters/layerbank/src/sdk/subgraphDetails.ts +++ b/adapters/layerbank/src/sdk/subgraphDetails.ts @@ -3,6 +3,10 @@ import { linea } from "viem/chains"; import { CHAINS, PROTOCOLS, RPC_URLS, SUBGRAPH_URLS } from "./config"; import { getMarketInfos } from "./marketDetails"; +// Define the zero address and dead address constants +const zeroAddress = "0x0000000000000000000000000000000000000000"; +const deadAddress = "0x000000000000000000000000000000000000dead"; + export interface AccountState { id: string; account: string; @@ -24,6 +28,11 @@ export const getAccountStatesForAddressByPoolAtBlock = async ( ); address = address?.toLowerCase(); + const marketsToUnderlying: any = {}; + for (let marketInfo of marketInfos) { + marketsToUnderlying[marketInfo.address] = marketInfo.underlyingAddress; + } + let accountWhereQuery = address ? `account: "${address}" \n` : ""; let amountWhereQuery = orWhere("supplied_gt: 0", "borrowed_gt: 0"); @@ -64,15 +73,21 @@ export const getAccountStatesForAddressByPoolAtBlock = async ( }); let data = await response.json(); - states.push( - ...data.data.accountStates.map((m: any) => ({ + // Filter and map the account states + const filteredAccountStates = data.data.accountStates + .filter( + (m: any) => m.account !== zeroAddress && m.account !== deadAddress + ) + .map((m: any) => ({ id: m.id, account: m.account, - token: m.token, + token: marketsToUnderlying[m.token], lentAmount: BigInt(m.supplied), borrowAmount: BigInt(m.borrowed), - })) - ); + })); + + // Push the filtered and mapped states into the states array + states.push(...filteredAccountStates); if (data.data.accountStates.length == 0) { fetchNext = false; From 36eaa5d115f1ff8ef335503bfd61eae2cd97a778 Mon Sep 17 00:00:00 2001 From: marsclimber0109 Date: Tue, 21 May 2024 22:49:21 +0900 Subject: [PATCH 5/5] chore: lowercase for token addrs --- adapters/layerbank/src/sdk/marketDetails.ts | 7 ++++--- adapters/layerbank/src/sdk/subgraphDetails.ts | 9 +++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/adapters/layerbank/src/sdk/marketDetails.ts b/adapters/layerbank/src/sdk/marketDetails.ts index a1cdf8de..fe7aa794 100644 --- a/adapters/layerbank/src/sdk/marketDetails.ts +++ b/adapters/layerbank/src/sdk/marketDetails.ts @@ -11,6 +11,7 @@ export interface MarketInfo { underlyingSymbol: string; exchangeRateStored: bigint; } + export const getMarketInfos = async ( coreAddress: `0x${string}`, blockNumber?: bigint @@ -43,9 +44,9 @@ export const getMarketInfos = async ( })) as any, }); - const underlyingAddresses = underlyingResults.map( - (v) => v.result as `0x${string}` - ); + const underlyingAddresses = underlyingResults + .map((v) => v.result as `0x${string}`) + .map((m) => m.toLowerCase()); const underlyings = underlyingAddresses.map((m) => { if (m === "0x0000000000000000000000000000000000000000") { diff --git a/adapters/layerbank/src/sdk/subgraphDetails.ts b/adapters/layerbank/src/sdk/subgraphDetails.ts index 037ab80c..ae53028b 100644 --- a/adapters/layerbank/src/sdk/subgraphDetails.ts +++ b/adapters/layerbank/src/sdk/subgraphDetails.ts @@ -76,12 +76,13 @@ export const getAccountStatesForAddressByPoolAtBlock = async ( // Filter and map the account states const filteredAccountStates = data.data.accountStates .filter( - (m: any) => m.account !== zeroAddress && m.account !== deadAddress + (m: any) => + m.account !== zeroAddress && m.account.toLowerCase() !== deadAddress ) .map((m: any) => ({ - id: m.id, - account: m.account, - token: marketsToUnderlying[m.token], + id: m.id.toLowerCase(), + account: m.account.toLowerCase(), + token: marketsToUnderlying[m.token].toLowerCase(), lentAmount: BigInt(m.supplied), borrowAmount: BigInt(m.borrowed), }));