Governance Transactions
Participate in Cardano's on-chain governance through DRep delegation, registration, voting, and submitting governance action proposals.
Overview
Cardano's on-chain governance system (CIP-1694) enables the community to vote on proposals and protocol updates. Mesh SDK implements the CIP-95 Web-Wallet Bridge extension, allowing dApps to interact with governance features. You can delegate your voting power to Decentralized Representatives (DReps), register as a DRep yourself, vote on governance actions, and submit new governance action proposals.
When to use this:
- Delegating your voting power to a DRep
- Registering as a DRep to represent other voters
- Voting on governance actions and protocol changes
- Submitting governance action proposals (info actions, parameter changes, treasury withdrawals, etc.)
- Building governance dashboards and tools
- Creating DRep management applications
Quick Start
import { MeshTxBuilder, BlockfrostProvider } from "@meshsdk/core";
// Initialize
const provider = new BlockfrostProvider("<YOUR_API_KEY>");
const txBuilder = new MeshTxBuilder({
fetcher: provider,
verbose: true,
});
// Get wallet data
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
const rewardAddresses = await wallet.getRewardAddresses();
const rewardAddress = rewardAddresses[0]!;
// Delegate to a DRep
txBuilder
.voteDelegationCertificate(
{ dRepId: "drep1yv4uesaj92wk8ljlsh4p7jzndnzrflchaz5fzug3zxg4naqkpeas3" },
rewardAddress
)
.changeAddress(changeAddress)
.selectUtxosFrom(utxos);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);API Reference
voteDelegationCertificate()
Delegate voting power to a DRep.
.voteDelegationCertificate(drep: DRepId, rewardAddress: string)| Parameter | Type | Description |
|---|---|---|
drep | DRepId | DRep identifier object |
rewardAddress | string | Your stake/reward address |
The DRepId object can specify:
{ dRepId: "drep1..." }- Delegate to a specific DRep{ alwaysAbstain: true }- Always abstain from voting{ alwaysNoConfidence: true }- Always vote no confidence
drepRegistrationCertificate()
Register as a DRep.
.drepRegistrationCertificate(dRepId: string, anchor?: Anchor)| Parameter | Type | Description |
|---|---|---|
dRepId | string | Your DRep ID (from wallet) |
anchor | Anchor | Optional metadata anchor |
The Anchor object:
{
anchorUrl: string; // URL to metadata JSON
anchorDataHash: string; // Hash of metadata content
}drepUpdateCertificate()
Update DRep metadata.
.drepUpdateCertificate(dRepId: string, anchor?: Anchor)| Parameter | Type | Description |
|---|---|---|
dRepId | string | Your DRep ID |
anchor | Anchor | New metadata anchor |
drepDeregistrationCertificate()
Retire as a DRep and reclaim deposit.
.drepDeregistrationCertificate(dRepId: string)| Parameter | Type | Description |
|---|---|---|
dRepId | string | Your DRep ID to retire |
vote()
Cast a vote on a governance action.
.vote(voter: Voter, govActionId: GovActionId, votingProcedure: VotingProcedure)| Parameter | Type | Description |
|---|---|---|
voter | Voter | Voter identity |
govActionId | GovActionId | Governance action reference |
votingProcedure | VotingProcedure | Vote details |
The Voter object:
// DRep voter
{ type: "DRep", drepId: "drep1..." }
// Stake pool operator
{ type: "StakePool", poolId: "pool1..." }
// Constitutional committee member
{ type: "ConstitutionalCommittee", hotCred: "..." }The VotingProcedure object:
{
voteKind: "Yes" | "No" | "Abstain";
anchor?: {
anchorUrl: string;
anchorDataHash: string;
};
}votePlutusScriptV3()
Indicate voting with a Plutus script.
.votePlutusScriptV3()voteScript()
Provide the voting script.
.voteScript(scriptCbor: string)voteRedeemerValue()
Provide the redeemer for script-based voting.
.voteRedeemerValue(redeemer: Data | object | string, type?: "Mesh" | "CBOR" | "JSON", exUnits?: Budget)proposal()
Submit a governance action proposal. Requires a deposit (returned when the action is resolved).
.proposal(governanceAction: GovernanceAction, anchor: Anchor, rewardAccount: string, deposit?: string)| Parameter | Type | Description |
|---|---|---|
governanceAction | GovernanceAction | The governance action to propose |
anchor | Anchor | Proposal metadata anchor (URL + hash) |
rewardAccount | string | Reward address for deposit return |
deposit | string | Deposit amount in lovelace (defaults to "100000000000", i.e. 100,000 ADA) |
The GovernanceAction is a discriminated union with a kind and action field:
// Info action (no on-chain effect, used for polls/sentiment)
{ kind: "InfoAction", action: {} }
// Protocol parameter change
{
kind: "ParameterChangeAction",
action: {
govActionId?: { transactionId: string; govActionIndex: number },
protocolParamUpdates: ProtocolParamUpdate,
policyHash?: { bytes: string },
}
}
// Treasury withdrawal
{
kind: "TreasuryWithdrawalsAction",
action: {
withdrawals: Record<string, string>, // reward address -> lovelace amount
policyHash?: { bytes: string },
}
}
// No confidence in current committee
{
kind: "NoConfidenceAction",
action: {
govActionId?: { transactionId: string; govActionIndex: number },
}
}
// Update constitutional committee
{
kind: "UpdateCommitteeAction",
action: {
govActionId?: { transactionId: string; govActionIndex: number },
committee: {
members: Array<{ stakeCredential: Credential; termLimit: number }>,
quorumThreshold: { numerator: string; denominator: string },
},
membersToRemove: Credential[],
}
}
// New constitution
{
kind: "NewConstitutionAction",
action: {
govActionId?: { transactionId: string; govActionIndex: number },
constitution: {
anchor: Anchor,
scriptHash?: { bytes: string },
},
}
}
// Hard fork initiation
{
kind: "HardForkInitiationAction",
action: {
govActionId?: { transactionId: string; govActionIndex: number },
protocolVersion: { major: number; minor: number },
}
}The Credential type used in committee actions:
{ type: "KeyHash", keyHash: string }
// or
{ type: "ScriptHash", scriptHash: string }The govActionId field is optional and refers to the most recently enacted governance action of the same type that this proposal builds upon. It is required for action types that must chain from a previous action (parameter changes, hard forks, committee updates, no confidence, new constitution).
proposalScript()
Attach a Plutus script witness to the proposal.
.proposalScript(scriptCbor: string, version: "V1" | "V2" | "V3")| Parameter | Type | Description |
|---|---|---|
scriptCbor | string | CBOR hex of the Plutus script |
version | LanguageVersion | Plutus language version |
proposalTxInReference()
Use a reference script for the proposal instead of providing it inline.
.proposalTxInReference(txHash: string, txIndex: number, scriptSize: string, scriptHash: string, version: "V1" | "V2" | "V3")| Parameter | Type | Description |
|---|---|---|
txHash | string | Transaction hash of the reference UTxO |
txIndex | number | Transaction index of the reference UTxO |
scriptSize | string | Size of the Plutus script in bytes |
scriptHash | string | Script hash of the referenced script |
version | LanguageVersion | Plutus language version |
proposalRedeemerValue()
Provide the redeemer for a Plutus script proposal.
.proposalRedeemerValue(redeemer: Data | object | string, type?: "Mesh" | "CBOR" | "JSON", exUnits?: Budget)| Parameter | Type | Description |
|---|---|---|
redeemer | Data | object | string | Redeemer data |
type | string | Data format type (default "Mesh") |
exUnits | Budget | Execution units budget (default { mem: 7_000_000, steps: 3_000_000_000 }) |
Common Patterns
Delegate to a DRep
Delegate your voting power to a registered DRep:
import { MeshTxBuilder, BlockfrostProvider } from "@meshsdk/core";
const provider = new BlockfrostProvider("<YOUR_API_KEY>");
const txBuilder = new MeshTxBuilder({
fetcher: provider,
verbose: true,
});
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
const rewardAddresses = await wallet.getRewardAddresses();
const rewardAddress = rewardAddresses[0]!;
const dRepId = "drep1yv4uesaj92wk8ljlsh4p7jzndnzrflchaz5fzug3zxg4naqkpeas3";
txBuilder
.voteDelegationCertificate({ dRepId }, rewardAddress)
.changeAddress(changeAddress)
.selectUtxosFrom(utxos);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
console.log(`Delegated to DRep: ${txHash}`);Delegate to Always Abstain
Configure your stake to always abstain from voting:
import { MeshTxBuilder, BlockfrostProvider } from "@meshsdk/core";
const provider = new BlockfrostProvider("<YOUR_API_KEY>");
const txBuilder = new MeshTxBuilder({
fetcher: provider,
verbose: true,
});
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
const rewardAddresses = await wallet.getRewardAddresses();
const rewardAddress = rewardAddresses[0]!;
txBuilder
.voteDelegationCertificate({ alwaysAbstain: true }, rewardAddress)
.changeAddress(changeAddress)
.selectUtxosFrom(utxos);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);Register as a DRep
Register yourself as a DRep with metadata:
import { MeshTxBuilder, BlockfrostProvider, hashDrepAnchor } from "@meshsdk/core";
const provider = new BlockfrostProvider("<YOUR_API_KEY>");
const txBuilder = new MeshTxBuilder({
fetcher: provider,
verbose: true,
});
// Get DRep ID from wallet
const dRep = await wallet.getDRep();
const dRepId = dRep.dRepIDCip105;
// Prepare metadata anchor
const anchorUrl = "https://example.com/drep-metadata.jsonld";
const anchorMetadata = {
"@context": {
"@language": "en",
"CIP100": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md",
"CIP119": "https://github.com/cardano-foundation/CIPs/blob/master/CIP-0119/README.md",
"hashAlgorithm": "CIP100:hashAlgorithm",
"body": { "@id": "CIP119:body" },
"givenName": "CIP119:givenName"
},
"hashAlgorithm": "blake2b-256",
"body": {
"givenName": "My DRep Name"
}
};
const anchorHash = hashDrepAnchor(anchorMetadata);
// Get wallet data
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
txBuilder
.drepRegistrationCertificate(dRepId, {
anchorUrl,
anchorDataHash: anchorHash,
})
.changeAddress(changeAddress)
.selectUtxosFrom(utxos);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
console.log(`DRep registered: ${txHash}`);Update DRep Metadata
Update your DRep profile information:
import { MeshTxBuilder, BlockfrostProvider, hashDrepAnchor } from "@meshsdk/core";
const provider = new BlockfrostProvider("<YOUR_API_KEY>");
const txBuilder = new MeshTxBuilder({
fetcher: provider,
verbose: true,
});
const dRep = await wallet.getDRep();
const dRepId = dRep.dRepIDCip105;
// New metadata
const anchorUrl = "https://example.com/drep-metadata-v2.jsonld";
const anchorMetadata = { /* updated metadata */ };
const anchorHash = hashDrepAnchor(anchorMetadata);
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
txBuilder
.drepUpdateCertificate(dRepId, {
anchorUrl,
anchorDataHash: anchorHash,
})
.changeAddress(changeAddress)
.selectUtxosFrom(utxos);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
console.log(`DRep updated: ${txHash}`);Retire as DRep
Retire from being a DRep and reclaim your deposit:
import { MeshTxBuilder, BlockfrostProvider } from "@meshsdk/core";
const provider = new BlockfrostProvider("<YOUR_API_KEY>");
const txBuilder = new MeshTxBuilder({
fetcher: provider,
verbose: true,
});
const dRep = await wallet.getDRep();
const dRepId = dRep.dRepIDCip105;
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
txBuilder
.drepDeregistrationCertificate(dRepId)
.selectUtxosFrom(utxos)
.changeAddress(changeAddress);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
console.log(`DRep retired: ${txHash}`);Vote on Governance Action
Cast a vote as a DRep:
import { MeshTxBuilder, BlockfrostProvider } from "@meshsdk/core";
const provider = new BlockfrostProvider("<YOUR_API_KEY>");
const txBuilder = new MeshTxBuilder({
fetcher: provider,
verbose: true,
});
const dRep = await wallet.getDRep();
const dRepId = dRep.dRepIDCip105;
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
// Governance action to vote on
const govActionTxHash = "aff2909f8175ee02a8c1bf96ff516685d25bf0c6b95aac91f4dfd53a5c0867cc";
const govActionIndex = 0;
txBuilder
.vote(
{
type: "DRep",
drepId: dRepId,
},
{
txHash: govActionTxHash,
txIndex: govActionIndex,
},
{
voteKind: "Yes",
}
)
.selectUtxosFrom(utxos)
.changeAddress(changeAddress);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
console.log(`Vote cast: ${txHash}`);Vote with Rationale
Include reasoning for your vote:
import { MeshTxBuilder, BlockfrostProvider, hashDrepAnchor } from "@meshsdk/core";
const provider = new BlockfrostProvider("<YOUR_API_KEY>");
const txBuilder = new MeshTxBuilder({
fetcher: provider,
verbose: true,
});
const dRep = await wallet.getDRep();
const dRepId = dRep.dRepIDCip105;
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
// Prepare vote rationale
const rationaleUrl = "https://example.com/vote-rationale.jsonld";
const rationaleContent = {
rationale: "I support this proposal because...",
references: ["https://example.com/supporting-doc"],
};
const rationaleHash = hashDrepAnchor(rationaleContent);
txBuilder
.vote(
{
type: "DRep",
drepId: dRepId,
},
{
txHash: "abc123...",
txIndex: 0,
},
{
voteKind: "Yes",
anchor: {
anchorUrl: rationaleUrl,
anchorDataHash: rationaleHash,
},
}
)
.selectUtxosFrom(utxos)
.changeAddress(changeAddress);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);Vote with Plutus Script
Vote using a Plutus script DRep:
import {
MeshTxBuilder,
BlockfrostProvider,
resolveScriptHash,
resolveScriptHashDRepId,
applyCborEncoding
} from "@meshsdk/core";
const provider = new BlockfrostProvider("<YOUR_API_KEY>");
const txBuilder = new MeshTxBuilder({
fetcher: provider,
verbose: true,
});
const utxos = await wallet.getUtxos();
const collateral = await wallet.getCollateral();
const changeAddress = await wallet.getChangeAddress();
// Your voting script
const votingScriptCbor = applyCborEncoding("your-voting-script-cbor");
const scriptHash = resolveScriptHash(votingScriptCbor, "V3");
const scriptDRepId = resolveScriptHashDRepId(scriptHash);
txBuilder
.txIn(
utxos[0]!.input.txHash,
utxos[0]!.input.outputIndex,
utxos[0]!.output.amount,
utxos[0]!.output.address
)
.txInCollateral(
collateral[0]!.input.txHash,
collateral[0]!.input.outputIndex,
collateral[0]!.output.amount,
collateral[0]!.output.address
)
.votePlutusScriptV3()
.vote(
{
type: "DRep",
drepId: scriptDRepId,
},
{
txHash: "abc123...",
txIndex: 0,
},
{
voteKind: "Yes",
}
)
.voteScript(votingScriptCbor)
.voteRedeemerValue("")
.changeAddress(changeAddress);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx, true);
const txHash = await wallet.submitTx(signedTx);Submit an Info Action
Submit an info action (used for polls and sentiment checks — has no on-chain effect):
import { MeshTxBuilder, BlockfrostProvider } from "@meshsdk/core";
const provider = new BlockfrostProvider("<YOUR_API_KEY>");
const txBuilder = new MeshTxBuilder({
fetcher: provider,
verbose: true,
});
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
const rewardAddresses = await wallet.getRewardAddresses();
const rewardAddress = rewardAddresses[0]!;
txBuilder
.proposal(
{
kind: "InfoAction",
action: {},
},
{
anchorUrl: "https://example.com/proposal.jsonld",
anchorDataHash: "a1b1c2d3e4f5...",
},
rewardAddress
)
.changeAddress(changeAddress)
.selectUtxosFrom(utxos);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
console.log(`Info action submitted: ${txHash}`);Submit a Treasury Withdrawal
Propose a treasury withdrawal to one or more reward addresses:
import { MeshTxBuilder, BlockfrostProvider } from "@meshsdk/core";
const provider = new BlockfrostProvider("<YOUR_API_KEY>");
const txBuilder = new MeshTxBuilder({
fetcher: provider,
verbose: true,
});
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
const rewardAddresses = await wallet.getRewardAddresses();
const rewardAddress = rewardAddresses[0]!;
txBuilder
.proposal(
{
kind: "TreasuryWithdrawalsAction",
action: {
withdrawals: {
[rewardAddress]: "50000000000", // 50,000 ADA in lovelace
},
},
},
{
anchorUrl: "https://example.com/treasury-proposal.jsonld",
anchorDataHash: "a1b1c2d3e4f5...",
},
rewardAddress
)
.changeAddress(changeAddress)
.selectUtxosFrom(utxos);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
console.log(`Treasury withdrawal proposed: ${txHash}`);Submit a No Confidence Action
Propose a motion of no confidence in the current constitutional committee:
import { MeshTxBuilder, BlockfrostProvider } from "@meshsdk/core";
const provider = new BlockfrostProvider("<YOUR_API_KEY>");
const txBuilder = new MeshTxBuilder({
fetcher: provider,
verbose: true,
});
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
const rewardAddresses = await wallet.getRewardAddresses();
const rewardAddress = rewardAddresses[0]!;
txBuilder
.proposal(
{
kind: "NoConfidenceAction",
action: {
govActionId: {
transactionId: "previousNoConfidenceTxHash...",
govActionIndex: 0,
},
},
},
{
anchorUrl: "https://example.com/no-confidence.jsonld",
anchorDataHash: "a1b1c2d3e4f5...",
},
rewardAddress
)
.changeAddress(changeAddress)
.selectUtxosFrom(utxos);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
const txHash = await wallet.submitTx(signedTx);
console.log(`No confidence action submitted: ${txHash}`);Complete Example
This example demonstrates a complete DRep lifecycle:
import {
MeshTxBuilder,
BlockfrostProvider,
hashDrepAnchor
} from "@meshsdk/core";
const provider = new BlockfrostProvider("<YOUR_API_KEY>");
function getTxBuilder() {
return new MeshTxBuilder({
fetcher: provider,
verbose: true,
});
}
// Register as a DRep
async function registerDRep(
wallet: any,
name: string,
metadataUrl: string
) {
const txBuilder = getTxBuilder();
const dRep = await wallet.getDRep();
const dRepId = dRep.dRepIDCip105;
const metadata = {
"@context": { /* CIP-119 context */ },
"body": { "givenName": name }
};
const anchorHash = hashDrepAnchor(metadata);
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
txBuilder
.drepRegistrationCertificate(dRepId, {
anchorUrl: metadataUrl,
anchorDataHash: anchorHash,
})
.changeAddress(changeAddress)
.selectUtxosFrom(utxos);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
return await wallet.submitTx(signedTx);
}
// Vote on a governance action
async function castVote(
wallet: any,
govActionTxHash: string,
govActionIndex: number,
voteKind: "Yes" | "No" | "Abstain"
) {
const txBuilder = getTxBuilder();
const dRep = await wallet.getDRep();
const dRepId = dRep.dRepIDCip105;
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
txBuilder
.vote(
{ type: "DRep", drepId: dRepId },
{ txHash: govActionTxHash, txIndex: govActionIndex },
{ voteKind }
)
.selectUtxosFrom(utxos)
.changeAddress(changeAddress);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
return await wallet.submitTx(signedTx);
}
// Delegate to a DRep
async function delegateToDRep(wallet: any, dRepId: string) {
const txBuilder = getTxBuilder();
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
const rewardAddresses = await wallet.getRewardAddresses();
const rewardAddress = rewardAddresses[0]!;
txBuilder
.voteDelegationCertificate({ dRepId }, rewardAddress)
.changeAddress(changeAddress)
.selectUtxosFrom(utxos);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
return await wallet.submitTx(signedTx);
}
// Retire as DRep
async function retireDRep(wallet: any) {
const txBuilder = getTxBuilder();
const dRep = await wallet.getDRep();
const dRepId = dRep.dRepIDCip105;
const utxos = await wallet.getUtxos();
const changeAddress = await wallet.getChangeAddress();
txBuilder
.drepDeregistrationCertificate(dRepId)
.selectUtxosFrom(utxos)
.changeAddress(changeAddress);
const unsignedTx = await txBuilder.complete();
const signedTx = await wallet.signTx(unsignedTx);
return await wallet.submitTx(signedTx);
}
// Usage
async function main() {
// 1. Register as DRep
const regTx = await registerDRep(
wallet,
"Community DRep",
"https://example.com/metadata.jsonld"
);
console.log(`Registered as DRep: ${regTx}`);
// 2. Vote on proposals
const voteTx = await castVote(
wallet,
"proposal-tx-hash...",
0,
"Yes"
);
console.log(`Vote cast: ${voteTx}`);
// 3. Others delegate to you
const delegateTx = await delegateToDRep(
otherWallet,
"drep1..." // Your DRep ID
);
console.log(`Delegation received: ${delegateTx}`);
// 4. Eventually retire
const retireTx = await retireDRep(wallet);
console.log(`Retired as DRep: ${retireTx}`);
}Troubleshooting
"DRep not registered" error
- You must register as a DRep before voting
- Use
drepRegistrationCertificate()first
"Invalid anchor hash" error
- The hash must match the content at the URL exactly
- Use
hashDrepAnchor()to compute the correct hash - Ensure the metadata file is publicly accessible
"Insufficient deposit" error
- DRep registration requires a deposit (check current protocol parameters)
- Ensure wallet has enough ADA for deposit + fees
"DRep inactive" error
- DReps must vote regularly to stay active
- Vote on governance actions or submit an update certificate
"Governance action not found" error
- Verify the transaction hash and index are correct
- The governance action may have already been resolved
"Invalid voter type" error
- Ensure the voter type matches your role (DRep, SPO, or CC)
- Use the correct identifier format for each type
"Insufficient deposit" for proposal
- Governance action proposals require a large deposit (check
govActionDepositin protocol parameters) - The deposit is returned when the governance action is resolved (enacted, expired, or dropped)
- Ensure wallet has enough ADA for deposit + fees
"Missing proposal script information" error
- When using
proposalScript()orproposalTxInReference(), ensure the script source is provided before calling.complete() - For Plutus script proposals, a redeemer must also be provided via
proposalRedeemerValue()
References
- CIP-1694: Cardano On-Chain Governance - The governance specification that defines DReps, voting, and governance actions
- CIP-95: Web-Wallet Bridge for Conway Governance - The standard for wallet-dApp governance interaction
- CIP-119: DRep Metadata Standard - Metadata standard for DRep registration
- Cardano Developer Portal - Official Cardano development resources
Related
- Transaction Basics - Core transaction building
- Staking - Stake delegation
- CIP-1694 - Governance specification
- CIP-119 - DRep metadata standard