feat(gro-protocol): adapter updated with pools

This commit is contained in:
Anthanh
2021-11-04 19:04:19 +01:00
parent faac1de582
commit 38b0d06951
3 changed files with 387 additions and 17 deletions

View File

@@ -11,5 +11,18 @@
],
"stateMutability": "view",
"type": "function"
},
"totalSupply": {
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
}

View File

@@ -0,0 +1,236 @@
const sdk = require("@defillama/sdk");
const BigNumber = require("bignumber.js");
const lpReservesAbi = {
constant: true,
inputs: [],
name: "getReserves",
outputs: [
{ internalType: "uint112", name: "_reserve0", type: "uint112" },
{ internalType: "uint112", name: "_reserve1", type: "uint112" },
{ internalType: "uint32", name: "_blockTimestampLast", type: "uint32" },
],
payable: false,
stateMutability: "view",
type: "function",
};
const lpSuppliesAbi = {
constant: true,
inputs: [],
name: "totalSupply",
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
payable: false,
stateMutability: "view",
type: "function",
};
const token0Abi = {
constant: true,
inputs: [],
name: "token0",
outputs: [{ internalType: "address", name: "", type: "address" }],
payable: false,
stateMutability: "view",
type: "function",
};
const token1Abi = {
constant: true,
inputs: [],
name: "token1",
outputs: [{ internalType: "address", name: "", type: "address" }],
payable: false,
stateMutability: "view",
type: "function",
};
/* lpPositions:{
balance,
token
}[]
*/
async function unwrapUniswapLPs(
balances,
lpPositions,
block,
chain = "ethereum",
transformAddress = (addr) => addr,
excludeTokensRaw = [],
retry = false
) {
const excludeTokens = excludeTokensRaw.map((addr) => addr.toLowerCase());
const lpTokenCalls = lpPositions.map((lpPosition) => ({
target: lpPosition.token,
}));
const lpReserves = sdk.api.abi.multiCall({
block,
abi: lpReservesAbi,
calls: lpTokenCalls,
chain,
});
const lpSupplies = sdk.api.abi.multiCall({
block,
abi: lpSuppliesAbi,
calls: lpTokenCalls,
chain,
});
const tokens0 = sdk.api.abi.multiCall({
block,
abi: token0Abi,
calls: lpTokenCalls,
chain,
});
const tokens1 = sdk.api.abi.multiCall({
block,
abi: token1Abi,
calls: lpTokenCalls,
chain,
});
if (retry) {
await Promise.all(
[
[lpReserves, lpReservesAbi],
[lpSupplies, lpSuppliesAbi],
[tokens0, token0Abi],
[tokens1, token1Abi],
].map(async (call) => {
await requery(await call[0], chain, block, call[1]);
})
);
}
await Promise.all(
lpPositions.map(async (lpPosition) => {
try {
const lpToken = lpPosition.token;
const token0 = (await tokens0).output
.find((call) => call.input.target === lpToken)
.output.toLowerCase();
const token1 = (await tokens1).output
.find((call) => call.input.target === lpToken)
.output.toLowerCase();
const supply = (await lpSupplies).output.find(
(call) => call.input.target === lpToken
).output;
const { _reserve0, _reserve1 } = (await lpReserves).output.find(
(call) => call.input.target === lpToken
).output;
if (!excludeTokens.includes(token0)) {
const token0Balance = BigNumber(lpPosition.balance)
.times(BigNumber(_reserve0))
.div(BigNumber(supply));
sdk.util.sumSingleBalance(
balances,
await transformAddress(token0),
token0Balance.toFixed(0)
);
}
if (!excludeTokens.includes(token1)) {
const token1Balance = BigNumber(lpPosition.balance)
.times(BigNumber(_reserve1))
.div(BigNumber(supply));
sdk.util.sumSingleBalance(
balances,
await transformAddress(token1),
token1Balance.toFixed(0)
);
}
} catch (e) {
console.log(
`Failed to get data for LP token at ${lpPosition.token} on chain ${chain}`
);
throw e;
}
})
);
}
const crvPools = {
// PWRD-3CRV
"0xbcb91e689114b9cc865ad7871845c95241df4105": {
swapContract: "0x001C249c09090D79Dc350A286247479F08c7aaD7",
underlyingTokens: [
"0xf0a93d4994b3d98fb5e3a2f90dbc2d69073cb86b",
"0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490",
],
},
};
async function unwrapCrvLPs(
balances,
lpPositions,
block,
chain = "ethereum",
transformAddress = (addr) => addr,
excludeTokens = []
) {
await Promise.all(
lpPositions.map(async (lp) => {
try {
await unwrapCrv(
balances,
lp.token,
lp.balance,
block,
chain,
transformAddress,
excludeTokens
);
} catch (e) {
console.log(
`Failed to get data for LP token at ${lp.token} on chain ${chain}`
);
throw e;
}
})
);
}
async function unwrapCrv(
balances,
crvToken,
balance3Crv,
block,
chain = "ethereum",
transformAddress = (addr) => addr,
excludeTokensRaw = []
) {
const excludeTokens = excludeTokensRaw.map((t) => t.toLowerCase());
if (crvPools[crvToken.toLowerCase()] === undefined) {
return;
}
const underlyingTokens = crvPools[crvToken.toLowerCase()].underlyingTokens;
const crvTotalSupply = sdk.api.erc20.totalSupply({
target: crvToken,
block,
chain,
});
const underlyingSwapTokens = (
await sdk.api.abi.multiCall({
calls: underlyingTokens.map((token) => ({
target: token,
params: [crvToken],
})),
block,
chain,
abi: "erc20:balanceOf",
})
).output;
const resolvedCrvTotalSupply = (await crvTotalSupply).output;
underlyingSwapTokens.forEach((call) => {
if (excludeTokens.includes(call.input.target.toLowerCase())) {
return;
}
const underlyingBalance = BigNumber(call.output || 0)
.times(balance3Crv)
.div(resolvedCrvTotalSupply);
sdk.util.sumSingleBalance(
balances,
transformAddress(call.input.target),
underlyingBalance.toFixed(0)
);
});
}
module.exports = {
unwrapCrv,
unwrapCrvLPs,
unwrapUniswapLPs,
};

View File

@@ -1,32 +1,153 @@
// Adapter for Gro Protocol : https://gro.xyz
const sdk = require("@defillama/sdk");
const groTokenAbi = require('./abi.json');
const { sumBalancerLps } = require("../helper/unwrapLPs");
const { unwrapUniswapLPs, unwrapCrvLPs } = require("./helpers");
const PWRD = "0xf0a93d4994b3d98fb5e3a2f90dbc2d69073cb86b";
const GVT = "0x3ADb04E127b9C0a5D36094125669d4603AC52a0c";
const DAI = "0x6B175474E89094C44Da98b954EedeAC495271d0F";
const groTokenAbi = require("./abi.json");
// Gro Protocol Token Addresses
const GRO = "0x3Ec8798B81485A254928B70CDA1cf0A2BB0B74D7"; // Governance Token, not counted for TVL unless staked in pools
const GVT = "0x3ADb04E127b9C0a5D36094125669d4603AC52a0c"; // Protocol token representing share of assets, fully count
const PWRD = "0xf0a93d4994b3d98fb5e3a2f90dbc2d69073cb86b"; // Protocol token representing share of assets, fully count
// Gro Protocol LP Pool Addresses
const PO_SS_GRO = "0x3Ec8798B81485A254928B70CDA1cf0A2BB0B74D7"; // Count only if staked
const P1_UNI_GRO_GVT = "0x2ac5bC9ddA37601EDb1A5E29699dEB0A5b67E9bB"; // Count non-GVT assets and only if staked
const P2_UNI_GRO_USDC = "0x21C5918CcB42d20A2368bdCA8feDA0399EbfD2f6"; // Count only if staked
const P3_SS_GVT = "0x3ADb04E127b9C0a5D36094125669d4603AC52a0c"; // Ignore as GVT already counted
const P4_CRV_PWRD_TCRV = "0xbcb91E689114B9Cc865AD7871845C95241Df4105"; // Count non-PWRD assets and only if staked
const P5_BAL_GRO_WETH = "0x702605f43471183158938c1a3e5f5a359d7b31ba"; // Count only if staked
// Other Token Addresses
const TCRV = "0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490"; // Count if staked
const DAI = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; // Count if staked
const USDC = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"; // Count if staked
const USDT = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; // Count if staked
const WETH = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; // Count if staked
// Contract Addresses
const GROTokenStaker = "0x001C249c09090D79Dc350A286247479F08c7aaD7";
async function tvl(timestamp, ethBlock) {
let balances = {};
const uniLpPositions = [];
const balLpPositions = [];
const crvLpPositions = [];
let balances = {};
if (timestamp < 1633046400) {
// Before 01-10-2021
// Prior to this point no pools and no pricing on Coingecko so use 18 decimal DAI as a $1.00 proxy
for (const token of [PWRD, GVT]) {
const current = await sdk.api.abi.call({
target: token,
abi: groTokenAbi["totalAssets"],
block: ethBlock,
});
sdk.util.sumSingleBalance(balances, DAI, current.output);
const current = await sdk.api.abi.call({
target: token,
abi: groTokenAbi["totalAssets"],
block: ethBlock,
});
// Treat amounts as if in DAI. Calls to totalAssets() return USD amount
sdk.util.sumSingleBalance(balances, DAI, current.output);
}
} else {
// On or after 01-10-2021
// Can output PWRD and GVT balances directly as Coingecko can price the tokens
// Assets held within PWRD and GVT directly
for (const token of [PWRD, GVT]) {
const current = await sdk.api.abi.call({
target: token,
abi: groTokenAbi["totalSupply"],
block: ethBlock,
});
sdk.util.sumSingleBalance(balances, token, current.output);
}
return balances;
// Assets held in staking pools (not counting any PWRD or GVT assets as these are already counted)
// PO_SS_GRO
const p0 = await sdk.api.erc20.balanceOf({
target: GRO,
owner: GROTokenStaker,
block: ethBlock,
});
sdk.util.sumSingleBalance(balances, GRO, p0.output);
// P1_UNI_GRO_GVT
// P2_UNI_GRO_USDC
const p1 = (
await sdk.api.erc20.balanceOf({
target: P1_UNI_GRO_GVT,
owner: GROTokenStaker,
block: ethBlock,
})
).output;
uniLpPositions.push({ token: P1_UNI_GRO_GVT, balance: p1 });
const p2 = (
await sdk.api.erc20.balanceOf({
target: P2_UNI_GRO_USDC,
owner: GROTokenStaker,
block: ethBlock,
})
).output;
uniLpPositions.push({ token: P2_UNI_GRO_USDC, balance: p2 });
await unwrapUniswapLPs(
balances,
uniLpPositions,
ethBlock,
"ethereum",
undefined,
[GVT]
); // Excludes already counted GVT amount
// P3_SS_GVT - GVT already accounted for
// P4_CRV_PWRD_TCRV
const p4 = await sdk.api.erc20.balanceOf({
target: P4_CRV_PWRD_TCRV,
owner: GROTokenStaker,
block: ethBlock,
});
crvLpPositions.push({ token: P4_CRV_PWRD_TCRV, balance: p4.output });
await unwrapCrvLPs(
balances,
crvLpPositions,
ethBlock,
"ethereum",
undefined,
[PWRD]
); // Excludes already counted PWRD amount
// P5_BAL_GRO_WETH
if (timestamp > 1633392000) {
// On or after 05-10-2021, P5 pool available
const p5 = await sdk.api.erc20.balanceOf({
target: P5_BAL_GRO_WETH,
owner: GROTokenStaker,
block: ethBlock,
});
balLpPositions.push({ P5_BAL_GRO_WETH, p5 });
await sumBalancerLps(
balances,
[[P5_BAL_GRO_WETH, GROTokenStaker, true]],
ethBlock,
"ethereum",
(addr) => addr.toLowerCase(addr)
);
}
}
return balances;
}
module.exports = {
ethereum:{
tvl,
},
start: 1622204347, // 28-05-2021 12:19:07 (UTC)
methodology: "Using DAI as a placeholder with same 18 decimals until coins listed on coingecko. The totalAssets() call returns USD value",
ethereum: {
tvl,
},
start: 1622204347, // 28-05-2021 12:19:07 (UTC)
methodology:
"Assets held within the GRO Protocol - either within the PWRD or Vault (GVT) products, or staked in the Gro Protocol pools.",
};