Created
November 1, 2021 13:33
-
-
Save Reinis-FRP/73d1bf5ea9edc78e7de3b4cd61802c80 to your computer and use it in GitHub Desktop.
Fetch LSP contracts from known creator addresses
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const util = require('util'); | |
const Web3 = require('web3'); | |
const client = require('node-rest-client-promise').Client(); | |
require('dotenv').config(); | |
const fs = require('fs').promises; | |
const NODE_URL = { | |
1: process.env.NODE_URL_CHAIN_1, | |
137: process.env.NODE_URL_CHAIN_137, | |
}; | |
const blockLimits = {1: 10000000, 137: 100000}; | |
const lspCreatorAddresses = { | |
1: [ | |
"0x07417ca264170fc5bd3568f93cfb956729752b61", | |
"0x5a8d408B7908E4F00A2f5460B621dbF2DDce8042", | |
"0x0b8de441B26E36f461b2748919ed71f50593A67b", | |
"0x60F3f5DDE708D097B7F092EFaB2E085AC0a82F42", | |
"0x31C893843685f1255A26502eaB5379A3518Aa5a9", | |
"0x9504b4ab8cd743b06074757d3B1bE3a3aF9cea10", | |
], | |
137: [ | |
"0x3e665D15425fAee14eEF53B9caaa0762b243911a", | |
"0x751190691A07acC3f43A7396AD87967bB685deEd", | |
"0x5Fd7FFF20Ee851cD7bEE72fB3C6d324e4C104c9f", | |
], | |
}; | |
const csvFile = './lspContracts.csv'; | |
const lspCreatorAbi = [{ | |
"anonymous": false, | |
"inputs": [ | |
{ | |
"indexed": true, | |
"internalType": "address", | |
"name": "longShortPair", | |
"type": "address" | |
}, | |
{ | |
"indexed": true, | |
"internalType": "address", | |
"name": "deployerAddress", | |
"type": "address" | |
}, | |
{ | |
"indexed": false, | |
"internalType": "address", | |
"name": "longToken", | |
"type": "address" | |
}, | |
{ | |
"indexed": false, | |
"internalType": "address", | |
"name": "shortToken", | |
"type": "address" | |
} | |
], | |
"name": "CreatedLongShortPair", | |
"type": "event" | |
}]; | |
const lspAbi = [ | |
{ | |
"inputs": [], | |
"name": "collateralPerPair", | |
"outputs": [ | |
{ | |
"internalType": "uint256", | |
"name": "", | |
"type": "uint256" | |
} | |
], | |
"stateMutability": "view", | |
"type": "function" | |
}, | |
{ | |
"inputs": [], | |
"name": "collateralToken", | |
"outputs": [ | |
{ | |
"internalType": "contract IERC20", | |
"name": "", | |
"type": "address" | |
} | |
], | |
"stateMutability": "view", | |
"type": "function" | |
}, | |
{ | |
"inputs": [], | |
"name": "contractState", | |
"outputs": [ | |
{ | |
"internalType": "enum LongShortPair.ContractState", | |
"name": "", | |
"type": "uint8" | |
} | |
], | |
"stateMutability": "view", | |
"type": "function" | |
}, | |
{ | |
"inputs": [], | |
"name": "customAncillaryData", | |
"outputs": [ | |
{ | |
"internalType": "bytes", | |
"name": "", | |
"type": "bytes" | |
} | |
], | |
"stateMutability": "view", | |
"type": "function" | |
}, | |
{ | |
"inputs": [], | |
"name": "expirationTimestamp", | |
"outputs": [ | |
{ | |
"internalType": "uint64", | |
"name": "", | |
"type": "uint64" | |
} | |
], | |
"stateMutability": "view", | |
"type": "function" | |
}, | |
{ | |
"inputs": [], | |
"name": "financialProductLibrary", | |
"outputs": [ | |
{ | |
"internalType": "contract LongShortPairFinancialProductLibrary", | |
"name": "", | |
"type": "address" | |
} | |
], | |
"stateMutability": "view", | |
"type": "function" | |
}, | |
{ | |
"inputs": [], | |
"name": "priceIdentifier", | |
"outputs": [ | |
{ | |
"internalType": "bytes32", | |
"name": "", | |
"type": "bytes32" | |
} | |
], | |
"stateMutability": "view", | |
"type": "function" | |
}, | |
{ | |
"inputs": [], | |
"name": "expiryPercentLong", | |
"outputs": [ | |
{ | |
"internalType": "uint256", | |
"name": "", | |
"type": "uint256" | |
} | |
], | |
"stateMutability": "view", | |
"type": "function" | |
}, | |
{ | |
"inputs": [], | |
"name": "pairName", | |
"outputs": [ | |
{ | |
"internalType": "string", | |
"name": "", | |
"type": "string" | |
} | |
], | |
"stateMutability": "view", | |
"type": "function" | |
}, | |
]; | |
const tokenAbi = [ | |
{ | |
"inputs": [], | |
"name": "decimals", | |
"outputs": [ | |
{ | |
"internalType": "uint8", | |
"name": "", | |
"type": "uint8" | |
} | |
], | |
"stateMutability": "view", | |
"type": "function" | |
}, | |
{ | |
"inputs": [], | |
"name": "name", | |
"outputs": [ | |
{ | |
"internalType": "string", | |
"name": "", | |
"type": "string" | |
} | |
], | |
"stateMutability": "view", | |
"type": "function" | |
}, | |
{ | |
"inputs": [], | |
"name": "symbol", | |
"outputs": [ | |
{ | |
"internalType": "string", | |
"name": "", | |
"type": "string" | |
} | |
], | |
"stateMutability": "view", | |
"type": "function" | |
}, | |
{ | |
"inputs": [], | |
"name": "totalSupply", | |
"outputs": [ | |
{ | |
"internalType": "uint256", | |
"name": "", | |
"type": "uint256" | |
} | |
], | |
"stateMutability": "view", | |
"type": "function" | |
}, | |
]; | |
const contractStates = ["Open", "ExpiredPriceRequested", "ExpiredPriceReceived"]; | |
let web3 = {}; | |
const latestBlock = {}; | |
const lspContracts = {}; | |
const tokenDetails = {}; | |
async function loadWeb3() { | |
for (i in NODE_URL) { | |
web3[i] = new Web3(NODE_URL[i]); | |
latestBlock[i] = await web3[i].eth.getBlockNumber(); | |
} | |
} | |
async function getContract(creatorAddress, chain) { | |
const contract = new web3[chain].eth.Contract(lspCreatorAbi, creatorAddress); | |
return contract; | |
}; | |
async function eventQuery(creatorAddress, chain, event, fromBlock, limit) { | |
const contract = await getContract(creatorAddress, chain); | |
events = await contract.getPastEvents(event, | |
{ | |
fromBlock: fromBlock, | |
toBlock: fromBlock + limit - 1 | |
}); | |
return events; | |
}; | |
async function tryEventQuery(creatorAddress, chain, event, fromBlock, limit, callback) { | |
const contract = await getContract(creatorAddress, chain); | |
try { | |
const events = await contract.getPastEvents(event, | |
{ | |
fromBlock: fromBlock, | |
toBlock: fromBlock + limit - 1 | |
}); | |
callback(null, events); | |
} catch (err) { | |
callback (err); | |
} | |
}; | |
async function getLspContracts() { | |
for (chain in lspCreatorAddresses) { | |
let events = []; | |
for (address in lspCreatorAddresses[chain]) { | |
const indexArray = []; | |
for (let i = 0; i <= latestBlock[chain]; i += blockLimits[chain]) { | |
indexArray.push(i); | |
} | |
events = events.concat((await Promise.all(indexArray.map(async (i) => { | |
return await eventQuery(lspCreatorAddresses[chain][address], chain, 'CreatedLongShortPair', i, blockLimits[chain]); | |
}))).reduce((reducedEvents, eventArray) => {return reducedEvents.concat(eventArray)}, [])); | |
} | |
await getLspFromEvents(events, chain); | |
} | |
} | |
async function getLspFromEvents(events, chain) { | |
for (const event of events) { | |
lspContracts[event.returnValues.longShortPair] = {"chainId": chain}; | |
lspContracts[event.returnValues.longShortPair]["creator"] = event.address; | |
lspContracts[event.returnValues.longShortPair]["deployer"] = event.returnValues.deployerAddress; | |
lspContracts[event.returnValues.longShortPair]["longTokenAddress"] = event.returnValues.longToken; | |
lspContracts[event.returnValues.longShortPair]["shortTokenAddress"] = event.returnValues.shortToken; | |
lspContracts[event.returnValues.longShortPair]["deployedAt"] = (await web3[chain].eth.getBlock(event.blockNumber)).timestamp; | |
await getLspDetails(event.returnValues.longShortPair, chain); | |
} | |
} | |
async function getLspDetails(lspAddress, chain) { | |
const lspContract = new web3[chain].eth.Contract(lspAbi, lspAddress); | |
[ | |
lspContracts[lspAddress]["collateralPerPair"], | |
lspContracts[lspAddress]["collateralAddress"], | |
lspContracts[lspAddress]["contractState"], | |
lspContracts[lspAddress]["ancillaryData"], | |
lspContracts[lspAddress]["expirationTimestamp"], | |
lspContracts[lspAddress]["financialProductLibrary"], | |
lspContracts[lspAddress]["priceIdentifier"], | |
expiryPercentLong, | |
] = await Promise.all([ | |
lspContract.methods.collateralPerPair().call(), | |
lspContract.methods.collateralToken().call(), | |
lspContract.methods.contractState().call(), | |
lspContract.methods.customAncillaryData().call(), | |
lspContract.methods.expirationTimestamp().call(), | |
lspContract.methods.financialProductLibrary().call(), | |
lspContract.methods.priceIdentifier().call(), | |
lspContract.methods.expiryPercentLong().call(), | |
]); | |
const rawCollateralPerPair = lspContracts[lspAddress].collateralPerPair; | |
lspContracts[lspAddress].collateralPerPair = web3[chain].utils.fromWei(lspContracts[lspAddress].collateralPerPair); | |
lspContracts[lspAddress].contractState = contractStates[lspContracts[lspAddress].contractState]; | |
try { | |
lspContracts[lspAddress].ancillaryData = web3[chain].utils.hexToUtf8(lspContracts[lspAddress].ancillaryData); | |
} catch (err) {} | |
try { | |
lspContracts[lspAddress]["pairName"] = await lspContract.methods.pairName().call(); | |
} catch (err) { | |
lspContracts[lspAddress]["pairName"] = ""; | |
} | |
lspContracts[lspAddress].priceIdentifier = web3[chain].utils.hexToUtf8(lspContracts[lspAddress].priceIdentifier); | |
const collateralDetails = await getTokenDetails(lspContracts[lspAddress].collateralAddress, chain); | |
const longTokenDetails = await getTokenDetails(lspContracts[lspAddress].longTokenAddress, chain); | |
const shortTokenDetails = await getTokenDetails(lspContracts[lspAddress].shortTokenAddress, chain); | |
lspContracts[lspAddress]["collateralSymbol"] = collateralDetails.symbol; | |
lspContracts[lspAddress]["collateralDecimals"] = collateralDetails.decimals; | |
lspContracts[lspAddress]["collateralLocked"] = web3[chain].utils.fromWei(web3[chain].utils.toBN(longTokenDetails.totalSupply).mul(web3[chain].utils.toBN(expiryPercentLong)).add(web3[chain].utils.toBN(shortTokenDetails.totalSupply).mul(web3[chain].utils.toBN(web3[chain].utils.toWei('1')).sub(web3[chain].utils.toBN(expiryPercentLong)))).mul(web3[chain].utils.toBN(rawCollateralPerPair)).div(web3[chain].utils.toBN('10').pow(web3[chain].utils.toBN('36')))); | |
lspContracts[lspAddress]["longTokenSymbol"] = longTokenDetails.symbol; | |
lspContracts[lspAddress]["longTokenDecimals"] = longTokenDetails.decimals; | |
lspContracts[lspAddress]["longTokensOutstanding"] = web3[chain].utils.fromWei(web3[chain].utils.toBN(longTokenDetails.totalSupply).mul(web3[chain].utils.toBN('10').pow(web3[chain].utils.toBN('18').sub(web3[chain].utils.toBN(longTokenDetails.decimals))))); | |
lspContracts[lspAddress]["shortTokenSymbol"] = shortTokenDetails.symbol; | |
lspContracts[lspAddress]["shortTokenDecimals"] = shortTokenDetails.decimals; | |
lspContracts[lspAddress]["shortTokensOutstanding"] = web3[chain].utils.fromWei(web3[chain].utils.toBN(shortTokenDetails.totalSupply).mul(web3[chain].utils.toBN('10').pow(web3[chain].utils.toBN('18').sub(web3[chain].utils.toBN(shortTokenDetails.decimals))))); | |
} | |
async function getTokenDetails(address, chain) { | |
if (address in tokenDetails) { | |
return tokenDetails[address]; | |
} else { | |
const token = new web3[chain].eth.Contract(tokenAbi, address); | |
tokenDetails[address] = {}; | |
[ | |
tokenDetails[address]["decimals"], | |
tokenDetails[address]["symbol"], | |
tokenDetails[address]["totalSupply"], | |
] = await Promise.all([ | |
token.methods.decimals().call(), | |
token.methods.symbol().call(), | |
token.methods.totalSupply().call(), | |
]); | |
return tokenDetails[address]; | |
} | |
} | |
function convertToCsv() { | |
const rows = Object.keys(lspContracts).map((address) => { | |
let row = {...{"lspAddress": address}, ...lspContracts[address]}; | |
row = Object.values(row); | |
row = row.join('\t'); | |
return row; | |
}); | |
const headers = Object.keys(lspContracts[Object.keys(lspContracts)[0]]); | |
headers.unshift('lspAddress'); | |
rows.unshift(headers.join('\t')); | |
return rows.join('\n'); | |
} | |
async function writeCsvFile(filePath, data) { | |
try { | |
await fs.writeFile(filePath, data); | |
} catch (err) { | |
console.error(err.message); | |
} | |
} | |
(async () => { | |
await loadWeb3(); | |
await getLspContracts(); | |
console.log(lspContracts); | |
const csv = convertToCsv(); | |
await writeCsvFile(csvFile, csv); | |
process.exit(0); | |
})().catch((e) => { | |
console.error(e); | |
process.exit(1); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment