From 39b9602d3685d3dd5e3931db4f7dfd7de3970b43 Mon Sep 17 00:00:00 2001 From: Rustem Kurmaev Date: Fri, 11 Aug 2023 19:21:45 +0300 Subject: [PATCH] feat: add basenet reports (#40) * feat: add basenet reports * basenet -> base --- .env.example | 1 + src/reports/reserve.ts | 108 +++++++++++++++++----------------- src/reports/snapshot-types.ts | 3 +- src/utils/rpcClients.ts | 7 ++- yarn.lock | 52 +++++++++++----- 5 files changed, 100 insertions(+), 71 deletions(-) diff --git a/.env.example b/.env.example index 42c1b27..fce36c4 100644 --- a/.env.example +++ b/.env.example @@ -5,6 +5,7 @@ RPC_MAINNET= RPC_ARBITRUM= RPC_POLYGON= RPC_OPTIMISM= +RPC_BASE= TENDERLY_ACCESS_TOKEN= TENDERLY_PROJECT_SLUG= diff --git a/src/reports/reserve.ts b/src/reports/reserve.ts index 719a1e5..0b7f032 100644 --- a/src/reports/reserve.ts +++ b/src/reports/reserve.ts @@ -1,5 +1,5 @@ -import { formatUnits } from "viem"; -import { AaveV3Reserve, CHAIN_ID } from "./snapshot-types"; +import { formatUnits } from 'viem'; +import { AaveV3Reserve, CHAIN_ID } from './snapshot-types'; export const getBlockExplorerLink: { [key in CHAIN_ID]: (address: string) => string; @@ -18,6 +18,8 @@ export const getBlockExplorerLink: { `[${address}](https://snowtrace.io/address/${address})`, [CHAIN_ID.METIS]: (address) => `[${address}](https://andromeda-explorer.metis.io/address/${address})`, + [CHAIN_ID.BASE]: (address) => + `[${address}](https://basescan.org/address/${address})`, }; export function renderReserveValue( @@ -27,30 +29,30 @@ export function renderReserveValue( ) { if ( [ - "reserveFactor", - "liquidationProtocolFee", - "liquidationThreshold", - "ltv", + 'reserveFactor', + 'liquidationProtocolFee', + 'liquidationThreshold', + 'ltv', ].includes(key) ) return `${formatUnits(BigInt(reserve[key]), 2)} %`; - if (["supplyCap", "borrowCap"].includes(key)) - return `${reserve[key].toLocaleString("en-US")} ${reserve.symbol}`; - if (key === "debtCeiling") + if (['supplyCap', 'borrowCap'].includes(key)) + return `${reserve[key].toLocaleString('en-US')} ${reserve.symbol}`; + if (key === 'debtCeiling') return `${Number(formatUnits(BigInt(reserve[key]), 2)).toLocaleString( - "en-US" + 'en-US' )} $`; - if (key === "liquidationBonus") + if (key === 'liquidationBonus') return reserve[key] === 0 - ? "0 %" + ? '0 %' : `${((reserve[key] as number) - 10000) / 100} %`; - if (key === "interestRateStrategy") + if (key === 'interestRateStrategy') return getBlockExplorerLink[chainId](reserve[key] as string); - if (key === "oracleLatestAnswer" && reserve.oracleDecimals) + if (key === 'oracleLatestAnswer' && reserve.oracleDecimals) return formatUnits(BigInt(reserve[key]), reserve.oracleDecimals); - if (typeof reserve[key] === "number") - return reserve[key].toLocaleString("en-US"); - if (typeof reserve[key] === "string" && /0x.+/.test(reserve[key] as string)) + if (typeof reserve[key] === 'number') + return reserve[key].toLocaleString('en-US'); + if (typeof reserve[key] === 'string' && /0x.+/.test(reserve[key] as string)) return getBlockExplorerLink[chainId](reserve[key] as string); return reserve[key]; } @@ -62,37 +64,37 @@ function renderReserveHeadline(reserve: AaveV3Reserve, chainId: CHAIN_ID) { } const ORDER: (keyof AaveV3Reserve)[] = [ - "symbol", - "decimals", - "isActive", - "isFrozen", - "supplyCap", - "borrowCap", - "debtCeiling", - "isSiloed", - "isFlashloanable", - "eModeCategory", - "oracle", - "oracleDecimals", - "oracleDescription", - "oracleName", - "oracleLatestAnswer", - "usageAsCollateralEnabled", - "ltv", - "liquidationThreshold", - "liquidationBonus", - "liquidationProtocolFee", - "reserveFactor", - "aToken", - "aTokenImpl", - "variableDebtToken", - "variableDebtTokenImpl", - "stableDebtToken", - "stableDebtTokenImpl", - "borrowingEnabled", - "stableBorrowRateEnabled", - "isBorrowableInIsolation", - "interestRateStrategy", + 'symbol', + 'decimals', + 'isActive', + 'isFrozen', + 'supplyCap', + 'borrowCap', + 'debtCeiling', + 'isSiloed', + 'isFlashloanable', + 'eModeCategory', + 'oracle', + 'oracleDecimals', + 'oracleDescription', + 'oracleName', + 'oracleLatestAnswer', + 'usageAsCollateralEnabled', + 'ltv', + 'liquidationThreshold', + 'liquidationBonus', + 'liquidationProtocolFee', + 'reserveFactor', + 'aToken', + 'aTokenImpl', + 'variableDebtToken', + 'variableDebtTokenImpl', + 'stableDebtToken', + 'stableDebtTokenImpl', + 'borrowingEnabled', + 'stableBorrowRateEnabled', + 'isBorrowableInIsolation', + 'interestRateStrategy', ]; function sortReserveKeys(a: keyof AaveV3Reserve, b: keyof AaveV3Reserve) { const indexA = ORDER.indexOf(a); @@ -103,10 +105,10 @@ function sortReserveKeys(a: keyof AaveV3Reserve, b: keyof AaveV3Reserve) { } function renderReserveConfig(reserve: AaveV3Reserve, chainId: CHAIN_ID) { - let content = "| description | value |\n| --- | --- |\n"; + let content = '| description | value |\n| --- | --- |\n'; const OMIT_KEYS: (keyof AaveV3Reserve)[] = [ - "underlying", // already rendered in the header - "symbol", // already rendered in the header + 'underlying', // already rendered in the header + 'symbol', // already rendered in the header ]; (Object.keys(reserve) as (keyof AaveV3Reserve)[]) .filter((key) => !OMIT_KEYS.includes(key)) @@ -130,9 +132,9 @@ export type ReserveDiff = { export function renderReserveDiff(diff: ReserveDiff, chainId: CHAIN_ID) { let content = renderReserveHeadline(diff as AaveV3Reserve, chainId); content += - "| description | value before | value after |\n| --- | --- | --- |\n"; + '| description | value before | value after |\n| --- | --- | --- |\n'; (Object.keys(diff) as (keyof AaveV3Reserve)[]) - .filter((key) => diff[key].hasOwnProperty("from")) + .filter((key) => diff[key].hasOwnProperty('from')) .sort(sortReserveKeys) .map((key) => { content += `| ${key} | ${renderReserveValue( diff --git a/src/reports/snapshot-types.ts b/src/reports/snapshot-types.ts index 934a423..d02eaa8 100644 --- a/src/reports/snapshot-types.ts +++ b/src/reports/snapshot-types.ts @@ -1,4 +1,4 @@ -import { z } from "zod"; +import { z } from 'zod'; export const aaveV3ConfigSchema = z.object({ oracle: z.string(), @@ -84,6 +84,7 @@ export const CHAIN_ID = { ARBITRUM: 42161, AVALANCHE: 43114, METIS: 1088, + BASE: 8453, } as const; const zodChainId = z.nativeEnum(CHAIN_ID); diff --git a/src/utils/rpcClients.ts b/src/utils/rpcClients.ts index 9814880..f44c494 100644 --- a/src/utils/rpcClients.ts +++ b/src/utils/rpcClients.ts @@ -1,6 +1,6 @@ // import 'dotenv/config'; import { createPublicClient, http, fallback } from 'viem'; -import { mainnet, arbitrum, polygon, optimism, metis } from 'viem/chains'; +import { mainnet, arbitrum, polygon, optimism, metis, base } from 'viem/chains'; export const mainnetClient = createPublicClient({ chain: mainnet, @@ -26,3 +26,8 @@ export const metisClient = createPublicClient({ chain: metis, transport: http(process.env.RPC_METIS), }); + +export const baseClient = createPublicClient({ + chain: base, + transport: http(process.env.RPC_BASE), +}); diff --git a/yarn.lock b/yarn.lock index 49ce00e..0aa2216 100644 --- a/yarn.lock +++ b/yarn.lock @@ -158,18 +158,30 @@ resolved "https://registry.yarnpkg.com/@multiformats/base-x/-/base-x-4.0.1.tgz#95ff0fa58711789d53aefb2590a8b7a4e715d121" integrity sha512-eMk0b9ReBbV23xXU693TAIrLyeO5iTgBZGSJfpqriG8UkYvr/hC9u9pyMlAakDNHWmbhMZCDs6KQO0jzKD8OTw== -"@noble/curves@1.0.0", "@noble/curves@~1.0.0": +"@noble/curves@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d" + integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA== + dependencies: + "@noble/hashes" "1.3.1" + +"@noble/curves@~1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.0.0.tgz#e40be8c7daf088aaf291887cbc73f43464a92932" integrity sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw== dependencies: "@noble/hashes" "1.3.0" -"@noble/hashes@1.3.0", "@noble/hashes@~1.3.0": +"@noble/hashes@1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.0.tgz#085fd70f6d7d9d109671090ccae1d3bec62554a1" integrity sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg== +"@noble/hashes@1.3.1", "@noble/hashes@~1.3.0": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" + integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -316,6 +328,13 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== +"@types/ws@^8.5.4": + version "8.5.5" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" + integrity sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg== + dependencies: + "@types/node" "*" + "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" @@ -372,15 +391,15 @@ loupe "^2.3.6" pretty-format "^27.5.1" -"@wagmi/chains@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@wagmi/chains/-/chains-1.1.0.tgz#d351b3dc6f472b167f180721f46f6098b6c1585b" - integrity sha512-pWZlxBk0Ql8E7DV8DwqlbBpOyUdaG9UDlQPBxJNALuEK1I0tbQ3AVvSDnlsEIt06UPmPo5o27gzs3hwPQ/A+UA== +"@wagmi/chains@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@wagmi/chains/-/chains-1.6.0.tgz#eb992ad28dbaaab729b5bcab3e5b461e8a035656" + integrity sha512-5FRlVxse5P4ZaHG3GTvxwVANSmYJas1eQrTBHhjxVtqXoorm0aLmCHbhmN8Xo1yu09PaWKlleEvfE98yH4AgIw== -abitype@0.8.7: - version "0.8.7" - resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.8.7.tgz#e4b3f051febd08111f486c0cc6a98fa72d033622" - integrity sha512-wQ7hV8Yg/yKmGyFpqrNZufCxbszDe5es4AZGYPBitocfSqXtjrTG9JMWFcc4N30ukl2ve48aBTwt7NJxVQdU3w== +abitype@0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-0.9.3.tgz#294d25288ee683d72baf4e1fed757034e3c8c277" + integrity sha512-dz4qCQLurx97FQhnb/EIYTk/ldQ+oafEDUqC0VVIeQS1Q48/YWt/9YNfMmp9SLFqN41ktxny3c8aYxHjmFIB/w== acorn-walk@^8.2.0: version "8.2.0" @@ -2150,17 +2169,18 @@ varint@^6.0.0: integrity sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg== viem@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/viem/-/viem-1.0.7.tgz#522a01c1e1402de953f1d55e4cbefcc772891517" - integrity sha512-P/T2Zn8+V74kxO2e2NdhNR/MBtldovssigvc36+7g3DgTeETKnSS1fMQdBl0jE+Atlal+M6cuJ2HcFY7U45o0Q== + version "1.6.0" + resolved "https://registry.yarnpkg.com/viem/-/viem-1.6.0.tgz#8befa678c3ac79b9558dfd1708130b2ecb1994f4" + integrity sha512-ae9Twkd0q2Qlj4yYpWjb4DzYAhKY0ibEpRH8FJaTywZXNpTjFidSdBaT0CVn1BaH7O7cnX4/O47zvDUMGJD1AA== dependencies: "@adraffy/ens-normalize" "1.9.0" - "@noble/curves" "1.0.0" + "@noble/curves" "1.1.0" "@noble/hashes" "1.3.0" "@scure/bip32" "1.3.0" "@scure/bip39" "1.2.0" - "@wagmi/chains" "1.1.0" - abitype "0.8.7" + "@types/ws" "^8.5.4" + "@wagmi/chains" "1.6.0" + abitype "0.9.3" isomorphic-ws "5.0.0" ws "8.12.0"