npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@realms-today/sowell-governance

v0.2.11

Published

TypeScript SDK for sowell-gov governance program

Downloads

1,463

Readme

@sowell/governance-sdk

TypeScript SDK for the sowell-gov on-chain governance program.

Install

yarn add @sowell/governance-sdk @solana/web3.js

Quick start

import {
  createProposalWithTransactionsInstruction,
  getGovernanceAddress,
  getProposalAddress,
  setProgramId,
} from "@sowell/governance-sdk";
import { PublicKey } from "@solana/web3.js";

setProgramId(new PublicKey("YourProgramId..."));

Instructions

All 18 instruction builders return a TransactionInstruction ready to send.

| # | Function | Description | |---|----------|-------------| | 0 | createRealmInstruction | Create a new realm (DAO) | | 1 | depositGoverningTokensInstruction | Deposit tokens to get voting power | | 2 | withdrawGoverningTokensInstruction | Withdraw deposited tokens | | 3 | createGovernanceInstruction | Create a governance over an account | | 4 | createProposalInstruction | Create a bare proposal (legacy) | | 5 | insertTransactionInstruction | Attach a transaction to a proposal | | 6 | castVoteInstruction | Cast a vote on a proposal | | 7 | relinquishVoteInstruction | Withdraw a vote | | 8 | executeTransactionInstruction | Execute an approved proposal's transaction | | 9 | setGovernanceConfigInstruction | Update governance config (via proposal) | | 10 | setRealmAuthorityInstruction | Transfer/remove realm authority | | 11 | setRealmConfigInstruction | Update realm settings | | 12 | createTokenOwnerRecordInstruction | Create a TOR without depositing | | 13 | createNativeTreasuryInstruction | Create the native SOL treasury PDA | | 14 | refundProposalDepositInstruction | Reclaim proposal deposit after completion | | 15 | createProposalWithTransactionsInstruction | Atomic proposal + transactions + vote | | 16 | setGovernanceLimitsInstruction | Set per-mint spending limits | | 17 | closeProposalInstruction | Cancel/finalize/dispose a proposal |

Key workflows

One-shot proposal (create + vote in a single tx)

createProposalWithTransactionsInstruction is the primary instruction for fast treasury operations. It batches up to four steps in one instruction:

  1. Create proposal (always SingleChoice with deny option)
  2. Attach N transactions (each with holdUpTime + instructions)
  3. Enter voting (finalize: true)
  4. Cast an approve vote (vote: true, implies finalize)
import {
  createProposalWithTransactionsInstruction,
  ProposalTransactionInput,
  InstructionData,
} from "@sowell/governance-sdk";

const tx: InstructionData = {
  programId: SystemProgram.programId,
  accounts: [
    { pubkey: treasuryPda, isSigner: true, isWritable: true },
    { pubkey: destination, isSigner: false, isWritable: true },
  ],
  data: transferInstructionData,
};

const ix = createProposalWithTransactionsInstruction({
  programId,
  realm,
  governance,
  proposalOwnerRecord: tokenOwnerRecord,
  governingTokenMint: communityMint,
  governanceAuthority: wallet.publicKey,
  payer: wallet.publicKey,
  name: "Transfer 5 SOL",
  descriptionLink: "https://...",
  proposalSeed: Keypair.generate().publicKey,
  transactions: [{ holdUpTime: 0, instructions: [tx] }],
  finalize: true, // Draft -> Voting
  vote: true,     // also cast an Approve vote (implies finalize)
  // maxVotingTime: 3600,  // optional: override governance default (can only extend)
  // voterWeightRecord,    // optional: voter weight addin
  // maxVoterWeightRecord, // optional: max voter weight addin
});

Tips:

  • vote: true implies finalize: true -- you don't need to set both
  • If the voter has enough weight to tip the vote (e.g. >60% under Early tipping), the proposal immediately transitions to Succeeded within the same instruction
  • holdUpTime: 0 means the transaction is executable immediately after the vote passes (after 1 slot)
  • proposalSeed must be unique per proposal -- use Keypair.generate().publicKey
  • Max ~4 SOL-transfer-sized transactions fit in a single instruction due to Solana's 1232-byte tx limit

Execute a succeeded proposal

import {
  executeTransactionInstruction,
  getProposalTransactionAddress,
  getGovernanceLimitsAddress,
} from "@sowell/governance-sdk";

const txPda = getProposalTransactionAddress(programId, proposal, 0, 0);

