-
Notifications
You must be signed in to change notification settings - Fork 4
feat: add missing governance and pool apis #120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds missing governance and pool operation APIs to the Evolution SDK transaction builder, enabling DRep registration/management, Constitutional Committee operations, and stake pool registration/retirement.
Key Changes
- New APIs: Added
delegateToPool,delegateToDRep,delegateToPoolAndDRep(explicit delegation methods), plusregisterDRep,updateDRep,deregisterDRep,authCommitteeHot,resignCommitteeCold,registerPool, andretirePool - Balance Calculation: Implemented proper accounting for certificate deposits/refunds and withdrawals in transaction balance calculations
- Protocol Compliance: Added enforcement of Cardano's minimum 1 input requirement to prevent transaction replay attacks
Reviewed changes
Copilot reviewed 18 out of 20 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
packages/evolution/test/VotingProcedures.CML.test.ts |
Removed debug console.log statements |
packages/evolution/test/ProposalProcedures.CML.test.ts |
Removed debug console.log statements and updated comment |
packages/evolution/src/sdk/builders/phases/utils.ts |
Added utility functions to calculate certificate deposits/refunds and withdrawals |
packages/evolution/src/sdk/builders/phases/Selection.ts |
Enforced minimum 1 input UTxO requirement for protocol compliance |
packages/evolution/src/sdk/builders/phases/ChangeCreation.ts |
Updated balance calculations to include deposits, refunds, and withdrawals |
packages/evolution/src/sdk/builders/phases/Balance.ts |
Updated balance verification to account for deposits, refunds, and withdrawals |
packages/evolution/src/sdk/builders/operations/index.ts |
Exported new Governance, Pool, and Mint operation modules |
packages/evolution/src/sdk/builders/operations/Stake.ts |
Added explicit delegation methods: delegateToPool, delegateToDRep, delegateToPoolAndDRep |
packages/evolution/src/sdk/builders/operations/Pool.ts |
Implemented pool registration and retirement operations |
packages/evolution/src/sdk/builders/operations/Operations.ts |
Added parameter types for new delegation, governance, and committee operations with deprecation marker for delegateTo |
packages/evolution/src/sdk/builders/operations/Governance.ts |
Implemented DRep and Constitutional Committee governance operations |
packages/evolution/src/sdk/builders/TransactionBuilder.ts |
Integrated new operation APIs and added poolDeposits tracking to state |
packages/evolution-devnet/test/TxBuilder.Stake.test.ts |
Added integration tests for new explicit delegation APIs |
packages/evolution-devnet/test/TxBuilder.Pool.test.ts |
Added integration tests for pool registration and retirement |
packages/evolution-devnet/test/TxBuilder.PlutusMint.test.ts |
Removed debug console.log statements |
packages/evolution-devnet/test/TxBuilder.Governance.test.ts |
Added integration tests for DRep and Constitutional Committee operations |
packages/evolution-devnet/src/Genesis.ts |
Added queryCurrentEpoch utility for testing pool retirement |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| yield* Ref.update(ctx, (state) => ({ | ||
| ...state, | ||
| certificates: [...state.certificates, certificate] | ||
| })) |
Copilot
AI
Dec 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing debug log statement for retirePool operation. For consistency with other operations in the codebase (like registerPool on line 67), this function should log when a PoolRetirement certificate is added.
| })) | |
| })) | |
| yield* Effect.logDebug( | |
| `[RetirePool] Added PoolRetirement certificate for pool ${PoolKeyHash.toHex(params.poolKeyHash)} at epoch ${params.epoch}` | |
| ) |
|
|
||
| import * as Certificate from "../../../core/Certificate.js" | ||
| import * as PoolKeyHash from "../../../core/PoolKeyHash.js" | ||
| import { TransactionBuilderError,TxBuilderConfigTag, TxContext } from "../TransactionBuilder.js" |
Copilot
AI
Dec 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing space after comma in import statement. Should be "TransactionBuilderError, TxBuilderConfigTag" for consistent code style.
| import { TransactionBuilderError,TxBuilderConfigTag, TxContext } from "../TransactionBuilder.js" | |
| import { TransactionBuilderError, TxBuilderConfigTag, TxContext } from "../TransactionBuilder.js" |
| yield* Ref.update(ctx, (state) => ({ | ||
| ...state, | ||
| certificates: [...state.certificates, certificate] | ||
| })) |
Copilot
AI
Dec 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing debug log statement for registerDRep operation. For consistency with similar operations in the codebase (like registerPool which logs the deposit), this function should log when a RegDrepCert certificate is added.
| })) | |
| })) | |
| yield* Effect.logDebug( | |
| `Added RegDrepCert for DRep ${credentialToKey(params.drepCredential)} with deposit ${drepDeposit}` | |
| ) |
| // This handles cases where refunds/withdrawals cover all costs, but no UTxO inputs exist | ||
| const stateAfterSelection = yield* Ref.get(ctx) | ||
| if (stateAfterSelection.selectedUtxos.length === 0) { | ||
| //TODO: double check if this is a good approach, it seems that this condition is only needed when refunds/withdrawals cover all costs |
Copilot
AI
Dec 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The TODO comment should be removed or addressed. This logic appears correct - enforcing minimum 1 input is required by Cardano protocol even when refunds/withdrawals cover all costs. The condition properly checks if no UTxOs are selected and adds the smallest available one. Consider either removing the TODO or providing more specific concerns if this approach needs review.
| //TODO: double check if this is a good approach, it seems that this condition is only needed when refunds/withdrawals cover all costs | |
| // At this point refunds/withdrawals may have covered all costs, leaving no selected inputs; | |
| // however, Cardano still requires at least one input UTxO, so we pick the smallest available one |
| * Certificates with refunds (money IN): | ||
| * - UnregCert: Stake deregistration refund | ||
| * - UnregDrepCert: DRep deregistration refund | ||
| * - RetirePoolCert: Pool retirement refund (PoolRetirement) |
Copilot
AI
Dec 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inaccurate documentation comment: The comment on line 25 states "RetirePoolCert: Pool retirement refund (PoolRetirement)" suggesting it provides a refund, but the code correctly implements no refund (lines 66-70). The documentation on line 25 should be corrected to indicate that pool retirement does NOT provide a refund in the Conway era, matching the implementation.
| * - RetirePoolCert: Pool retirement refund (PoolRetirement) | |
| * - RetirePoolCert: Pool retirement (no refund in Conway era; pool deposits are burned) |
| return { | ||
| ...state, | ||
| certificates: [...state.certificates, certificate], | ||
| redeemers: newRedeemers, | ||
| deferredRedeemers: newDeferredRedeemers | ||
| } |
Copilot
AI
Dec 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing debug log statement for authCommitteeHot operation. For consistency with similar operations in the codebase, this function should log when an AuthCommitteeHotCert certificate is added.
| return { | |
| ...state, | |
| certificates: [...state.certificates, certificate], | |
| redeemers: newRedeemers, | |
| deferredRedeemers: newDeferredRedeemers | |
| } | |
| const updatedState = { | |
| ...state, | |
| certificates: [...state.certificates, certificate], | |
| redeemers: newRedeemers, | |
| deferredRedeemers: newDeferredRedeemers | |
| } | |
| console.debug("[Governance] Added AuthCommitteeHotCert", { | |
| coldCredential: credentialToKey(params.coldCredential), | |
| hotCredential: credentialToKey(params.hotCredential) | |
| }) | |
| return updatedState |
| redeemers: newRedeemers, | ||
| deferredRedeemers: newDeferredRedeemers | ||
| } | ||
| }) |
Copilot
AI
Dec 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing debug log statement for resignCommitteeCold operation. For consistency with similar operations in the codebase, this function should log when a ResignCommitteeColdCert certificate is added.
| }) | |
| }) | |
| yield* Effect.logDebug( | |
| `Added ResignCommitteeColdCert certificate for cold credential ${credentialToKey(params.coldCredential)}` | |
| ) |
| */ | ||
| export const queryUtxos = (cluster: Cluster) => Effect.runPromise(queryUtxosEffect(cluster)) | ||
|
|
||
| //TODO: this function does not belong here |
Copilot
AI
Dec 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The TODO comment indicates this function might be misplaced. The queryCurrentEpoch function appears to be a devnet testing utility but is placed in Genesis.ts. Consider moving this to a more appropriate module (perhaps a separate Query.ts or TestUtils.ts) or removing the TODO if this location is acceptable.
| //TODO: this function does not belong here |
| // TODO: protocol param should be resolved earlier in builder phases, not here | ||
| // protocol param can come from the provider or the build options directly |
Copilot
AI
Dec 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The TODO comment indicates protocol parameters should be resolved earlier in builder phases. This is a valid architectural concern - fetching protocol parameters in individual operation programs creates coupling to the provider and may result in redundant fetches. Consider resolving protocol parameters once during an initialization phase and passing them through the context.
| export function calculateCertificateBalance( | ||
| certificates: ReadonlyArray<Certificate.Certificate>, | ||
| poolDeposits: ReadonlyMap<string, bigint> | ||
| ): { deposits: bigint; refunds: bigint } { | ||
| return certificates.reduce( | ||
| (acc, cert) => { | ||
| switch (cert._tag) { | ||
| // Registration certificates with deposits (money goes OUT) | ||
| case "RegCert": | ||
| case "RegDrepCert": | ||
| case "StakeRegDelegCert": | ||
| case "VoteRegDelegCert": | ||
| case "StakeVoteRegDelegCert": | ||
| acc.deposits += cert.coin | ||
| break | ||
|
|
||
| // Deregistration certificates with refunds (money comes IN) | ||
| case "UnregCert": | ||
| case "UnregDrepCert": | ||
| acc.refunds += cert.coin | ||
| break | ||
|
|
||
| // Pool registration - deposit tracked in state | ||
| case "PoolRegistration": { | ||
| const operatorHex = PoolKeyHash.toHex(cert.poolParams.operator) | ||
| const deposit = poolDeposits.get(operatorHex) | ||
| if (deposit !== undefined) { | ||
| acc.deposits += deposit | ||
| } | ||
| break | ||
| } | ||
|
|
||
| // Pool retirement - no refund in Conway era (deposit is not refunded) | ||
| // Pool deposits are burned upon retirement | ||
| case "PoolRetirement": | ||
| // No refund for pool retirement in Conway | ||
| break | ||
|
|
||
| // Delegation certificates with no deposit/refund | ||
| case "StakeRegistration": | ||
| case "StakeDeregistration": | ||
| case "StakeDelegation": | ||
| case "VoteDelegCert": | ||
| case "StakeVoteDelegCert": | ||
| case "AuthCommitteeHotCert": | ||
| case "ResignCommitteeColdCert": | ||
| case "UpdateDrepCert": | ||
| // No deposit or refund | ||
| break | ||
| } | ||
| return acc | ||
| }, | ||
| { deposits: 0n, refunds: 0n } | ||
| ) | ||
| } |
Copilot
AI
Dec 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing unit test coverage for the new calculateCertificateBalance utility function. This function implements critical logic for calculating deposits and refunds from certificates. Given that the repository has extensive test coverage for other utilities and builder functions, this new utility should have comprehensive unit tests to verify correct handling of all certificate types, edge cases (empty certificates, missing pool deposits), and the balance calculations.
No description provided.