From 5ce627419cdd0756be4ab4ceb3c844902e3e18cb Mon Sep 17 00:00:00 2001 From: Aaron Ho <616127+cincauhangus@users.noreply.github.com> Date: Tue, 29 Oct 2024 00:04:08 +0800 Subject: [PATCH 1/3] fix: added all superfluid supported chains, using own subgraphs --- projects/superfluid.js | 159 +++++++++++++++++++++++++++-------------- 1 file changed, 106 insertions(+), 53 deletions(-) diff --git a/projects/superfluid.js b/projects/superfluid.js index 95f64ca96e55..b4d7b7c4021a 100644 --- a/projects/superfluid.js +++ b/projects/superfluid.js @@ -1,13 +1,8 @@ const sdk = require("@defillama/sdk"); -const { request, } = require("graphql-request"); // GraphQLClient -const { isStableToken } = require('./helper/streamingHelper') -const { getBlock } = require('./helper/http') -const { transformBalances } = require('./helper/portedTokens') - -// Superfluid Supertokens can be retrieved using GraphQl API - cannot use block number to retrieve historical data at the moment though -// TheGraph URL before being deprecated, before 2021-12-23 -// const polygonGraphUrl = sdk.graph.modifyEndpoint('BoiJR4mfVpVthWjTcansrCUFCjKY9MfDxgTfzkf4YpAN') -// const xdaiGraphUrl = sdk.graph.modifyEndpoint('A3LhWnFQR13mxQPFGUZML9vyBrLLKhLJBhfFsrdShxBU') +const { isStableToken } = require("./helper/streamingHelper"); +const { getBlock } = require("./helper/http"); +const { transformBalances } = require("./helper/portedTokens"); +const { blockQuery } = require("./helper/http"); const supertokensQuery = ` query get_supertokens($block: Int) { @@ -35,31 +30,36 @@ query get_supertokens($block: Int) { } } `; -// An upcoming superfluid graphql subgraph will be published soon and provide token supplies. function isWhitelistedToken(token, address, isVesting) { - const isStable = isStableToken(token?.symbol, address) && !tokensNativeToSidechain.includes(address.toLowerCase()) - return isVesting ? !isStable : isStable + const isStable = + isStableToken(token?.symbol, address) && + !tokensNativeToSidechain.includes(address.toLowerCase()); + return isVesting ? !isStable : isStable; } -const blacklist = new Set(['0x441bb79f2da0daf457bad3d401edb68535fb3faa'].map(i => i.toLowerCase())) +const blacklist = new Set( + ["0x441bb79f2da0daf457bad3d401edb68535fb3faa"].map((i) => i.toLowerCase()) +); // Main function for all chains to get balances of superfluid tokens async function getChainBalances(allTokens, chain, block, isVesting) { // Init empty balances let balances = {}; - allTokens = allTokens.filter(({ underlyingAddress, underlyingToken = {}, }) => isWhitelistedToken(underlyingToken, underlyingAddress, isVesting)) + allTokens = allTokens.filter(({ underlyingAddress, underlyingToken = {} }) => + isWhitelistedToken(underlyingToken, underlyingAddress, isVesting) + ); // Abi MultiCall to get supertokens supplies const { output: supply } = await sdk.api.abi.multiCall({ - abi: 'erc20:totalSupply', // abi['totalSupply'], - calls: allTokens.map(token => ({ + abi: "erc20:totalSupply", // abi['totalSupply'], + calls: allTokens.map((token) => ({ target: token.id, - }) - ), - block, chain - }) + })), + block, + chain, + }); supply.forEach(({ output: totalSupply }, i) => { const { @@ -70,54 +70,107 @@ async function getChainBalances(allTokens, chain, block, isVesting) { name, symbol, isNativeAssetSuperToken, - } = allTokens[i] - let underlyingTokenBalance = totalSupply * (10 ** (underlyingToken || { decimals: 18 }).decimals) / (10 ** decimals) + } = allTokens[i]; + let underlyingTokenBalance = + (totalSupply * 10 ** (underlyingToken || { decimals: 18 }).decimals) / + 10 ** decimals; // Accumulate to balances, the balance for tokens on mainnet or sidechain - let prefixedUnderlyingAddress = underlyingAddress + let prefixedUnderlyingAddress = underlyingAddress; // if (!underlyingToken && underlyingTokenBalance/1e24 > 1) sdk.log(name, symbol, chain, Math.floor(underlyingTokenBalance/1e24)) // if (isNativeAssetSuperToken) prefixedUnderlyingAddress = chain + ':' + underlyingAddress - if (!underlyingToken || blacklist.has(underlyingAddress.toLowerCase())) return; - sdk.util.sumSingleBalance(balances, prefixedUnderlyingAddress, underlyingTokenBalance) - }) + if (!underlyingToken || blacklist.has(underlyingAddress.toLowerCase())) + return; + sdk.util.sumSingleBalance( + balances, + prefixedUnderlyingAddress, + underlyingTokenBalance + ); + }); - return transformBalances(chain, balances) + return transformBalances(chain, balances); } const tokensNativeToSidechain = [ - '0x2bf2ba13735160624a0feae98f6ac8f70885ea61', // xdai FRACTION - '0x63e62989d9eb2d37dfdb1f93a22f063635b07d51', // xdai MIVA - '0x263026e7e53dbfdce5ae55ade22493f828922965', // polygon RIC -] + "0x2bf2ba13735160624a0feae98f6ac8f70885ea61", // xdai FRACTION + "0x63e62989d9eb2d37dfdb1f93a22f063635b07d51", // xdai MIVA + "0x263026e7e53dbfdce5ae55ade22493f828922965", // polygon RIC +]; + +async function retrieveSupertokensBalances( + chain, + block, + isVesting, + ts, + graphUrl +) { + const blockNum = await getBlock(ts, chain, { [chain]: block }); + const gblock = blockNum - 5000; + + console.log(chain, blockNum, gblock); -async function retrieveSupertokensBalances(chain, block, isVesting, ts, graphUrl) { - const gblock = (await getBlock(ts, chain, { [chain]: block })) - 5000 // Retrieve supertokens from graphql API - const { tokens } = await request(graphUrl, supertokensQuery, { block: gblock }) - const allTokens = tokens.filter(t => t.isSuperToken) + const { tokens } = await blockQuery(graphUrl, supertokensQuery, { + api: { + getBlock: () => gblock, + block: gblock, + }, + }); + const allTokens = tokens.filter((t) => t.isSuperToken); - return getChainBalances(allTokens, chain, block, isVesting) + return getChainBalances(allTokens, chain, block, isVesting); } -const config = { - avax: { graph: sdk.graph.modifyEndpoint('CtYR3ng4ED64HVEzDo49eKQgEf78RERiC8mDUtwLxda'), }, - polygon: { graph: sdk.graph.modifyEndpoint('7d9iBvDoM43SZiZhRR2pnpW8z3ujSEy9nC6RuqnufRU9'), }, - xdai: { graph: sdk.graph.modifyEndpoint('DE6fybqxjXLNvqGpd4QLAD92kAZNEmha1ZfKvS2qM376'), }, - optimism: { graph: sdk.graph.modifyEndpoint('S48f1C3KhNB2YbEMDxYHPzZ3FYt27fQZdruKfSTeEdZ'), }, - arbitrum: { graph: sdk.graph.modifyEndpoint('ES5GNHtiaqP6jFydhUyD9R4RackYrbGr6LEL1ZDauktd'), }, - bsc: { graph: sdk.graph.modifyEndpoint('FzYUiDH968QKbjURULGE5Pwh1ZRvcBNjDcut5YSiMYnj'), }, -} +/** + * List of subgraphs can be retrieved from https://docs.superfluid.finance/docs/technical-reference/subgraph + */ +const subgraphEndpoints = { + arbitrum: { + graph: "https://subgraph-endpoints.superfluid.dev/arbitrum-one/protocol-v1", + }, + avax: { + graph: "https://subgraph-endpoints.superfluid.dev/avalanche-c/protocol-v1", + }, + base: { + graph: "https://subgraph-endpoints.superfluid.dev/base-mainnet/protocol-v1", + }, + bsc: { + graph: "https://subgraph-endpoints.superfluid.dev/bsc-mainnet/protocol-v1", + }, + // degen: { + // graph: + // "https://subgraph-endpoints.superfluid.dev/degenchain-mainnet/protocol-v1", + // }, + ethereum: { + graph: "https://subgraph-endpoints.superfluid.dev/eth-mainnet/protocol-v1", + }, + optimism: { + graph: + "https://subgraph-endpoints.superfluid.dev/optimism-mainnet/protocol-v1", + }, + polygon: { + graph: + "https://subgraph-endpoints.superfluid.dev/polygon-mainnet/protocol-v1", + }, + scroll: { + graph: + "https://subgraph-endpoints.superfluid.dev/scroll-mainnet/protocol-v1", + }, + xdai: { + graph: "https://subgraph-endpoints.superfluid.dev/xdai-mainnet/protocol-v1", + }, +}; module.exports = { methodology: `TVL is the total quantity of tokens locked in Super Tokens from Superfluid, on Polygon and xDai (most important being weth, dai, usdc and wbtc, as well as QiDAO and MOCA)`, - hallmarks: [ - [1644278400, "Fake ctx hack"], - ], + hallmarks: [[1644278400, "Fake ctx hack"]], }; -Object.keys(config).forEach(chain => { - const { graph } = config[chain] +Object.keys(subgraphEndpoints).forEach((chain) => { + const { graph } = subgraphEndpoints[chain]; module.exports[chain] = { - tvl: async (_, _b, { [chain]: block }) => retrieveSupertokensBalances(chain, block, false, _, graph), - vesting: async (_, _b, { [chain]: block }) => retrieveSupertokensBalances(chain, block, true, _, graph), - } -}) + tvl: async (_, _b, { [chain]: block }) => + retrieveSupertokensBalances(chain, block, false, _, graph), + vesting: async (_, _b, { [chain]: block }) => + retrieveSupertokensBalances(chain, block, true, _, graph), + }; +}); From 401bccc3be368d9b29cf94f7a57cdc062b285a98 Mon Sep 17 00:00:00 2001 From: Aaron Ho <616127+cincauhangus@users.noreply.github.com> Date: Tue, 29 Oct 2024 00:45:24 +0800 Subject: [PATCH 2/3] fix: hide unlisted tokens --- projects/superfluid.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/projects/superfluid.js b/projects/superfluid.js index b4d7b7c4021a..855ade873c8b 100644 --- a/projects/superfluid.js +++ b/projects/superfluid.js @@ -104,18 +104,13 @@ async function retrieveSupertokensBalances( graphUrl ) { const blockNum = await getBlock(ts, chain, { [chain]: block }); - const gblock = blockNum - 5000; - - console.log(chain, blockNum, gblock); - - // Retrieve supertokens from graphql API const { tokens } = await blockQuery(graphUrl, supertokensQuery, { - api: { - getBlock: () => gblock, - block: gblock, - }, + api: { getBlock: () => blockNum, block: blockNum }, }); - const allTokens = tokens.filter((t) => t.isSuperToken); + const allTokens = tokens.filter((t) => t.isSuperToken && t.isListed); + + sdk.log("Balance table for [%s]", chain); + console.table(allTokens); return getChainBalances(allTokens, chain, block, isVesting); } From f3c61e030294a30803eeccc6454322c76417b8e6 Mon Sep 17 00:00:00 2001 From: Aaron Ho <616127+cincauhangus@users.noreply.github.com> Date: Sun, 10 Nov 2024 00:40:58 +0800 Subject: [PATCH 3/3] merged superfluid TVLs, added missing chains, updated methodology & description --- projects/superfluid.js | 48 ++++++++++-------------------------------- 1 file changed, 11 insertions(+), 37 deletions(-) diff --git a/projects/superfluid.js b/projects/superfluid.js index 855ade873c8b..f4f572721f2b 100644 --- a/projects/superfluid.js +++ b/projects/superfluid.js @@ -31,26 +31,15 @@ query get_supertokens($block: Int) { } `; -function isWhitelistedToken(token, address, isVesting) { - const isStable = - isStableToken(token?.symbol, address) && - !tokensNativeToSidechain.includes(address.toLowerCase()); - return isVesting ? !isStable : isStable; -} - -const blacklist = new Set( +const blacklistedSuperTokens = new Set( ["0x441bb79f2da0daf457bad3d401edb68535fb3faa"].map((i) => i.toLowerCase()) ); // Main function for all chains to get balances of superfluid tokens -async function getChainBalances(allTokens, chain, block, isVesting) { +async function getChainBalances(allTokens, chain, block) { // Init empty balances let balances = {}; - allTokens = allTokens.filter(({ underlyingAddress, underlyingToken = {} }) => - isWhitelistedToken(underlyingToken, underlyingAddress, isVesting) - ); - // Abi MultiCall to get supertokens supplies const { output: supply } = await sdk.api.abi.multiCall({ abi: "erc20:totalSupply", // abi['totalSupply'], @@ -76,10 +65,12 @@ async function getChainBalances(allTokens, chain, block, isVesting) { 10 ** decimals; // Accumulate to balances, the balance for tokens on mainnet or sidechain let prefixedUnderlyingAddress = underlyingAddress; - // if (!underlyingToken && underlyingTokenBalance/1e24 > 1) sdk.log(name, symbol, chain, Math.floor(underlyingTokenBalance/1e24)) - // if (isNativeAssetSuperToken) prefixedUnderlyingAddress = chain + ':' + underlyingAddress - if (!underlyingToken || blacklist.has(underlyingAddress.toLowerCase())) + if ( + !underlyingToken || + blacklistedSuperTokens.has(underlyingAddress.toLowerCase()) + ) { return; + } sdk.util.sumSingleBalance( balances, prefixedUnderlyingAddress, @@ -90,29 +81,14 @@ async function getChainBalances(allTokens, chain, block, isVesting) { return transformBalances(chain, balances); } -const tokensNativeToSidechain = [ - "0x2bf2ba13735160624a0feae98f6ac8f70885ea61", // xdai FRACTION - "0x63e62989d9eb2d37dfdb1f93a22f063635b07d51", // xdai MIVA - "0x263026e7e53dbfdce5ae55ade22493f828922965", // polygon RIC -]; - -async function retrieveSupertokensBalances( - chain, - block, - isVesting, - ts, - graphUrl -) { +async function retrieveSupertokensBalances(chain, block, ts, graphUrl) { const blockNum = await getBlock(ts, chain, { [chain]: block }); const { tokens } = await blockQuery(graphUrl, supertokensQuery, { api: { getBlock: () => blockNum, block: blockNum }, }); const allTokens = tokens.filter((t) => t.isSuperToken && t.isListed); - sdk.log("Balance table for [%s]", chain); - console.table(allTokens); - - return getChainBalances(allTokens, chain, block, isVesting); + return getChainBalances(allTokens, chain, block); } /** @@ -156,7 +132,7 @@ const subgraphEndpoints = { }; module.exports = { - methodology: `TVL is the total quantity of tokens locked in Super Tokens from Superfluid, on Polygon and xDai (most important being weth, dai, usdc and wbtc, as well as QiDAO and MOCA)`, + methodology: `TVL is the value of SuperTokens in circulation. SuperTokens are Superfluid protocol's extension of the ERC20 token standard with additional functionalities like Money Streaming or Distributions. More on SuperTokens here: https://docs.superfluid.finance/docs/concepts/overview/super-tokens`, hallmarks: [[1644278400, "Fake ctx hack"]], }; @@ -164,8 +140,6 @@ Object.keys(subgraphEndpoints).forEach((chain) => { const { graph } = subgraphEndpoints[chain]; module.exports[chain] = { tvl: async (_, _b, { [chain]: block }) => - retrieveSupertokensBalances(chain, block, false, _, graph), - vesting: async (_, _b, { [chain]: block }) => - retrieveSupertokensBalances(chain, block, true, _, graph), + retrieveSupertokensBalances(chain, block, _, graph), }; });