Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

- Various optimisations in `dict` and `assets` methods.

- <sup>⚠️ BREAKING-CHANGE ⚠️</sup> [`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
Expand Down
2 changes: 1 addition & 1 deletion lib/cardano/transaction.ak
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ pub type Transaction {
validity_range: ValidityRange,
extra_signatories: List<VerificationKeyHash>,
/// > [!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<ScriptPurpose, Redeemer>,
datums: Dict<DataHash, Data>,
id: TransactionId,
Expand Down
38 changes: 24 additions & 14 deletions lib/cardano/transaction/script_purpose.ak
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -77,15 +87,15 @@ 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)?,
(compare(mint0, propose0) == Less)?,
(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)?,
Expand All @@ -95,15 +105,15 @@ 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)?,
(compare(publish0, publish1) == Less)?,
(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)?,
Expand Down