Get All Active Proposals For Wallet

Fetch all active proposals that a wallet can vote on.

We will fetch all active proposals that a user can vote on. For this we will need to do following steps

  • Find out how many DAOs the wallet is part of from TokenOwnerRecordV1 and TokenOwnerRecordV2.

  • Find all governance accounts for the DAOs (realm address) from GovernanceV1 and GovernanceV2 accounts. We use the _in operator to pass in an array of realms in a single call.

  • Find all proposals where state = 2 for all the governance accounts. We again use the _in operator to pass in an array of governance accounts in a single call.

Here is a code snippet for you to try it out in replit.

// Node doesn't implement fetch so we have to import it
import fetch from "node-fetch";

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();
}

//We only fetch realm field, since thats what we are interested in
async function getRealmsForWallet(wallet) {
  const query = `
    query MyQuery {
      GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw_TokenOwnerRecordV1(
        where: {governingTokenOwner: {_eq: ${JSON.stringify(wallet)}}}
      ) {
        realm
      }
      GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw_TokenOwnerRecordV2(
        where: {governingTokenOwner: {_eq: ${JSON.stringify(wallet)}}}
      ) {
        realm
      }
    }
  `;

  const { errors, data } = await fetchGraphQL(query);

  if (errors) {
    // handle those errors like a pro
    console.error(errors);
  }

  const realms = []
    data.GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw_TokenOwnerRecordV1.forEach((dao) => {
      realms.push(dao.realm)
    })
  
    data.GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw_TokenOwnerRecordV2.forEach((dao) => {
      realms.push(dao.realm)
    })

  console.log(`Wallet is part of ${realms.length} DAOs`);
  
  // do something great with this precious data
  return realms;
}

async function getGovernanceAccountsForAllRealms(realms) {
  
  //realms should be an array
  const query = `
  query MyQuery($_in: [String!] = "") {
  GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw_GovernanceV1(
    where: {realm: {_in: $_in}}
  ) {
    pubkey
  }
  GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw_GovernanceV2(
    where: {realm: {_in: $_in}}
  ) {
    pubkey
  }
}
`

  const variables = {
    _in: realms
  }

  const { errors, data } = await fetchGraphQL(query, variables);

  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;
}

async function getActiveProposals(governanceAccounts) {
  //governanceAccounts should be an array
  const query = `
  query MyQuery($_in: [String!] = "") {
  GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw_ProposalV1(
    where: {_and: {state: {_eq: 2}, governance: {_in: $_in}}}
  ) {
    closedAt
    descriptionLink
    draftAt
    executingAt
    executionFlags
    governance
    governingTokenMint
    instructionsCount
    instructionsExecutedCount
    instructionsNextIndex
    lamports
    maxVoteWeight
    name
    noVotesCount
    signatoriesCount
    signatoriesSignedOffCount
    signingOffAt
    state
    tokenOwnerRecord
    voteThreshold
    votingAt
    votingAtSlot
    votingCompletedAt
    yesVotesCount
  }
  GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw_ProposalV2(
    where: {_and: {state: {_eq: 2}, governance: {_in: $_in}}}
  ) {
    abstainVoteWeight  
    closedAt
    denyVoteWeight
    descriptionLink
    draftAt
    executingAt
    executionFlags
    governance
    governingTokenMint
    lamports
    maxVoteWeight
    maxVotingTime
    name
    options
    reserved1
    signatoriesCount
    signatoriesSignedOffCount
    signingOffAt
    startVotingAt
    state
    tokenOwnerRecord
    vetoVoteWeight
    voteThreshold
    voteType
    votingAt
    votingAtSlot
    votingCompletedAt
  }
}
`

  const variables = {
    _in: governanceAccounts
  }

  const { errors, data } = await fetchGraphQL(query, variables);

  if (errors) {
    // handle those errors like a pro
    console.error(errors);
  }

  // do something great with this precious data
  console.log(data);

  return data;
}

//Get DAOs for a wallet
const realms = await getRealmsForWallet("JPQmr9p2RF3X5TuBXxn6AGcEfcsHp4ehcmzE5Ys7pZD")


//Get governance accounts for all realms
const governanceAccounts = await getGovernanceAccountsForAllRealms(realms);
const proposals = await getActiveProposals(governanceAccounts);

console.log(proposals)

Last updated