const ix = executeTransactionInstruction({
  programId,
  governance,
  proposal,
  proposalTransaction: txPda,
  instructionAccounts: [
    // accounts required by the inner CPI, in order
    { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
    { pubkey: treasuryPda, isSigner: false, isWritable: true },
    { pubkey: destination, isSigner: false, isWritable: true },
  ],
  // Pass this to enforce spending limits (required when governance has limits set)
  governanceLimits: getGovernanceLimitsAddress(programId, governance),
});

Close / cancel a proposal

closeProposalInstruction is a unified instruction that handles cancellation, finalization, and account disposal (reclaims rent).

const ix = closeProposalInstruction({
  programId,
  realm,
  governance,
  proposal,
  proposalOwnerRecord: tokenOwnerRecord,
  governingTokenMint: communityMint,
  authority: wallet.publicKey,
  beneficiary: wallet.publicKey, // receives reclaimed rent
  proposalTransactions: [txPda1, txPda2], // must pass ALL transaction PDAs
});

Who can close:

| Proposal state | Who | Outcome | |---|---|---| | Completed, Cancelled, Defeated, Vetoed | Anyone | Dispose (reclaim rent) | | Draft, SigningOff | Owner/delegate | Cancel + dispose | | Voting (active) | Owner/delegate | Cancel + dispose | | Voting (expired) | Anyone | Finalize vote; dispose if Defeated/Vetoed | | Succeeded, Executing, ExecutingWithErrors | No one | Must execute txns or expire |

Spending limits

Set per-mint caps on how much a governance can spend per ExecuteTransaction:

import {
  setGovernanceLimitsInstruction,
  MintSpendingLimit,
  NATIVE_SOL_MINT,
  SpendingLimitTypeKind,
} from "@sowell/governance-sdk";

const limits: MintSpendingLimit[] = [
  { mint: usdcMint, limit: { kind: SpendingLimitTypeKind.Absolute, amount: 1_000_000_000n } },
  { mint: NATIVE_SOL_MINT, limit: { kind: SpendingLimitTypeKind.Bps, bps: 500 } }, // 5% of balance
];

const ix = setGovernanceLimitsInstruction(
  programId,
  governance,
  realm,
  realmAuthority,  // or governance PDA (via proposal)
  payer,
  limits,
);

Tips:

  • NATIVE_SOL_MINT (PublicKey.default) is the sentinel for native SOL limits
  • BPS values are basis points: 10000 = 100%, 500 = 5%
  • BPS limits are per-execution against the current balance (not the original)
  • Pass an empty limits array to clear all limits and unset the has_spending_limits flag
  • Once limits are set, executeTransactionInstruction must include the governanceLimits PDA

Account decoders

Deserialize on-chain account data into typed objects. Pass the raw Buffer from connection.getAccountInfo().

import {
  decodeRealm,
  decodeGovernance,
  decodeProposal,
  decodeTokenOwnerRecord,
  decodeVoteRecord,
  decodeProposalTransaction,
  decodeRealmConfig,
  decodeProposalDeposit,
  decodeGovernanceLimits,
} from "@sowell/governance-sdk";

const info = await connection.getAccountInfo(proposalAddress);
const proposal = decodeProposal(info.data);
console.log(proposal.state);    // ProposalState enum
console.log(proposal.name);
console.log(proposal.options);  // ProposalOption[]

Account fetchers

Fetch and decode governance accounts in one call:

import {
  fetchRealm,
  fetchGovernance,
  fetchProposal,
  fetchTokenOwnerRecord,
  fetchVoteRecord,
  fetchAccount,
  fetchAccounts,
  AccountNotFoundError,
} from "@sowell/governance-sdk";

const realm = await fetchRealm(connection, realmAddress);
const proposal = await fetchProposal(connection, proposalAddress, {
  throwIfMissing: false, // returns null instead of throwing
});

try {
  const governance = await fetchGovernance(connection, governanceAddress);
  console.log(governance.sowellian.betEnabled);
} catch (e) {
  if (e instanceof AccountNotFoundError) {
    console.log("Governance account does not exist yet");
  }
}

Available typed fetchers:

  • fetchRealm
  • fetchGovernance
  • fetchProposal
  • fetchProposalTransaction
  • fetchTokenOwnerRecord
  • fetchVoteRecord
  • fetchRealmConfig
  • fetchProposalDeposit
  • fetchGovernanceLimits
  • fetchSowellianConfig
  • fetchBet
  • fetchSecondaryMarket
  • fetchReceipt

Governance query APIs (Oyster-style)

For indexer and UI-style queries, use the get* APIs:

import {
  getRealms,
  getAllGovernances,
  getProposalsByGovernance,
  getGovernanceAccounts,
  pubkeyFilter,
  decodeProposal,
  GovernanceAccountType,
} from "@sowell/governance-sdk";

const realms = await getRealms(connection, programId);
const governances = await getAllGovernances(connection, programId, realmPk);
const proposals = await getProposalsByGovernance(connection, programId, governancePk);

const custom = await getGovernanceAccounts(
  connection,
  programId,
  decodeProposal,
  GovernanceAccountType.Proposal,
  [pubkeyFilter(1, governancePk)!]
);

Included helpers:

  • getGovernanceAccounts
  • getGovernanceAccount
  • tryGetGovernanceAccount
  • getRealm, getRealms
  • getRealmConfig, tryGetRealmConfig
  • getVoteRecord, getVoteRecordsByVoter
  • getTokenOwnerRecord, getTokenOwnerRecordForRealm, getTokenOwnerRecordsByOwner, getAllTokenOwnerRecords
  • getGovernance, getAllGovernances
  • getProposal, getProposalsByGovernance, getAllProposals
  • getProposalDepositsByDepositPayer
  • pubkeyFilter

PDA derivation

All 14 PDA helpers follow the pattern get*Address(programId, ...seeds): PublicKey.

import {
  getRealmAddress,
  getGovernanceAddress,
  getTokenOwnerRecordAddress,
  getProposalAddress,
  getProposalTransactionAddress,
  getVoteRecordAddress,
  getNativeTreasuryAddress,
  getGovernanceLimitsAddress,
  getGoverningTokenHoldingAddress,
  getRealmConfigAddress,
  getProposalDepositAddress,
  getProgramGovernanceAddress,
  getMintGovernanceAddress,
  getTokenGovernanceAddress,
} from "@sowell/governance-sdk";

const realm = getRealmAddress(programId, "My DAO");
const governance = getGovernanceAddress(programId, realm, governedAccount);
const treasury = getNativeTreasuryAddress(programId, governance);
const limits = getGovernanceLimitsAddress(programId, governance);
const proposal = getProposalAddress(programId, governance, mint, seed);
const txPda = getProposalTransactionAddress(programId, proposal, 0, 0);

Instruction decoder (for indexers)

Parse raw instruction data into typed discriminated unions:

import { decodeGovernanceInstruction, getInstructionName } from "@sowell/governance-sdk";

const decoded = decodeGovernanceInstruction(instructionData);
if (decoded && decoded.instruction === 15) {
  // CreateProposalWithTransactions
  console.log(decoded.name, decoded.finalize, decoded.vote);
}

getInstructionName(6); // "CastVote"

Error handling

Parse custom program errors from transaction failures:

import {
  parseGovernanceError,
  isGovernanceError,
  getGovernanceErrorName,
  getGovernanceErrorMessage,
} from "@sowell/governance-sdk";

// From a failed transaction's error code:
const err = parseGovernanceError(604);
// { code: 604, name: "SpendingLimitExceeded", message: "Treasury spending limit breached" }

isGovernanceError(604);          // true
getGovernanceErrorName(604);     // "SpendingLimitExceeded"
getGovernanceErrorMessage(604);  // "Treasury spending limit breached"

Error codes range from 500-606. Key ones:

| Code | Name | When | |---|---|---| | 500 | InvalidInstruction | Unrecognized instruction discriminant | | 503 | InvalidGoverningTokenMint | Wrong mint for the governance | | 509 | InvalidProposalState | Operation not valid for current proposal state | | 548 | VoteWeightSourceNotAllowed | Voter weight addin check failed | | 602 | MathematicalOverflow | Arithmetic overflow | | 603 | InvalidMaxVotingTime | maxVotingTime below votingBaseTime | | 604 | SpendingLimitExceeded | Transaction exceeds treasury spending limit | | 605 | InvalidGovernanceLimitsAccount | Wrong or invalid GovernanceLimits PDA | | 606 | InvalidCloseProposalState | Invalid state for CloseProposal |

Enums

All state enums are exported for matching against decoded account data:

import {
  ProposalState,
  VoteTipping,
  VoteThresholdType,
  VoteKind,
  SpendingLimitTypeKind,
  GovernanceAccountType,
  TransactionExecutionStatus,
  GovernanceInstruction,
} from "@sowell/governance-sdk";

| Enum | Values | |---|---| | ProposalState | Draft, SigningOff, Voting, Succeeded, Executing, Completed, Cancelled, Defeated, ExecutingWithErrors, Vetoed | | VoteTipping | Strict, Early, Disabled | | VoteThresholdType | YesVotePercentage, Disabled | | VoteKind | Approve, Deny, Veto | | SpendingLimitTypeKind | Absolute, Bps | | GovernanceInstruction | 0-17, maps to all 18 instructions |

Testing

yarn test        # run all tests
yarn test:watch  # watch mode
yarn build       # compile TypeScript

Tests use LiteSVM for fast in-process Solana program testing.

License

Apache-2.0