Skip to content

[Dijkstra] CIP-159-01: core types#1124

Open
williamdemeo wants to merge 6 commits intomasterfrom
1113-cip-159-01-core-types
Open

[Dijkstra] CIP-159-01: core types#1124
williamdemeo wants to merge 6 commits intomasterfrom
1113-cip-159-01-core-types

Conversation

@williamdemeo
Copy link
Member

Description

Closes #1113

CIP-159-01: Core types DirectDeposits, BalanceInterval, AccountBalanceIntervals

Summary

This PR introduces the shared domain types required by CIP-159 (Account Address Enhancement) in a new module Ledger.Dijkstra.Specification.Account. These types are used across Transaction, Certs, Utxo, and Script.Validation, so they are factored into their own module to avoid circular dependencies.

This covers Phase 1 (ADA-only). Phase 2 (multi-asset) upgrade paths are documented in the module as comments.

What's included

Definition Type Purpose
DirectDeposits Credential ⇀ Coin ADA deposits into account addresses within a transaction
BalanceInterval Maybe Coin × Maybe Coin Half-open interval [lo, hi) for balance assertions
AccountBalanceIntervals Credential ⇀ BalanceInterval Per-account balance interval assertions in a transaction
validBalanceInterval BalanceInterval → Type Well-formedness predicate requiring at least one bound
inBalanceInterval Coin → BalanceInterval → Type Membership predicate with Dec instance

Design decisions

  • Maybe × Maybe representation for BalanceInterval: Follows the existing Maybe Slot × Maybe Slot convention used by validity intervals. A separate validBalanceInterval predicate excludes the (nothing, nothing) case rather than encoding it structurally, giving downstream rules flexibility in how they assert well-formedness.

  • Half-open interval semantics: Unlike inInterval for slots (which uses closed [l, r] bounds), inBalanceInterval implements [lo, hi) as specified by CIP-159 (inclusive_lower_bound, exclusive_upper_bound). The upper bound check is suc c ≤ hi (i.e., c < hi).

  • No explicit DecEq declarations: BalanceInterval inherits DecEq from DecEq-× and DecEq-Maybe in the prelude. DirectDeposits and AccountBalanceIntervals are type aliases over .

  • Module parameterization: Parameterized by GovStructure (like Certs), giving access to Credential, Coin, etc.

Acceptance criteria checklist

  • DirectDeposits type alias defined and available for import
  • BalanceInterval and AccountBalanceIntervals types defined
  • inBalanceInterval predicate defined with decidability (Dec)
  • DecEq instances available where needed (inherited from prelude)
  • Module compiles with --safe

Checklist

  • Commit sequence broadly makes sense and commits have useful messages
  • Any semantic changes to the specifications are documented in CHANGELOG.md
  • Code is formatted according to CONTRIBUTING.md
  • Self-reviewed the diff

@williamdemeo williamdemeo self-assigned this Mar 13, 2026
@williamdemeo williamdemeo marked this pull request as ready for review March 13, 2026 03:28
Comment on lines +36 to +37
A `DirectDeposits`{.AgdaDatatype} map records the ADA being deposited into account
(reward) addresses within a single transaction. Each entry maps the stake credential
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe note that "reward addresses" is pre-Dijkstra nomenclature, and that now these are called account addresses.

Comment on lines +56 to +94
We represent a `BalanceInterval` as a pair of optional bounds, following the same
`Maybe × Maybe` convention used by the existing validity-interval type
(`Maybe Slot × Maybe Slot`).

```agda
BalanceInterval : Type
BalanceInterval = Maybe Coin × Maybe Coin
```
<!--
```agda
-- (just lo , just hi) represents [lo, hi)
-- (just lo , nothing) represents [lo, ∞)
-- (nothing , just hi) represents [0, hi)
-- (nothing , nothing) is excluded by the well-formedness predicate below.
```
-->

### Well-Formedness {#sec:balance-interval-wf}

[CIP 159][] requires that at least one bound is present. The
`validBalanceInterval`{.AgdaFunction} predicate excludes the `(nothing, nothing)`
case.

```agda
validBalanceInterval : BalanceInterval → Type
validBalanceInterval (just _ , _ ) = ⊤
validBalanceInterval (nothing , just _ ) = ⊤
validBalanceInterval (nothing , nothing) = ⊥
```

<!--
```agda
validBalanceInterval? : ∀ bi → Dec (validBalanceInterval bi)
validBalanceInterval? (just _ , _ ) = yes tt
validBalanceInterval? (nothing , just _ ) = yes tt
validBalanceInterval? (nothing , nothing) = no (λ ())
```
-->

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A better approach will be to forbid by construction invalid balance intervals

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I thought of that (and Claude also suggested that as an alternative), but I thought it best to get it working with a simpler type, plus a predicate, first and then later upgrade to a richer type. Wdyt?

williamdemeo and others added 4 commits March 13, 2026 11:32
Co-authored-by: Carlos Tomé Cortiñas <carlos.tome-cortinas@iohk.io>
Co-authored-by: Carlos Tomé Cortiñas <carlos.tome-cortinas@iohk.io>
Co-authored-by: Carlos Tomé Cortiñas <carlos.tome-cortinas@iohk.io>
Co-authored-by: Carlos Tomé Cortiñas <carlos.tome-cortinas@iohk.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Dijkstra] CIP-159-01: Core types AccountValue, BalanceInterval, DirectDeposits

2 participants