Skip to content

Instantly share code, notes, and snippets.

@Reinis-FRP
Created November 1, 2021 13:33
Show Gist options
  • Save Reinis-FRP/73d1bf5ea9edc78e7de3b4cd61802c80 to your computer and use it in GitHub Desktop.
Save Reinis-FRP/73d1bf5ea9edc78e7de3b4cd61802c80 to your computer and use it in GitHub Desktop.
Fetch LSP contracts from known creator addresses
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