dolomite: handle custom tokens

This commit is contained in:
g1nt0ki
2023-06-22 19:45:13 +02:00
parent b227220043
commit ccaf3e596a
8 changed files with 323 additions and 19 deletions

14
package-lock.json generated
View File

@@ -63,9 +63,9 @@
}
},
"node_modules/@defillama/sdk": {
"version": "4.0.26",
"resolved": "https://registry.npmjs.org/@defillama/sdk/-/sdk-4.0.26.tgz",
"integrity": "sha512-qZ0aZHocHhpWC/Mis/rvc/CCOs1Z+MCbLIVSVfJi/6d4acOzgV5m+oLtxVK1Rz0bsMrPZHdT+kUFkum8EKPodw==",
"version": "4.0.28",
"resolved": "https://registry.npmjs.org/@defillama/sdk/-/sdk-4.0.28.tgz",
"integrity": "sha512-0mqCkiy1pOhZgLCQ/RSdHyuPvchoIoOWj0JIRzFnUAV9uEP6Pck/EqYNB4PpoonZqWAqBDM2cGN1/qj/WQUUtw==",
"dependencies": {
"@supercharge/promise-pool": "^2.1.0",
"ethers": "^5.4.5",
@@ -4194,9 +4194,9 @@
}
},
"@defillama/sdk": {
"version": "4.0.26",
"resolved": "https://registry.npmjs.org/@defillama/sdk/-/sdk-4.0.26.tgz",
"integrity": "sha512-qZ0aZHocHhpWC/Mis/rvc/CCOs1Z+MCbLIVSVfJi/6d4acOzgV5m+oLtxVK1Rz0bsMrPZHdT+kUFkum8EKPodw==",
"version": "4.0.28",
"resolved": "https://registry.npmjs.org/@defillama/sdk/-/sdk-4.0.28.tgz",
"integrity": "sha512-0mqCkiy1pOhZgLCQ/RSdHyuPvchoIoOWj0JIRzFnUAV9uEP6Pck/EqYNB4PpoonZqWAqBDM2cGN1/qj/WQUUtw==",
"requires": {
"@supercharge/promise-pool": "^2.1.0",
"ethers": "^5.4.5",
@@ -6791,7 +6791,7 @@
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
"ansi-regex": "5.0.1"
}
},
"strip-json-comments": {

View File

@@ -3,17 +3,23 @@ const {
getMarketTokenAddress,
getMarketTotalPar,
} = require("./dolomite-margin.json");
const { sumTokens2 } = require('../helper/unwrapLPs')
const dolomiteMargin = "0x6bd780e7fdf01d77e4d475c821f1e7ae05409072";
async function getTokensAndBalances(api, supplyOrBorrow) {
const tokens = await api.fetchList({ lengthAbi: getNumMarkets, itemAbi: getMarketTokenAddress, target: dolomiteMargin })
if (supplyOrBorrow === 'supply')
return sumTokens2({ owner: dolomiteMargin, api, tokens })
const underlyingTokens = await api.multiCall({ abi: 'address:UNDERLYING_TOKEN', calls: tokens, permitFailure: true, })
let bals
if (supplyOrBorrow === 'supply') {
bals = await api.multiCall({ abi: 'erc20:balanceOf', calls: tokens.map(i => ({ target: i, params: dolomiteMargin })), })
const res = await api.fetchList({ lengthAbi: getNumMarkets, itemAbi: getMarketTotalPar, target: dolomiteMargin })
res.forEach((v, i) => api.addToken(tokens[i], v.borrow))
} else {
const res = await api.fetchList({ lengthAbi: getNumMarkets, itemAbi: getMarketTotalPar, target: dolomiteMargin })
bals = res.map(i => i.borrow)
}
tokens.forEach((v, i) => {
api.add(underlyingTokens[i] ?? v, bals[i])
})
}
async function tvl(timestamp, ethereumBlock, blocksToKeys, { api }) {

View File

@@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IUniswapV2Factory {
function allPairsLength() external view returns (uint);
function allPairs(uint) external view returns (address);
}
contract TestUniQuery {
constructor(address factory) {
IUniswapV2Factory uniswapFactory = IUniswapV2Factory(factory);
uint pairCount = uniswapFactory.allPairsLength();
// encode the return data
bytes memory _data = abi.encode(pairCount);
// force constructor to return data via assembly
assembly {
// abi.encode adds an additional offset (32 bytes) that we need to skip
let _dataStart := add(_data, 32)
// msize() gets the size of active memory in bytes.
// if we subtract msize() from _dataStart, the output will be
// the amount of bytes from _dataStart to the end of memory
// which due to how the data has been laid out in memory, will coincide with
// where our desired data ends.
let _dataEnd := sub(msize(), _dataStart)
// starting from _dataStart, get all the data in memory.
return(_dataStart, _dataEnd)
}
}
}

View File

@@ -0,0 +1,100 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IUniswapV2Pair {
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves()
external
view
returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}
interface IUniswapV2Factory {
function allPairsLength() external view returns (uint);
function allPairs(uint) external view returns (address);
}
contract UniV2TVL {
struct KeyValuePair {
address key;
uint value;
}
mapping(address => uint) public tvlMap;
mapping(address => bool) public isBaseToken;
address[] public tokens;
constructor(
address factory,
address[] memory baseTokens,
bool includeQuoteTokens,
uint startIndex,
uint endIndex
) {
IUniswapV2Factory uniswapFactory = IUniswapV2Factory(factory);
uint pairCount = uniswapFactory.allPairsLength();
if (endIndex == 0) endIndex = pairCount;
// Create a set of base tokens for efficient membership check
for (uint i = startIndex; i < baseTokens.length; i++) {
isBaseToken[baseTokens[i]] = true;
}
for (uint i = 0; i < pairCount; i++) {
address pairAddress = uniswapFactory.allPairs(i);
IUniswapV2Pair pair = IUniswapV2Pair(pairAddress);
address token0 = pair.token0();
address token1 = pair.token1();
uint reserve0;
uint reserve1;
(reserve0, reserve1, ) = pair.getReserves();
bool isToken0BaseToken = isBaseToken[token0];
bool isToken1BaseToken = isBaseToken[token1];
if ( reserve0 == 0 || reserve1 == 0) continue;
if (isToken0BaseToken && isToken1BaseToken) {
if (tvlMap[token0] == 0) tokens.push(token0);
if (tvlMap[token1] == 0) tokens.push(token1);
tvlMap[token0] += reserve0;
tvlMap[token1] += reserve1;
} else if (isToken0BaseToken) {
if (tvlMap[token0] == 0) tokens.push(token0);
tvlMap[token0] += reserve0 * 2;
} else if (isToken1BaseToken) {
if (tvlMap[token1] == 0) tokens.push(token1);
tvlMap[token1] += reserve1 * 2;
} else if (includeQuoteTokens) {
if (tvlMap[token0] == 0) tokens.push(token0);
if (tvlMap[token1] == 0) tokens.push(token1);
tvlMap[token0] += reserve0;
tvlMap[token1] += reserve1;
}
}
KeyValuePair[] memory returnData = new KeyValuePair[](tokens.length);
for (uint i = 0; i < tokens.length; i++) {
returnData[i] = KeyValuePair(tokens[i], tvlMap[tokens[i]]);
}
// encode the return data
bytes memory _data = abi.encode(returnData);
// force constructor to return data via assembly
assembly {
// abi.encode adds an additional offset (32 bytes) that we need to skip
let _dataStart := add(_data, 32)
// msize() gets the size of active memory in bytes.
// if we subtract msize() from _dataStart, the output will be
// the amount of bytes from _dataStart to the end of memory
// which due to how the data has been laid out in memory, will coincide with
// where our desired data ends.
let _dataEnd := sub(msize(), _dataStart)
// starting from _dataStart, get all the data in memory.
return(_dataStart, _dataEnd)
}
}
}

126
utils/package-lock.json generated
View File

@@ -9,7 +9,8 @@
"version": "0.0.1",
"license": "ISC",
"dependencies": {
"glob": "^8.0.3"
"glob": "^8.0.3",
"solc": "^0.8.20"
},
"devDependencies": {
"inquirer": "^8.2.4",
@@ -205,6 +206,19 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"node_modules/command-exists": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz",
"integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w=="
},
"node_modules/commander": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
"engines": {
"node": ">= 12"
}
},
"node_modules/defaults": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
@@ -258,6 +272,25 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -701,6 +734,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/js-sha3": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
"integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
@@ -723,6 +761,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
"integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==",
"engines": {
"node": ">= 0.10.0"
}
},
"node_modules/mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
@@ -799,7 +845,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -875,12 +920,40 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
"node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"bin": {
"semver": "bin/semver"
}
},
"node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
},
"node_modules/solc": {
"version": "0.8.20",
"resolved": "https://registry.npmjs.org/solc/-/solc-0.8.20.tgz",
"integrity": "sha512-fPRnGspIEqmhu63RFO3pc79sLA7ZmzO0Uy0L5l6hEt2wAsq0o7UV6pXkAp3Mfv9IBhg7Px/oTu3a+y4gs3BWrQ==",
"dependencies": {
"command-exists": "^1.2.8",
"commander": "^8.1.0",
"follow-redirects": "^1.12.1",
"js-sha3": "0.8.0",
"memorystream": "^0.3.1",
"semver": "^5.5.0",
"tmp": "0.0.33"
},
"bin": {
"solcjs": "solc.js"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -938,7 +1011,6 @@
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"dev": true,
"dependencies": {
"os-tmpdir": "~1.0.2"
},
@@ -1125,6 +1197,16 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
"command-exists": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz",
"integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w=="
},
"commander": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
"integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="
},
"defaults": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
@@ -1166,6 +1248,11 @@
"escape-string-regexp": "^1.0.5"
}
},
"follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -1505,6 +1592,11 @@
"integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
"dev": true
},
"js-sha3": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
"integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
@@ -1521,6 +1613,11 @@
"is-unicode-supported": "^0.1.0"
}
},
"memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
"integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw=="
},
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
@@ -1578,8 +1675,7 @@
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
},
"readable-stream": {
"version": "3.6.0",
@@ -1629,12 +1725,31 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
},
"solc": {
"version": "0.8.20",
"resolved": "https://registry.npmjs.org/solc/-/solc-0.8.20.tgz",
"integrity": "sha512-fPRnGspIEqmhu63RFO3pc79sLA7ZmzO0Uy0L5l6hEt2wAsq0o7UV6pXkAp3Mfv9IBhg7Px/oTu3a+y4gs3BWrQ==",
"requires": {
"command-exists": "^1.2.8",
"commander": "^8.1.0",
"follow-redirects": "^1.12.1",
"js-sha3": "0.8.0",
"memorystream": "^0.3.1",
"semver": "^5.5.0",
"tmp": "0.0.33"
}
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -1683,7 +1798,6 @@
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"dev": true,
"requires": {
"os-tmpdir": "~1.0.2"
}

View File

@@ -13,6 +13,7 @@
"inquirer-fuzzy-path": "^2.3.0"
},
"dependencies": {
"glob": "^8.0.3"
"glob": "^8.0.3",
"solc": "^0.8.20"
}
}

