diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3907102..b7627e6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,8 @@
- Various optimisations in `dict` and `assets` methods.
+- ⚠️ BREAKING-CHANGE ⚠️ [`cardano/transaction/script_purpose.{compare}`](https://aiken-lang.github.io/stdlib/cardano/transaction/script_purpose.html#compare) now follows the ledger's ordering of script purposes, which is the ordering of the `redeemers` list in the script context: `Spend` < `Mint` < `Publish` < `Withdraw` < `Vote` < `Propose`. It previously followed the constructor order of `ScriptPurpose` (`Mint` first, `Withdraw` before `Publish`), which does not match the on-chain ordering. See [#125](https://github.com/aiken-lang/stdlib/issues/125).
+
## v3.0.0 - 2025-10-21
### Added
diff --git a/lib/cardano/transaction.ak b/lib/cardano/transaction.ak
index 12f8ec8..0e7d2b3 100644
--- a/lib/cardano/transaction.ak
+++ b/lib/cardano/transaction.ak
@@ -65,7 +65,7 @@ pub type Transaction {
validity_range: ValidityRange,
extra_signatories: List,
/// > [!IMPORTANT]
- /// > Redeemers are ordered by ascending [ScriptPurpose](./transaction.html#ScriptPurpose).
+ /// > Redeemers are ordered by ascending [ScriptPurpose](./transaction.html#ScriptPurpose), following the internal ledger's ordering of script purposes: [`Spend`](./transaction.html#ScriptPurpose) < [`Mint`](./transaction.html#ScriptPurpose) < [`Publish`](./transaction.html#ScriptPurpose) < [`Withdraw`](./transaction.html#ScriptPurpose) < [`Vote`](./transaction.html#ScriptPurpose) < [`Propose`](./transaction.html#ScriptPurpose). Note that this ordering **differs from the constructor order** of [ScriptPurpose](./transaction.html#ScriptPurpose); see [script_purpose.compare](./transaction/script_purpose.html#compare).
redeemers: Pairs,
datums: Dict,
id: TransactionId,
diff --git a/lib/cardano/transaction/script_purpose.ak b/lib/cardano/transaction/script_purpose.ak
index 13c7783..9b98ca8 100644
--- a/lib/cardano/transaction/script_purpose.ak
+++ b/lib/cardano/transaction/script_purpose.ak
@@ -10,32 +10,42 @@ use cardano/transaction.{
}
use cardano/transaction/output_reference
+/// Compare two script purposes, using the same ordering as the one used by
+/// the ledger when constructing the
+/// [redeemers](./transaction.html#Transaction) list:
+///
+/// [`Spend`](./transaction.html#ScriptPurpose) < [`Mint`](./transaction.html#ScriptPurpose) < [`Publish`](./transaction.html#ScriptPurpose) < [`Withdraw`](./transaction.html#ScriptPurpose) < [`Vote`](./transaction.html#ScriptPurpose) < [`Propose`](./transaction.html#ScriptPurpose)
+///
+/// Note that this ordering follows the internal ledger types, and thus
+/// differs from the constructor order of
+/// [ScriptPurpose](./transaction.html#ScriptPurpose): `Spend` comes before
+/// `Mint`, and `Publish` comes before `Withdraw`.
pub fn compare(left: ScriptPurpose, right: ScriptPurpose) -> Ordering {
when left is {
- Mint(left) ->
+ Spend(left) ->
when right is {
- Mint(right) -> bytearray.compare(left, right)
+ Spend(right) -> output_reference.compare(left, right)
_ -> Less
}
- Spend(left) ->
+ Mint(left) ->
when right is {
- Spend(right) -> output_reference.compare(left, right)
- Mint(_) -> Greater
+ Mint(right) -> bytearray.compare(left, right)
+ Spend(_) -> Greater
_ -> Less
}
- Withdraw(left) ->
+ Publish { at: left, .. } ->
when right is {
- Withdraw(right) -> credential.compare(left, right)
+ Publish { at: right, .. } -> int.compare(left, right)
Spend(_) | Mint(_) -> Greater
_ -> Less
}
- Publish { at: left, .. } ->
+ Withdraw(left) ->
when right is {
- Publish { at: right, .. } -> int.compare(left, right)
- Spend(_) | Mint(_) | Withdraw(_) -> Greater
+ Withdraw(right) -> credential.compare(left, right)
+ Spend(_) | Mint(_) | Publish { .. } -> Greater
_ -> Less
}
@@ -77,7 +87,7 @@ test compare_matrix() {
(compare(mint0, mint0) == Equal)?,
(compare(mint0, mint1) == Less)?,
(compare(mint1, mint0) == Greater)?,
- (compare(mint0, spend0) == Less)?,
+ (compare(mint0, spend0) == Greater)?,
(compare(mint0, withdraw0) == Less)?,
(compare(mint0, publish0) == Less)?,
(compare(mint0, vote0) == Less)?,
@@ -85,7 +95,7 @@ test compare_matrix() {
(compare(spend0, spend0) == Equal)?,
(compare(spend0, spend1) == Less)?,
(compare(spend1, spend0) == Greater)?,
- (compare(spend0, mint0) == Greater)?,
+ (compare(spend0, mint0) == Less)?,
(compare(spend0, withdraw0) == Less)?,
(compare(spend0, publish0) == Less)?,
(compare(spend0, vote0) == Less)?,
@@ -95,7 +105,7 @@ test compare_matrix() {
(compare(withdraw1, withdraw0) == Greater)?,
(compare(withdraw0, mint0) == Greater)?,
(compare(withdraw0, spend0) == Greater)?,
- (compare(withdraw0, publish0) == Less)?,
+ (compare(withdraw0, publish0) == Greater)?,
(compare(withdraw0, vote0) == Less)?,
(compare(withdraw0, propose0) == Less)?,
(compare(publish0, publish0) == Equal)?,
@@ -103,7 +113,7 @@ test compare_matrix() {
(compare(publish1, publish0) == Greater)?,
(compare(publish0, mint0) == Greater)?,
(compare(publish0, spend0) == Greater)?,
- (compare(publish0, withdraw0) == Greater)?,
+ (compare(publish0, withdraw0) == Less)?,
(compare(publish0, vote0) == Less)?,
(compare(publish0, propose0) == Less)?,
(compare(vote0, vote0) == Equal)?,