From 24706483e232812abf75551a854fb8a23fea267b Mon Sep 17 00:00:00 2001 From: Hrishikesh-Thakkar Date: Tue, 15 Oct 2024 15:48:54 +0530 Subject: [PATCH 1/4] hardcoding the subgraph ids and refactoring --- .env.example | 5 +---- src/strategies/moxie/index.ts | 12 ++++-------- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/.env.example b/.env.example index 8af16a922..09a8f8d33 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,4 @@ SNAPSHOT_API_STRATEGY_SALT=12345 # Salt for the snapshot API strategy to send a key in header (optional) PASSPORT_API_KEY= # API key for the passport API (optional for other strategies) PASSPORT_SCORER_ID= # Scorer ID for the passport API (optional for other strategies) -MOXIE_API_KEY= # API key for the moxie APIs (optional for other strategies) -MOXIE_PROTOCOL_ID= #Protocol ID for the moxie API (optional for other strategies) -MOXIE_VESTING_ID= # Vesting ID for the moxie API (optional for other strategies) -MOXIE_LIQUDITY_ID= # Liquidity ID for the moxie API (optional for other strategies) \ No newline at end of file +MOXIE_API_KEY= # API key for the moxie APIs (optional for other strategies) \ No newline at end of file diff --git a/src/strategies/moxie/index.ts b/src/strategies/moxie/index.ts index 32ee0e511..5de34bc9e 100644 --- a/src/strategies/moxie/index.ts +++ b/src/strategies/moxie/index.ts @@ -33,22 +33,18 @@ export async function strategy( throw new Error("This strategy expects a single address"); }; const MOXIE_API_KEY = process.env.MOXIE_API_KEY || ""; - const MOXIE_PROTOCOL_ID = process.env.MOXIE_PROTOCOL_ID || ""; - const MOXIE_VESTING_ID = process.env.MOXIE_VESTING_ID || ""; - const MOXIE_LIQUIDITY_ID = process.env.MOXIE_LIQUIDITY_ID || ""; + const MOXIE_PROTOCOL_ID = "7zS29h4BDSujQq8R3TFF37JfpjtPQsRUpoC9p4vo4scx"; + const MOXIE_VESTING_ID = "BuR6zAj2GSVZz6smGbJZkgQx8S6GUS881R493ZYZKSk3"; + const MOXIE_LIQUIDITY_ID = "2rv5XN3LDQiuc9BXFzUri7ZLnS6K1ZqNJzp8Zj8TqMhy"; //SETTING DEFAULT SUBGRAPH URLS let MOXIE_PROTOCOL_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-protocol/version/latest"; let MOXIE_VESTING_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-vesting/version/latest"; let MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-liquidity/version/latest"; - if (MOXIE_API_KEY !== "" && MOXIE_PROTOCOL_ID !== "") { + if (MOXIE_API_KEY !== "" ) { MOXIE_PROTOCOL_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_PROTOCOL_ID}`; - } - if (MOXIE_API_KEY !== "" && MOXIE_LIQUIDITY_ID !== "") { MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_LIQUIDITY_ID}`; - } - if (MOXIE_API_KEY !== "" && MOXIE_VESTING_ID !== "") { MOXIE_VESTING_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_VESTING_ID}`; } From 4067c1a47e476d1072dd064d14051a6f3eea8001 Mon Sep 17 00:00:00 2001 From: 0xsarvesh Date: Thu, 24 Oct 2024 18:25:22 +0530 Subject: [PATCH 2/4] updated strategy to use moxie endpoints --- src/strategies/moxie/examples.json | 28 ++-- src/strategies/moxie/index.ts | 213 +++-------------------------- 2 files changed, 35 insertions(+), 206 deletions(-) diff --git a/src/strategies/moxie/examples.json b/src/strategies/moxie/examples.json index 517ec6feb..e5723a02c 100644 --- a/src/strategies/moxie/examples.json +++ b/src/strategies/moxie/examples.json @@ -1,14 +1,16 @@ [ - { - "name": "Example query", - "strategy": { - "name": "moxie" - }, - "network": "8453", - "addresses": [ - "0xb59aa5bb9270d44be3fa9b6d67520a2d28cf80ab" - ], - "snapshot": 20631331 - } - ] - \ No newline at end of file + { + "name": "Example query", + "strategy": { + "name": "moxie" + }, + "network": "8453", + "addresses": [ + "0x764e427020ad72624075c61260192c6e486d15a5", + "0xb59aa5bb9270d44be3fa9b6d67520a2d28cf80ab", + "0xcf03287A85298166522002c97aE4B1556fF026B3", + "0xcBFBcbFcA74955B8AB75Dec41F7b9eF36F329879" + ], + "snapshot": 20631331 + } +] diff --git a/src/strategies/moxie/index.ts b/src/strategies/moxie/index.ts index 5de34bc9e..6bdf503fc 100644 --- a/src/strategies/moxie/index.ts +++ b/src/strategies/moxie/index.ts @@ -1,23 +1,16 @@ -import { BigNumberish } from '@ethersproject/bignumber'; -import { formatUnits } from '@ethersproject/units'; -import { Multicaller, subgraphRequest } from '../../utils'; -import { getAddress } from '@ethersproject/address'; +import { customFetch } from '../../utils'; -export const author = 'Hrishikesh-Thakkar'; -export const version = '0.0.1'; +export const author = '0xsarvesh'; +export const version = '0.0.2'; -const abi = [ - 'function balanceOf(address account) external view returns (uint256)' -]; +const MOXIE_ENDPOINT = 'https://api.moxie.xyz/protocol/address-votes'; +const MOXIE_API_KEY = process.env.MOXIE_API_KEY || ''; -const QUERY_LIMIT = 1000; -const UNSTAKED_FAN_TOKEN_MULTIPLIER = 2; -const STAKED_FAN_TOKEN_MULTIPLIER = 3; -const MOXIE_LIQUIDITY_MULTIPLIER = 2; -const MOXIE_CONTRACT_ADDRESS = "0x8C9037D1Ef5c6D1f6816278C7AAF5491d24CD527"; -const MOXIE_DECIMALS = 18; -const PORTFOLIO_SUBGRAPH_PAGE_LIMIT = 2; -const LIQUIDITY_POOL_SUBGRAPH_PAGE_LIMIT = 1; +const buildURL = (addresses, snapshot) => { + const addressesParam = addresses.join(','); + const snapshotParam = snapshot ? `&block=${snapshot}` : '&block=latest'; + return `${MOXIE_ENDPOINT}?addresses=${addressesParam}${snapshotParam}`; +}; //Strategy to Compute Voting Power for MoxieDAO export async function strategy( @@ -28,182 +21,16 @@ export async function strategy( options, snapshot ) { - //Check if the addresses array has length not equal to 1 - if(addresses.length != 1) { - throw new Error("This strategy expects a single address"); - }; - const MOXIE_API_KEY = process.env.MOXIE_API_KEY || ""; - const MOXIE_PROTOCOL_ID = "7zS29h4BDSujQq8R3TFF37JfpjtPQsRUpoC9p4vo4scx"; - const MOXIE_VESTING_ID = "BuR6zAj2GSVZz6smGbJZkgQx8S6GUS881R493ZYZKSk3"; - const MOXIE_LIQUIDITY_ID = "2rv5XN3LDQiuc9BXFzUri7ZLnS6K1ZqNJzp8Zj8TqMhy"; - - //SETTING DEFAULT SUBGRAPH URLS - let MOXIE_PROTOCOL_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-protocol/version/latest"; - let MOXIE_VESTING_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-vesting/version/latest"; - let MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL = "https://api.studio.thegraph.com/query/88457/moxie-liquidity/version/latest"; - - if (MOXIE_API_KEY !== "" ) { - MOXIE_PROTOCOL_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_PROTOCOL_ID}`; - MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_LIQUIDITY_ID}`; - MOXIE_VESTING_SUBGRAPH_URL = `https://gateway.thegraph.com/api/${MOXIE_API_KEY}/subgraphs/id/${MOXIE_VESTING_ID}`; - } - - //Check if the snapshot is for a specific block number or it's latest - const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; - const addressesMap = addresses.reduce((map, address) => { - map[getAddress(address)] = 0; - return map; - }, {}); - - const lowercaseAddresses = Object.keys(addressesMap).map((address) => - address.toLowerCase() - ); - - // Once we have the addresses we need to query the subgraphs to get the vesting contract addresses - const vestingSubgraphQuery = { - tokenLockWallets: { - __args: { - where: { - beneficiary_in: lowercaseAddresses - } - }, - id: true, - beneficiary: true, - } - }; - //Adding block to the query if the snapshot is not latest - if (snapshot !== 'latest') { - vestingSubgraphQuery.tokenLockWallets.__args['block'] = { number: snapshot }; - } - - //Query the vesting subgraph to get the vesting contract addresses - const vestingContractResponse = await subgraphRequest(MOXIE_VESTING_SUBGRAPH_URL, vestingSubgraphQuery); - - // Generate a map of vesting contract addresses to beneficiaries - const addressToBeneficiaryMap = vestingContractResponse.tokenLockWallets.reduce((map, wallet) => { - map[wallet.id.toLowerCase()] = wallet.beneficiary.toLowerCase(); - return map; - }, {}); - - // Add vesting contract addresses to the list of addresses to query - const allAddresses = [ - ...Object.keys(addressToBeneficiaryMap), - ...lowercaseAddresses - ]; - - // Initialise all the addresses with a score of 0 - const allAddressesScoreMap = allAddresses.reduce((map, address) => { - map[getAddress(address)] = 0; - return map; - }, {}); - - const protocolSubgraphQuery = { - portfolios: { - __args: { - where: { - user_in: allAddresses, - balance_gt: 0 - }, - first: QUERY_LIMIT, - skip: 0 - }, - unstakedBalance: true, - stakedBalance: true, - subjectToken: { - currentPriceInMoxie: true - }, - user: { - id: true - } - } - }; - - const liquidityPoolSubgraphQuery = { - userPools: { - __args: { - where: { - user_in: allAddresses, - }, - first: QUERY_LIMIT, - skip: 0 - }, - totalLPAmount: true, - pool: { - totalSupply: true, - moxieReserve: true, - }, - user: { - id: true - } - } - }; - - //Adding block to the queries if the snapshot is not latest - if (snapshot !== 'latest') { - protocolSubgraphQuery.portfolios.__args['block'] = { number: snapshot }; - liquidityPoolSubgraphQuery.userPools.__args['block'] = { number: snapshot }; - } - - const fetchSubgraphData = async (subgraphUrl, query, processFunction, key, pageLimit) => { - let next_page = 0; - while (next_page < pageLimit) { - query[key].__args.skip = next_page * QUERY_LIMIT; - const response = await subgraphRequest(subgraphUrl, query); - const data = response[Object.keys(response)[0]]; - - processFunction(data); - - if (data.length < QUERY_LIMIT) break; - next_page++; - } - }; - - const processProtocolData = (portfolios) => { - portfolios.forEach((portfolio) => { - const userAddress = getAddress(portfolio.user.id); - allAddressesScoreMap[userAddress] += parseFloat(formatUnits(portfolio.unstakedBalance, MOXIE_DECIMALS)) * UNSTAKED_FAN_TOKEN_MULTIPLIER * portfolio.subjectToken.currentPriceInMoxie + - parseFloat(formatUnits(portfolio.stakedBalance, MOXIE_DECIMALS)) * STAKED_FAN_TOKEN_MULTIPLIER * portfolio.subjectToken.currentPriceInMoxie; - }); - }; - - const processLiquidityPoolData = (userPools) => { - userPools.forEach((userPool) => { - const userAddress = getAddress(userPool.user.id); - allAddressesScoreMap[userAddress] += MOXIE_LIQUIDITY_MULTIPLIER * parseFloat(formatUnits(userPool.totalLPAmount, MOXIE_DECIMALS)) * - parseFloat(formatUnits(userPool.pool.moxieReserve, MOXIE_DECIMALS)) / - parseFloat(formatUnits(userPool.pool.totalSupply, MOXIE_DECIMALS)); - }); - }; - - // RPC Call to get balance of Moxie at a block for users - const fetchBalances = async () => { - const multi = new Multicaller(network, provider, abi, { blockTag }); - allAddresses.forEach((address) => - multi.call(address, MOXIE_CONTRACT_ADDRESS, 'balanceOf', [address]) - ); - const result: Record = await multi.execute(); - Object.entries(result).forEach(([address, balance]) => { - let formattedBalance = parseFloat(formatUnits(balance, MOXIE_DECIMALS)); - allAddressesScoreMap[getAddress(address)] += formattedBalance; - }); - }; - - // Fetch data from both subgraphs in parallel - await Promise.all([ - fetchSubgraphData(MOXIE_PROTOCOL_SUBGRAPH_URL, protocolSubgraphQuery, processProtocolData, "portfolios", PORTFOLIO_SUBGRAPH_PAGE_LIMIT), - fetchSubgraphData(MOXIE_LIQUIDITY_POOL_SUBGRAPH_URL, liquidityPoolSubgraphQuery, processLiquidityPoolData, "userPools", LIQUIDITY_POOL_SUBGRAPH_PAGE_LIMIT), - fetchBalances(), - ]); - - // Now we have the score for each address we need to ensure it is added to the beneficiary address if it exists - Object.keys(allAddressesScoreMap).forEach((address) => { - const beneficiary = addressToBeneficiaryMap[address.toLowerCase()]; - if (beneficiary) { - addressesMap[getAddress(beneficiary)] += allAddressesScoreMap[address]; - } else { - addressesMap[address] += allAddressesScoreMap[address]; + const response = await customFetch(buildURL(addresses, snapshot), { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + 'x-airstack-protocol': MOXIE_API_KEY } }); - return addressesMap; -} \ No newline at end of file + const votes = await response.json(); + + return votes.scores; +} From 6ee94e796cea11332c45bb1a5db307e161bed5a7 Mon Sep 17 00:00:00 2001 From: 0xsarvesh Date: Fri, 25 Oct 2024 16:17:50 +0530 Subject: [PATCH 3/4] Updated to post request to handle upto 500 addresses --- src/strategies/moxie/index.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/strategies/moxie/index.ts b/src/strategies/moxie/index.ts index 6bdf503fc..a9bfb5ed8 100644 --- a/src/strategies/moxie/index.ts +++ b/src/strategies/moxie/index.ts @@ -6,12 +6,6 @@ export const version = '0.0.2'; const MOXIE_ENDPOINT = 'https://api.moxie.xyz/protocol/address-votes'; const MOXIE_API_KEY = process.env.MOXIE_API_KEY || ''; -const buildURL = (addresses, snapshot) => { - const addressesParam = addresses.join(','); - const snapshotParam = snapshot ? `&block=${snapshot}` : '&block=latest'; - return `${MOXIE_ENDPOINT}?addresses=${addressesParam}${snapshotParam}`; -}; - //Strategy to Compute Voting Power for MoxieDAO export async function strategy( space, @@ -21,8 +15,12 @@ export async function strategy( options, snapshot ) { - const response = await customFetch(buildURL(addresses, snapshot), { - method: 'GET', + const response = await customFetch(MOXIE_ENDPOINT, { + method: 'POST', + body: JSON.stringify({ + block: snapshot, + addresses + }), headers: { Accept: 'application/json', 'Content-Type': 'application/json', From fd61859948386993f5f24271e48d0210596f098f Mon Sep 17 00:00:00 2001 From: 0xsarvesh Date: Fri, 25 Oct 2024 17:39:20 +0530 Subject: [PATCH 4/4] Changing timeout from 20 to 60 sec --- src/strategies/moxie/index.ts | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/strategies/moxie/index.ts b/src/strategies/moxie/index.ts index a9bfb5ed8..35ee37c48 100644 --- a/src/strategies/moxie/index.ts +++ b/src/strategies/moxie/index.ts @@ -15,18 +15,22 @@ export async function strategy( options, snapshot ) { - const response = await customFetch(MOXIE_ENDPOINT, { - method: 'POST', - body: JSON.stringify({ - block: snapshot, - addresses - }), - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - 'x-airstack-protocol': MOXIE_API_KEY - } - }); + const response = await customFetch( + MOXIE_ENDPOINT, + { + method: 'POST', + body: JSON.stringify({ + block: snapshot, + addresses + }), + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + 'x-airstack-protocol': MOXIE_API_KEY + } + }, + 60000 + ); const votes = await response.json();