Tool for calculating and analyzing token balances across different DEX blockchains and other types of Smart Contracts. This tool is specifically designed for:
- Multi-DEX Analysis: Retrieval and analysis of token balances across different DEX (Honeyswap, Sushiswap, Balancer, SwaprHQ)
- Multi-Chain Support: Compatible with multiple blockchain networks (Gnosis, Ethereum, Polygon)
- Voting Power Calculation: Generation of voting power from snapshots with the ability to apply different calculation models and modify balances
- Temporal Analysis: Ability to analyze balances at different points in time (snapshot)
- Holders Ranking: Creation of rankings of token holders
- Flexible Export: Generation of reports in JSON and CSV format
The tool is particularly useful for:
- DAO administrators wishing to calculate the distribution of voting rights
- Analysts seeking to understand token distribution
- Blockchain developers needing precise data on token balances
- Auditors wanting to verify holdings across different platforms
- Installation
- Configuration
- Project Structure
- Usage
- Code Modification and Feature Addition
- Contribution
- License
- Support
- TODO
git clone [project-url]Install the LTS version of node found in the .nvmrc file or use nvm to manage node versions
nvm installuse the node version
nvm usenpm install -g yarnyarn installcp .env.example .envModify the copy of the .env.example file to .env at the root of the project with the following variables:
-
The Graph API Key
- Visit The Graph
- Create an account or log in
- Go to your profile > Settings > API Keys
- Create a new API key
- Copy the key into your .env:
THEGRAPH_API_KEY=your_api_key
-
Etherscan API Key
- Visit Etherscan
- Create an account or log in
- Go to API Keys > Add
- Create a new API key
- Copy the key into your .env:
API_KEY_ETHERSCAN=your_etherscan_key
-
Gnosisscan API Key
- Visit Gnosisscan
- Create an account or log in
- Go to API Keys > Add
- Create a new API key
- Copy the key into your .env:
API_KEY_GNOSISSCAN=your_gnosisscan_key
-
Polygonscan API Key
- Visit Polygonscan
- Create an account or log in
- Go to API Keys > Add
- Create a new API key
- Copy the key into your .env:
API_KEY_POLYGONSCAN=your_polygonscan_key
-
Moralis API Key
- Visit Moralis
- Create an account or log in
- Go to API Keys
- Create a new API key
- Copy the key into your .env:
API_KEY_MORALIS=your_moralis_key
-
Additional Endpoints (Optional)
- Add your additional endpoints as a JSON array:
ENDPOINT_EXTRA=["https://endpoint1.com","https://endpoint2.com"]
- Add your additional endpoints as a JSON array:
-
The Graph Development URLs (Optional) If you are developing with custom The Graph endpoints:
THE_GRAPH_DEV_URL_REG_GNOSIS="your_url" THE_GRAPH_DEV_URL_REG_ETHEREUM="your_url" THE_GRAPH_DEV_URL_REG_POLYGON="your_url" THE_GRAPH_DEV_URL_GOV_GNOSIS="your_url"
Your final .env file should look like this:
API_KEY_GNOSISSCAN="your_gnosisscan_key"
API_KEY_ETHERSCAN="your_etherscan_key"
API_KEY_POLYGONSCAN="your_polygonscan_key"
THEGRAPH_API_KEY="your_thegraph_key"
# Optional
ENDPOINT_EXTRA=["https://endpoint1.com","https://endpoint2.com"]
# The Graph DEV URLs (Optional)
THE_GRAPH_DEV_URL_REG_GNOSIS=""
THE_GRAPH_DEV_URL_REG_ETHEREUM=""
THE_GRAPH_DEV_URL_REG_POLYGON=""
THE_GRAPH_DEV_URL_GOV_GNOSIS=""
src/
├── abi/ # ABI files
├── configs/ # Configuration files
├── graphql/ # GraphQL query files
├── mocks/ # Mock files
├── models/ # Data models
├── modifiers/ # Balance modifiers
├── tasks/ # Main tasks
├── types/ # TypeScript type definitions
├── utils/ # Utilities and common functions
└── index.ts # Entry point
.env # Environment variables
.env.example # Example .env file
.gitignore # Git ignored file
.nvmrc # Node version
package.json # Application configuration file
readme.md # Documentation
tsconfig.json # TypeScript configuration
constants.ts: Definitions of global constantsdex.json: DEX configurationoptionsModifiers.ts: Configuration file for voting power calculations
powerVotingModels.ts: Voting power calculation modelsinputModels.ts: Input data models
Contains the main tasks of the application:
- GetBalancesREG: Retrieves REG balances across different DEX and networks
- GetAddressOwnRealToken: Lists addresses owning RealTokens
- RankingREG: Generates a ranking of REG holders from REG snapshots
- CalculatePowerVotingREG: Calculates voting power for each address from REG snapshots
graphql.ts: Functions for interacting with TheGraphlib.ts: General utility functionsqueryDexs.ts: DEX-specific queries
# Start the application in normal mode
yarn start
# Start the application in log writing mode to a file logs.log
yarn start:logsRetrieves REG balances across different DEX and networks.
# Available options:
- Network selection (Gnosis, Ethereum, Polygon)
- DEX selection by network
- Customizable time periodLists addresses owning RealTokens.
# Features:
- Token selection
- Customizable time period
- Exclusion of specific addressesGenerates a ranking of REG holders from REG snapshots.
# Options:
- Configurable Top N holders
- Filtering by balance typeCalculates voting power for each address from REG snapshots.
# Features:
- Different calculation models available
- Support for balance modifiers
- Generation of transaction data in batches of 500To add a new DEX to our application, follow these steps:
- Create a new balance retrieval function: This function must be able to retrieve balances for the new DEX. It should be defined in the appropriate file ("src/utils/queryDeks.ts") and exported for use elsewhere in the application.
// Example of a balance retrieval function for a new DEX
export async function getRegBalancesNewDexExample(
configs: any,
network?: Network,
timestamp?: number | undefined,
mock?: boolean | undefined
): Promise<ResponseFunctionGetRegBalances> {
// Your code here...
return responseFormatterNewDexExample(result);
}- Create a new response conversion function: This function must convert and standardize the response from the graph to the "ResponseFunctionGetRegBalances" format ("src/utils/queryDeks.ts"), used in the previous function to format the return.
// Example of a response formatting function from the graph
function responseFormatterNewDexExample(pairs: any): ResponseFunctionGetRegBalances[] {
return pairs.map((pair: any) => {
const totalSupply = pair.totalSupply;
return {
poolId: pair.id,
liquidityPositions: pair.liquidityPositions.map((liquidityPosition: any) => {
const userLiquidityTokenBalance = liquidityPosition.liquidityTokenBalance;
const userLiquidityPercentage = userLiquidityTokenBalance / totalSupply;
return {
user: {
id: liquidityPosition.user.id,
},
liquidity: [
{
tokenId: pair.token0.symbol,
tokenDecimals: pair.token0.decimals,
tokenSymbol: pair.token0.symbol,
tokenBalance: new BigNumber(pair.reserve0).multipliedBy(userLiquidityPercentage).toString(),
},
{
tokenId: pair.token1.symbol,
tokenDecimals: pair.token1.decimals,
tokenSymbol: pair.token1.symbol,
tokenBalance: new BigNumber(pair.reserve1).multipliedBy(userLiquidityPercentage).toString(),
},
],
};
}),
};
});
}-
Add DEX information in the constants file Complete the DEX, NETWORK, the constant networkToDexsMap, and dexFunctionMap
-
Complete the DEX configuration file for the added DEX Add configuration information in the "src/configs/dex.json" file
-
Optionally, add a mock file for the added DEX The mock file allows testing without having to call TheGraph
Create a ts file in the modifiers folder with the name of the modifier function that will be exported, one file per modifier.
Modify the NormalizeOptions type in the inputModels.types.ts file with the key of the modifier.
Create the code for the modifier with the minimum structure:
export function modifierName(
data: SourceBalancesREG[],
options: NormalizeOptions["modifierName"]
): SourceBalancesREG[] {
// Your code here...
}The modifier must return an array of SourceBalancesREG[] which is the modified version of the input data data without changing its structure.
Add the exported function to the module in the index.ts file of the modifiers folder.
To use the new modifier, add the key and value in the optionsModifiers.ts file.
To be written
- Fork the project
- Create a branch (
git checkout -b feature/new-feature) - Commit the changes (
git commit -am 'Add new feature') - Push the branch (
git push origin feature/new-feature) - Create a Pull Request
MIT
For any questions or issues, please open an issue in the repository or contact us on Telegram.
- Write the Code Modification and Feature Addition section -> add calculation model for voting power
- Add a custom logger to remove TheGraph API keys from the logs
- Add the dex keys management in the ranking calculation