Legacy Stake Registration
Register stake credentials using the pre-Conway certificate format (no deposit)
Legacy Stake Registration
The Conway era introduced new registration certificates (RegCert, CDDL tag 7) that require a 2 ADA deposit. However, the legacy certificates (StakeRegistration, CDDL tag 0) are still accepted on mainnet and are what most wallets and tools use today.
Use legacy registration when:
- You want to avoid the 2 ADA deposit
- You need compatibility with pre-Conway tooling
- You're building a wallet that supports older node versions
Legacy vs Conway Registration
| Legacy (pre-Conway) | Conway | |
|---|---|---|
| Certificate | StakeRegistration (tag 0) | RegCert (tag 7) |
| Deposit | None | 2 ADA (from protocol params) |
| Builder method | registerStakeLegacy() | registerStake() |
| Deregistration | deregisterStakeLegacy() | deregisterStake() |
| Combined register + delegate | Not available | registerAndDelegateTo() |
Both formats are valid on mainnet today. The ledger accepts either. Choose legacy for simplicity or Conway for deposit-based guarantees.
Basic Legacy Registration
import { , , } from "@evolution-sdk/evolution"
const = .()
.({
: "https://cardano-preprod.blockfrost.io/api/v0",
: ..!
})
.({ : ..!, : 0 })
const = await .()
const = .!
// Legacy registration — no deposit required
const = await .().({ }).()
const = await .()
await .()Compare with Conway registration which fetches keyDeposit from protocol parameters:
import { , , } from "@evolution-sdk/evolution"
const = .()
.({
: "https://cardano-preprod.blockfrost.io/api/v0",
: ..!
})
.({ : ..!, : 0 })
declare const : .
// Conway registration — 2 ADA deposit deducted automatically
const = await .().({ }).()Register and Delegate in One Transaction
Legacy registration doesn't have a combined certificate, but you can chain both operations in a single transaction:
import { , , } from "@evolution-sdk/evolution"
const = .()
.({
: "https://cardano-preprod.blockfrost.io/api/v0",
: ..!
})
.({ : ..!, : 0 })
declare const : .
declare const : any // pool key hash from a stake pool explorer
// Register (legacy) + delegate in one transaction
const = await
.()
.({ })
.({ , })
.()
const = await .()
await .()Script-Controlled Legacy Registration
For stake credentials controlled by a Plutus script, provide a redeemer:
import { , , , } from "@evolution-sdk/evolution"
const = .()
.({
: "https://cardano-preprod.blockfrost.io/api/v0",
: ..!
})
.({ : ..!, : 0 })
declare const : .
declare const : any // compiled Plutus staking script
const = await
.()
.({
: ,
: .(0n, []),
: "legacy-register-script-stake"
})
.({ : })
.()
const = await .()
await .()Withdrawal with a Stake Script
Stake scripts are Plutus validators that run when you withdraw rewards. This is also the foundation of the coordinator pattern used by DeFi protocols — a zero-amount withdrawal triggers the stake validator, which can enforce global invariants across multiple script inputs.
Basic Script Withdrawal
import { , , , } from "@evolution-sdk/evolution"
const = .()
.({
: "https://cardano-preprod.blockfrost.io/api/v0",
: ..!
})
.({ : ..!, : 0 })
declare const : .
declare const : any // compiled Plutus staking script
declare const : bigint
// Withdraw rewards — the stake script validates this transaction
const = await
.()
.({
: ,
: ,
: .(0n, []),
: "withdraw-rewards"
})
.({ : })
.()
const = await .()
await .()Coordinator Pattern (Zero-Amount Withdrawal)
Use amount: 0n to trigger a stake validator without withdrawing rewards. The validator runs and can enforce rules across the entire transaction — checking that inputs, outputs, and certificates meet your protocol's invariants:
import { , , , } from "@evolution-sdk/evolution"
const = .()
.({
: "https://cardano-preprod.blockfrost.io/api/v0",
: ..!
})
.({ : ..!, : 0 })
declare const : .
declare const : any
// Zero withdrawal — triggers the validator without moving funds
const = await
.()
.({
: ,
: 0n,
: .(0n, []),
: "coordinator-trigger"
})
.({ : })
.()
const = await .()
await .()Batch Redeemer (Coordinated Spend + Withdraw)
The most powerful pattern combines script UTxO spending with a withdrawal validator. The withdrawal redeemer receives the indices of all spent inputs, so the stake validator can verify each one:
import { , , , , } from "@evolution-sdk/evolution"
import * as from "@evolution-sdk/evolution/Bytes"
import * as from "@evolution-sdk/evolution/PlutusV3"
import * as from "@evolution-sdk/evolution/ScriptHash"
import * as from "@evolution-sdk/evolution/InlineDatum"
const = .()
.({
: "https://cardano-preprod.blockfrost.io/api/v0",
: ..!
})
.({ : ..!, : 0 })
// Your compiled multi-validator (spend + withdraw endpoints)
declare const : string
const = new .({ : .() })
const = .()
const = // ScriptHash is a valid Credential
// Redeemer constructors matching your Aiken validator
const = (: bigint): . =>
.()
const = (: <bigint>): . =>
.(0n, [.(.(.))])
// Fetch UTxOs locked at the script address
declare const : ..[]
const = .(0, 2)
// Build the coordinated transaction
let = .()
// Collect from each script UTxO — self-referencing redeemer gets the final input index
for (const of ) {
= .({
: [],
: () => ((.))
})
}
// Attach the script once (shared by spend + withdraw endpoints)
= .({ : })
// Zero withdrawal with batch redeemer — receives all input indices
= .({
: ,
: 0n,
: {
: () =>
(.(() => (.))),
:
},
: "coordinator-withdraw"
})
const = await .()
const = await .()
await .()Why batch redeemers? Input indices aren't known until coin selection runs. The all callback receives the final sorted indices after the transaction is balanced — solving the chicken-and-egg problem.
Legacy Deregistration
Deregister a legacy-registered stake credential. No deposit is refunded (since none was paid):
import { , , } from "@evolution-sdk/evolution"
const = .()
.({
: "https://cardano-preprod.blockfrost.io/api/v0",
: ..!
})
.({ : ..!, : 0 })
const = await .()
const = .!
// Withdraw rewards first, then deregister — in one transaction
const = await .()
const = await
.()
.({ , : . })
.({ })
.()
const = await .()
await .()Always withdraw rewards before deregistering. Rewards are lost after deregistration regardless of which certificate format you used.
Full Lifecycle Example
Register, delegate, withdraw, and deregister — all using legacy certificates:
import { , , } from "@evolution-sdk/evolution"
const = .()
.({
: "https://cardano-preprod.blockfrost.io/api/v0",
: ..!
})
.({ : ..!, : 0 })
declare const : any
const = await .()
const = .!
// 1. Register + delegate
const = await
.()
.({ })
.({ , })
.()
await (await .()).()
// ... epochs pass, rewards accumulate ...
// 2. Withdraw rewards
const = await .()
const = await
.()
.({ , : . })
.()
await (await .()).()
// 3. Deregister when done
const = await
.()
.({ })
.()
await (await .()).()Next Steps
- Registration (Conway) — Conway-era registration with deposit
- Delegation — Pool and DRep delegation options
- Withdrawal — Reward withdrawal patterns
- Deregistration — Conway-era deregistration with refund