@moonwell-fi/moonwell-sdk
Version:
TypeScript Interface for Moonwell
165 lines • 6.52 kB
JavaScript
import axios from "axios";
import { isAddress } from "viem";
import { HttpRequestError } from "../../common/index.js";
import { publicEnvironments, } from "../../environments/index.js";
import * as logger from "../../logger/console.js";
/**
* Returns a list of the delegates from the Moonwell Governance Forum
*
* https://forum.moonwell.fi/c/delegation-pitch/17
*/
export async function getDelegates(client) {
let users = [];
const logId = logger.start("getDelegates", "Starting to get delegates...");
const getUsersPaginated = async (page = 0) => {
const response = await axios.get(`https://forum.moonwell.fi/directory_items.json?period=all&order=Delegate+Wallet+Address&user_field_ids=2%7C1%7C3&page=${page}`);
if (response.status !== 200 || !response.data) {
throw new HttpRequestError(response.statusText);
}
const results = response.data.directory_items
.filter((item) => item.user.user_fields["1"] !== undefined &&
item.user.user_fields["1"].value !== undefined &&
item.user.user_fields["1"].value[0] !== undefined &&
isAddress(item.user.user_fields["1"].value[0]) &&
item.user.user_fields["2"] !== undefined &&
item.user.user_fields["2"].value !== undefined &&
item.user.user_fields["2"].value[0] !== undefined)
.map((item) => {
const avatar = item.user.avatar_template.replace("{size}", "160");
const result = {
avatar: avatar.startsWith("/user_avatar")
? `https://dub1.discourse-cdn.com/flex017${avatar}`
: avatar,
name: item.user.username,
wallet: item.user.user_fields["1"].value[0],
pitch: {
intro: item.user.user_fields["2"].value[0],
url: item.user.user_fields["3"]?.value[0],
},
};
return result;
});
users = users.concat(results);
const loadMore = response.data.directory_items.length > 0;
if (loadMore) {
await getUsersPaginated(page + 1);
}
};
await getUsersPaginated();
//Get how many proposals the delegate have voted for
const proposals = await getDelegatesExtendedData({
users: users.map((r) => r.wallet),
});
//Get delegate voting powers
const envs = Object.values(client.environments).filter((env) => env.contracts.views !== undefined);
const votingPowers = await Promise.all(users.map(async (user) => Promise.all(envs.map((environment) => environment.contracts.views?.read.getUserVotingPower([
user.wallet,
])))));
logger.end(logId);
users = users.map((user, index) => {
let votingPower = {};
const userVotingPowers = votingPowers[index];
if (userVotingPowers) {
votingPower = envs.reduce((prev, curr, reduceIndex) => {
const { claimsVotes, stakingVotes, tokenVotes } = userVotingPowers[reduceIndex];
const totalVotes = claimsVotes.delegatedVotingPower +
stakingVotes.delegatedVotingPower +
tokenVotes.delegatedVotingPower;
return {
...prev,
[curr.chainId]: Number(totalVotes / BigInt(10 ** 18)),
};
}, {});
}
const extended = {
...user,
proposals: proposals[user.wallet.toLowerCase()],
votingPower,
};
return extended;
});
return users;
}
/**
* Helper function to get how many proposals the delegates have created and voted
*/
const getDelegatesExtendedData = async (params) => {
const response = await axios.post(publicEnvironments.moonbeam.governanceIndexerUrl, {
query: `
query {
proposers(where: {id_in: [${params.users.map((r) => `"${r.toLowerCase()}"`).join(",")}]}) {
items {
id
proposals(limit: 1000) {
items {
chainId
proposalId
}
}
}
}
voters(where: {id_in: [${params.users.map((r) => `"${r.toLowerCase()}"`).join(",")}]}) {
items {
id
votes(limit: 1000) {
items {
voter
proposal {
chainId
}
}
}
}
}
}
`,
});
if (response.status === 200 && response.data?.data?.voters) {
const voters = response?.data?.data?.voters?.items.reduce((prev, curr) => {
return {
...prev,
[curr.id.toLowerCase()]: curr.votes.items.reduce((prevVotes, currVotes) => {
const previousVotes = prevVotes[currVotes.proposal.chainId] || 0;
return {
...prevVotes,
[currVotes.proposal.chainId]: previousVotes + 1,
};
}, {}),
};
}, {});
const proposers = response?.data?.data?.proposers?.items.reduce((prev, curr) => {
return {
...prev,
[curr.id.toLowerCase()]: curr.proposals.items.reduce((prevVotes, currVotes) => {
const previousProposed = prevVotes[currVotes.chainId] || 0;
return {
...prevVotes,
[currVotes.chainId]: previousProposed + 1,
};
}, {}),
};
}, {});
return params.users.reduce((prev, curr) => {
const proposalsCreated = proposers[curr.toLowerCase()];
const proposalsVoted = voters[curr.toLowerCase()];
const chains = [
...Object.keys(proposalsCreated || {}),
...Object.keys(proposalsVoted || {}),
];
return {
...prev,
[curr.toLowerCase()]: chains.reduce((prevChain, currChain) => {
return {
...prevChain,
[currChain]: {
created: proposalsCreated?.[currChain] || 0,
voted: proposalsVoted?.[currChain] || 0,
},
};
}, {}),
};
}, {});
}
return {};
};
//# sourceMappingURL=getDelegates.js.map