View File

@@ -0,0 +1,24 @@
const ethers = require('ethers')
const { getProvider } = require('@defillama/sdk/build/general')
const fs = require('fs')
const coreAssets = require('../../projects/helper/coreAssets.json')
const bytecode = fs.readFileSync(__dirname + `/../artifacts/UniV2TVL.bytecode`, 'utf8')
// const inputData = ethers.utils.defaultAbiCoder.encode(['address'], ['0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f']);
const inputData = ethers.utils.defaultAbiCoder.encode(['address', 'address[]', 'bool', 'uint256', 'uint256'], ['0x460b2005b3318982feADA99f7ebF13e1D6f6eFfE', Object.values(coreAssets.ethereum), false, 0, 0]);
// concatenate the bytecode of BatchPoolManagerData with the input data.
// the slice is done to remove the 0x prefix from the input data added by the encoding
const contractCreationCode = bytecode.concat(inputData.slice(2));
const provider = getProvider('ethereum')
async function main() {
const returnedData = await provider.call({ data: '0x' + contractCreationCode })
console.log(returnedData)
// decode the returned data to get the array of tuples using the same data types as the Data struct in the PoolManager contract
const [decoded] = ethers.utils.defaultAbiCoder.decode(['tuple(address,uint256)[]'], returnedData);
console.log(decoded)
}
main()

View File

@@ -0,0 +1,28 @@
const solc = require('solc');
const fs = require('fs');
const contractName = 'UniV2TVL';
const contractFile = `${contractName}.sol`;
// Solidity contract code
const solidityCode = fs.readFileSync(__dirname+`/../contracts/${contractFile}`, 'utf8');
function compileContract(contractCode) {
const input = {
language: 'Solidity',
sources: {
[contractFile]: {
content: contractCode,
},
},
settings: {
outputSelection: { '*': { '*': ['*'], }, },
},
};
const output = JSON.parse(solc.compile(JSON.stringify(input)));
const bytecode = output.contracts[contractFile][contractName].evm.bytecode.object;
fs.writeFileSync(__dirname+`/../artifacts/${contractName}.bytecode`, bytecode)
}
// Compile the contract and get the bytecode
compileContract(solidityCode)