Fetch all DAO treasury wallets and their holdings.
Given a DAO, we need to fetch its treasury info. In order to do this, we need the DAO's realm address. -
Once we have the realm address, we will fetch all the governance accounts for it.
Treasury wallets are a PDA(program derived address) of governance pubkeys and 'native-treasury' text. Code snippet in the below section.
Once we have the treasury wallets, we use Get Portfolio to fetch Sol, Token balances and NFTs in a single call. You can usr any other approach you want.
Here's a fully working code snippet for you to try out in replit.
Fetch Treasury Info For Grape Dao
// Node doesn't implement fetch so we have to import it
import fetch from "node-fetch";
import { PublicKey } from "@solana/web3.js";
import { promises } from "dns";
const SHYFT_API_KEY = "YOUR-KEY"
async function fetchGraphQL(query, variables = {}, name = "MyQuery") {
const result = await fetch(
`https://programs.shyft.to/v0/graphql/?api_key=${SHYFT_API_KEY}`,
{
method: "POST",
body: JSON.stringify({
query: query,
variables: variables,
operationName: name
})
}
);
return await result.json();
}
async function getGovernanceAccountsForDAO(realmAddress) {
//realms should be an array
const query = `
query MyQuery($_in: [String!] = "") {
GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw_GovernanceV1(
where: {realm: {_eq: ${JSON.stringify(realmAddress)}}}
) {
pubkey
}
GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw_GovernanceV2(
where: {realm: {_eq: ${JSON.stringify(realmAddress)}}}
) {
pubkey
}
}
`
const { errors, data } = await fetchGraphQL(query);
if (errors) {
// handle those errors like a pro
console.error(errors);
}
const govAccts = []
data.GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw_GovernanceV1.forEach((dao) => {
govAccts.push(dao?.pubkey)
})
data.GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw_GovernanceV2.forEach((dao) => {
govAccts.push(dao?.pubkey)
})
console.log(govAccts);
return govAccts;
}
function getNativeTreasuryAddress(governanceAccounts) {
const programId = new PublicKey("GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw")
const treasuryAddress = []
governanceAccounts.forEach(async (governance) => {
const acc = new PublicKey(governance)
const [address] = await PublicKey.findProgramAddress(
[Buffer.from('native-treasury'), acc.toBuffer()],
programId
);
const addy = address.toBase58()
console.log(addy)
treasuryAddress.push(address.toBase58());
})
return treasuryAddress;
}
async function fetchTreasuryInfo(wallets) {
console.time('portfolio')
const promises = []
//Once we have the treasury wallets, we can fetch their holdings
wallets.map(async (wallet) => {
promises.push(getPortfolio(wallet))
})
return await Promise.all(promises);
}
async function getPortfolio(wallet) {
try {
console.log('fetching portfolio for ', wallet)
const result = await fetch(
`https://api.shyft.to/sol/v1/wallet/get_portfolio?network=mainnet-beta&wallet=${wallet}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
"x-api-key": SHYFT_API_KEY
},
}
);
const res = await result.json()
return res;
} catch (err) {
console.error(err)
}
}
async function getDaoTreasury(realmAddress) {
//Get governance accounts for all realms
const governanceAccounts = await getGovernanceAccountsForDAO(realmAddress);
console.log('gov accounts fetched');
const treasuryWallets = await getNativeTreasuryAddress(governanceAccounts);
console.log('treasury wallets: ', treasuryWallets);
return await fetchTreasuryInfo(treasuryWallets);
}
//Grape DAO treasury
const treasury = await getDaoTreasury("By2sVGZXwfQq6rAiAM3rNPJ9iQfb5e2QhnF4YjJ4Bip");
console.dir(treasury, {depth: null})