diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 399db4d..e6d2b5e 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -31,9 +31,9 @@ jobs: uses: actions/configure-pages@v2 - name: 🧰 Install Aiken - uses: aiken-lang/setup-aiken@v1 + uses: aiken-lang/setup-aiken@v0.1.0 with: - version: v1.0.28-alpha + version: v1.0.18-alpha - name: 📝 Run fmt run: aiken fmt --check @@ -52,7 +52,7 @@ jobs: path: "docs/" deploy: - # if: ${{ startsWith(github.ref, 'refs/tags') }} + if: ${{ startsWith(github.ref, 'refs/tags') }} needs: build runs-on: ubuntu-latest environment: diff --git a/lib/aiken/collection.ak b/lib/aiken/collection.ak new file mode 100644 index 0000000..39a8b23 --- /dev/null +++ b/lib/aiken/collection.ak @@ -0,0 +1,4 @@ +/// An positive integer, that materializes the position of an element in a +/// collection. +pub type Index = + Int diff --git a/lib/aiken/dict.ak b/lib/aiken/collection/dict.ak similarity index 100% rename from lib/aiken/dict.ak rename to lib/aiken/collection/dict.ak diff --git a/lib/aiken/list.ak b/lib/aiken/collection/list.ak similarity index 99% rename from lib/aiken/list.ak rename to lib/aiken/collection/list.ak index b8bb4b8..3745c49 100644 --- a/lib/aiken/list.ak +++ b/lib/aiken/collection/list.ak @@ -1,6 +1,6 @@ use aiken/builtin -use aiken/bytearray -use aiken/int +use aiken/primitive/bytearray +use aiken/primitive/int /// Determine if all elements of the list satisfy the given predicate. /// diff --git a/lib/aiken/pairs.ak b/lib/aiken/collection/pairs.ak similarity index 100% rename from lib/aiken/pairs.ak rename to lib/aiken/collection/pairs.ak diff --git a/lib/aiken/math/rational.ak b/lib/aiken/math/rational.ak index d99ef20..a5db89e 100644 --- a/lib/aiken/math/rational.ak +++ b/lib/aiken/math/rational.ak @@ -10,7 +10,7 @@ //// Comparing rational values should, therefore, only happen after reduction (see [reduce](#reduce)) or via the [compare](#compare) method. use aiken/builtin -use aiken/list +use aiken/collection/list use aiken/math use aiken/option diff --git a/lib/aiken/bytearray.ak b/lib/aiken/primitive/bytearray.ak similarity index 100% rename from lib/aiken/bytearray.ak rename to lib/aiken/primitive/bytearray.ak diff --git a/lib/aiken/int.ak b/lib/aiken/primitive/int.ak similarity index 98% rename from lib/aiken/int.ak rename to lib/aiken/primitive/int.ak index fd602b6..885f798 100644 --- a/lib/aiken/int.ak +++ b/lib/aiken/primitive/int.ak @@ -1,6 +1,6 @@ -use aiken/bytearray use aiken/math use aiken/option +use aiken/primitive/bytearray /// Compare two integers. /// diff --git a/lib/aiken/string.ak b/lib/aiken/primitive/string.ak similarity index 100% rename from lib/aiken/string.ak rename to lib/aiken/primitive/string.ak diff --git a/lib/aiken/time.ak b/lib/aiken/time.ak index f181815..e69de29 100644 --- a/lib/aiken/time.ak +++ b/lib/aiken/time.ak @@ -1,3 +0,0 @@ -/// A number of milliseconds since 00:00:00 UTC on 1 January 1970. -pub type PosixTime = - Int diff --git a/lib/aiken/transaction/certificate.ak b/lib/aiken/transaction/certificate.ak deleted file mode 100644 index a5d9c8e..0000000 --- a/lib/aiken/transaction/certificate.ak +++ /dev/null @@ -1,15 +0,0 @@ -use aiken/hash.{Blake2b_224, Hash} -use aiken/transaction/credential.{PoolId, StakeCredential, VerificationKey} - -/// An on-chain certificate attesting of some operation. Publishing -/// certificates / triggers different kind of rules; most of the time, -/// they require signatures from / specific keys. -pub type Certificate { - CredentialRegistration { delegator: StakeCredential } - CredentialDeregistration { delegator: StakeCredential } - CredentialDelegation { delegator: StakeCredential, delegatee: PoolId } - PoolRegistration { pool_id: PoolId, vrf: Hash } - PoolDeregistration { pool_id: PoolId, epoch: Int } - Governance - TreasuryMovement -} diff --git a/lib/aiken/transaction/value.ak b/lib/cardano/assets.ak similarity index 98% rename from lib/aiken/transaction/value.ak rename to lib/cardano/assets.ak index eac2203..f4e9556 100644 --- a/lib/aiken/transaction/value.ak +++ b/lib/cardano/assets.ak @@ -1,8 +1,12 @@ -use aiken/dict.{Dict, from_ascending_pairs_with} +use aiken/collection/dict.{Dict, from_ascending_pairs_with} +use aiken/collection/list use aiken/hash.{Blake2b_224, Hash} -use aiken/list use aiken/option -use aiken/transaction/credential.{Script} +use cardano/credential.{Script} + +/// Lovelace is now a type wrapper for Int. +pub type Lovelace = + Int /// A type-alias for a `PolicyId`. A `PolicyId` is always 28-byte long pub type PolicyId = diff --git a/lib/cardano/certificate.ak b/lib/cardano/certificate.ak new file mode 100644 index 0000000..6ca9045 --- /dev/null +++ b/lib/cardano/certificate.ak @@ -0,0 +1,71 @@ +use cardano/assets.{Lovelace} +use cardano/credential.{Credential, StakePoolId, VerificationKeyHash} + +/// An on-chain certificate attesting of some operation. Publishing +/// certificates / triggers different kind of rules; most of the time, +/// they require signatures from / specific keys. +pub type Certificate { + // Register a stake credential with an optional deposit amount. + // The deposit is always present when using the new registration certificate + // format available since the Conway era. + RegisterCredential { credential: Credential, deposit: Option } + // Un-Register a stake credential with an optional refund amount + // The deposit is always present when using the new de-registration certificate + // format available since the Conway era. + UnregisterCredential { credential: Credential, refund: Option } + // Delegate stake to a [Delegate](#Delegate). + DelegateCredential { credential: Credential, delegate: Delegate } + // Register and delegate staking credential to a Delegatee in one certificate. + RegisterAndDelegateCredential { + credential: Credential, + delegate: Delegate, + deposit: Lovelace, + } + // Register a delegate representative (a.k.a DRep). The deposit is explicit and + // is refunded when the delegate steps down (unregister). + RegisterDelegateRepresentative { + delegate_representative: Credential, + deposit: Lovelace, + } + // Update a delegate representative (a.k.a DRep). The certificate also contains + // metadata which aren't visible on-chain. + UpdateDelegateRepresentative { delegate_representative: Credential } + // UnRegister a delegate representative, and refund back its past deposit. + UnregisterDelegateRepresentative { + delegate_representative: Credential, + refund: Lovelace, + } + // Register a new stake pool + RegisterStakePool { + // The hash digest of the stake pool's cold (public) key + stake_pool: StakePoolId, + // The hash digest of the stake pool's VRF (public) key + vrf: VerificationKeyHash, + } + // Retire a stake pool. 'at_epoch' indicates in which the retirement will take place + RetireStakePool { stake_pool: StakePoolId, at_epoch: Int } + // Authorize a Hot credential for a specific Committee member's cold credential + AuthorizeConstitutionalCommitteeProxy { + constitutional_committee_member: Credential, + proxy: Credential, + } + // Step down from the constitutional committee as a member. + RetireFromConstitutionalCommittee { + constitutional_committee_member: Credential, + } +} + +pub type Delegate { + DelegateBlockProduction { stake_pool: StakePoolId } + DelegateVote { delegate_representative: DelegateRepresentative } + DelegateBoth { + stake_pool: StakePoolId, + delegate_representative: DelegateRepresentative, + } +} + +pub type DelegateRepresentative { + Registered(Credential) + AlwaysAbstain + AlwaysNoConfidence +} diff --git a/lib/aiken/transaction/credential.ak b/lib/cardano/credential.ak similarity index 86% rename from lib/aiken/transaction/credential.ak rename to lib/cardano/credential.ak index fa6327d..4cd8fbf 100644 --- a/lib/aiken/transaction/credential.ak +++ b/lib/cardano/credential.ak @@ -1,13 +1,13 @@ use aiken/builtin -use aiken/hash.{Blake2b_224, Hash} +use aiken/hash.{Blake2b_224, Blake2b_256, Hash} /// A general structure for representing an on-chain `Credential`. /// /// Credentials are always one of two kinds: a direct public/private key /// pair, or a script (native or Plutus). pub type Credential { - VerificationKeyCredential(Hash) - ScriptCredential(Hash) + VerificationKey(VerificationKeyHash) + Script(ScriptHash) } /// A Cardano `Address` typically holding one or two credential references. @@ -23,18 +23,12 @@ pub type Address { /// Smart-constructor for an [Address](#Address) from a [verification key](#VerificationKey) hash. The resulting address has no delegation rights whatsoever. pub fn from_verification_key(vk: Hash) -> Address { - Address { - payment_credential: VerificationKeyCredential(vk), - stake_credential: None, - } + Address { payment_credential: VerificationKey(vk), stake_credential: None } } /// Smart-constructor for an [Address](#Address) from a [script](#Script) hash. The address has no delegation rights whatsoever. pub fn from_script(script: Hash) -> Address { - Address { - payment_credential: ScriptCredential(script), - stake_credential: None, - } + Address { payment_credential: Script(script), stake_credential: None } } /// Set (or reset) the delegation part of an [Address](#Address) using a [verification key](#VerificationKey) hash. This is useful when combined with [`from_verification_key`](#from_verification_key) and/or [`from_script`](#from_script). @@ -44,7 +38,7 @@ pub fn with_delegation_key( ) -> Address { Address { payment_credential: self.payment_credential, - stake_credential: Some(Inline(VerificationKeyCredential(vk))), + stake_credential: Some(Inline(VerificationKey(vk))), } } @@ -55,7 +49,7 @@ pub fn with_delegation_script( ) -> Address { Address { payment_credential: self.payment_credential, - stake_credential: Some(Inline(ScriptCredential(script))), + stake_credential: Some(Inline(Script(script))), } } @@ -107,6 +101,14 @@ pub type StakeCredential = pub type PaymentCredential = Credential -/// A unique stake pool identifier, as a hash of its owner verification key. -pub type PoolId = +pub type StakePoolId = Hash + +pub type VerificationKeyHash = + Hash + +pub type ScriptHash = + Hash + +pub type DatumHash = + Hash diff --git a/lib/cardano/governance.ak b/lib/cardano/governance.ak new file mode 100644 index 0000000..b01d81e --- /dev/null +++ b/lib/cardano/governance.ak @@ -0,0 +1,109 @@ +use aiken/collection.{Index} +use aiken/hash.{Blake2b_256, Hash} +use aiken/math/rational.{Rational} +use cardano/assets.{Lovelace} +use cardano/credential.{Credential, ScriptHash, VerificationKeyHash} +use cardano/governance/protocol_parameters.{ProtocolParametersUpdate} + +pub type ProposalProcedure { + deposit: Lovelace, + return_address: Credential, + governance_action: GovernanceAction, +} + +pub type GovernanceAction { + ProtocolParameters { + /// The last governance action of type 'ProtocolParameters'. They must all + /// form a chain. + ancestor: Option, + /// The new proposed protocol parameters. Only values set to `Some` are relevant. + new_parameters: ProtocolParametersUpdate, + /// The optional guardrails script defined in the constitution. The script + /// is executed by the ledger in addition to the hard-coded ledger rules. + /// + /// It must pass for the new protocol parameters to be deemed valid. + guardrails: Option, + } + HardFork { + /// The last governance action of type `HardFork`. They must all + /// form a chain. + ancestor: Option, + /// The new proposed version. Few rules apply to proposing new versions: + /// + /// - The `major` component, if incremented, must be exactly one more than the current. + /// - The `minor` component, if incremented, must be exactly one more than the current. + /// - If the `major` component is incremented, `minor` must be set to `0`. + /// - Neither `minor` nor `major` can be decremented. + new_version: ProtocolVersion, + } + TreasuryWithdrawal { + /// A collection of beneficiaries, which can be plain verification key + /// hashes or script hashes (e.g. DAO). + beneficiaries: Pairs, + /// The optional guardrails script defined in the constitution. The script + /// is executed by the ledger in addition to the hard-coded ledger rules. + /// + /// It must pass for the withdrawals to be authorized. + guardrails: Option, + } + NoConfidence { + /// The last governance action of type `NoConfidence` or + /// `ConstitutionalCommittee`. They must all / form a chain. + ancestor: Option, + } + ConstitutionalCommittee { + /// The last governance action of type `NoConfidence` or + /// `ConstitutionalCommittee`. They must all / form a chain. + ancestor: Option, + /// Constitutional members to be removed. + evicted_members: List, + /// Constitutional members to be added. + added_members: Pairs, + /// The new quorum value, as a ratio of a numerator and a denominator. The + /// quorum specifies the threshold of 'Yes' votes necessary for the + /// constitutional committee to accept a proposal procedure. + quorum: Rational, + } + NewConstitution { + /// The last governance action of type `Constitution` or + /// `ConstitutionalCommittee`. They must all / form a chain. + ancestor: Option, + /// The new proposed constitution. + constitution: Constitution, + } + NicePoll +} + +pub type Vote { + No + Yes + Abstain +} + +pub type TransactionId = + Hash + +pub type GovernanceActionId { + transaction: TransactionId, + proposal_procedure: Index, +} + +pub type ProtocolVersion { + major: Int, + minor: Int, +} + +pub type Constitution { + guardrails: Option, +} + +/// An epoch number after which constitutional committee member +/// mandate expires. +pub type Mandate = + Int + +pub type Voter { + ConstitutionalCommitteeMember(Credential) + DelegateRepresentative(Credential) + StakePool(VerificationKeyHash) +} diff --git a/lib/cardano/governance/protocol_parameters.ak b/lib/cardano/governance/protocol_parameters.ak new file mode 100644 index 0000000..ca2c575 --- /dev/null +++ b/lib/cardano/governance/protocol_parameters.ak @@ -0,0 +1,368 @@ +use aiken/math/rational.{Rational} +use cardano/assets.{Lovelace} + +pub opaque type ProtocolParametersUpdate { + inner: Pairs, +} + +pub type ScriptExecutionPrices { + memory: Rational, + cpu: Rational, +} + +pub type ExecutionUnits { + memory: Int, + cpu: Int, +} + +pub type StakePoolOperatorVotingThresholds { + motion_of_no_confidence: Rational, + constitutional_committee: ConstitutionalCommitteeThresholds, + hard_fork: Rational, + protocol_parameters: ProtocolParametersThresholds< + Rational, + Void, + Void, + Void, + Void, + >, +} + +pub type DelegateRepresentativeVotingThresholds { + motion_of_no_confidence: Rational, + constitutional_committee: ConstitutionalCommitteeThresholds, + constitution: Rational, + hard_fork: Rational, + protocol_parameters: ProtocolParametersThresholds< + Void, + Rational, + Rational, + Rational, + Rational, + >, + treasury_withdrawal: Rational, +} + +pub type ProtocolParametersThresholds< + security, + network, + economic, + technical, + governance, +> { + security_group: security, + network_group: network, + economic_group: economic, + technical_group: technical, + governance_group: governance, +} + +pub type ConstitutionalCommitteeThresholds { + default: Rational, + under_no_confidence: Rational, +} + +/// The linear coefficient that intervenes in the transaction fee calculation. +/// It is multiplied by the size of the transaction in bytes to obtain a Lovelace value. +pub fn min_fee_coefficient(self: ProtocolParametersUpdate) -> Option { + get_protocol_param(self.inner, 0, into_int) +} + +/// The constant factor that intervenes in the transaction fee calculation. It is +/// a flat cost of lovelace that is added to every fee calculation. +pub fn min_fee_constant(self: ProtocolParametersUpdate) -> Option { + get_protocol_param(self.inner, 1, into_int) +} + +/// The maximum size of a serialized block body, expressed in bytes. +pub fn max_block_body_size(self: ProtocolParametersUpdate) -> Option { + get_protocol_param(self.inner, 2, into_int) +} + +/// The maximum size of a serialized transaction (body + witnesses), expressed in bytes. +pub fn max_transaction_size(self: ProtocolParametersUpdate) -> Option { + get_protocol_param(self.inner, 3, into_int) +} + +/// The maximum size of a serialized block header, expressed in bytes. +pub fn max_block_header_size(self: ProtocolParametersUpdate) -> Option { + get_protocol_param(self.inner, 4, into_int) +} + +/// The required deposit amount when registering stake credentials, expressed in Lovelace. +pub fn stake_credential_deposit( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 5, into_int) +} + +/// The required deposit amount when registering a stake pool, expressed in Lovelace. +pub fn stake_pool_deposit(self: ProtocolParametersUpdate) -> Option { + get_protocol_param(self.inner, 6, into_int) +} + +/// The maximum number of epoch in the future allowed for a stake pool retirement to be scheduled. +pub fn stake_pool_retirement_horizon( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 7, into_int) +} + +/// The desired/optimal number of fully saturated stake pools in the system. Also known as the _'k-parameter'_. +pub fn desired_number_of_stake_pools( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 8, into_int) +} + +/// A parameter controlling the influence of an pool owner's pledge on the rewards. Also known as _'a0'_. +pub fn stake_pool_pledge_influence( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 9, into_rational) +} + +/// The monetary expansion parameter, controlling the fraction of Ada put in circulation on every epoch through the incentivies model. Also known as _'ρ'_. +pub fn monetary_expansion(self: ProtocolParametersUpdate) -> Option { + get_protocol_param(self.inner, 10, into_rational) +} + +/// The parameter controlling what fraction (%) of available rewards is sent to the treasury on every epoch. Also known as _'τ'_. +pub fn treasury_expansion(self: ProtocolParametersUpdate) -> Option { + get_protocol_param(self.inner, 11, into_rational) +} + +/// Minimum authorized constant cost that stake pools can declare when registering, expressed in Lovelace. +pub fn min_stake_pool_cost(self: ProtocolParametersUpdate) -> Option { + get_protocol_param(self.inner, 16, into_int) +} + +/// The linear coefficient that intervenes in the calculation of the minimum Ada value that any UTxO must hold. It is expressed in Lovelace per Byte, and is also known as the 'coins per utxo byte' parameter. +pub fn min_utxo_deposit_coefficient( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 17, into_int) +} + +/// The costs associated with the various operations of the Plutus Virtual Machine, which can be different for each Plutus version. +pub fn cost_models(self: ProtocolParametersUpdate) -> Option { + get_protocol_param(self.inner, 18, identity) +} + +/// The price, in Lovelace per unit, of the execution units corresponding to cpu and memory usage of on-chain scripts. +pub fn script_execution_prices( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 19, into_script_execution_prices) +} + +/// The maximum execution units allowed for a single transaction. +pub fn max_transaction_execution_units( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 20, into_execution_units) +} + +/// The maximum execution units allowed for a single block. +pub fn max_block_execution_units( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 21, into_execution_units) +} + +/// The maximum size of a serialized value in a transaction output. This effectively limits +/// the maximum kinds of assets that can be sent in a single output. It is expressed in bytes. +pub fn max_value_size(self: ProtocolParametersUpdate) -> Option { + get_protocol_param(self.inner, 22, into_int) +} + +/// The scaling factor applied to the transaction cost for defining the minimum collateral +/// amount. It is expressed in percent points (so 100 = 100%). +pub fn collateral_percentage(self: ProtocolParametersUpdate) -> Option { + get_protocol_param(self.inner, 23, into_int) +} + +/// The maximum number of collateral inputs allowed in the transaction. +pub fn max_collateral_inputs(self: ProtocolParametersUpdate) -> Option { + get_protocol_param(self.inner, 24, into_int) +} + +/// The various governance voting thresholds pertaining to stake pool operators. +pub fn stake_pool_operator_voting_thresholds( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 25, into_spo_voting_thresholds) +} + +/// The various governance voting thresholds pertaining to delegate representatives +/// (a.k.a DReps). +pub fn delegate_representative_voting_thresholds( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 26, into_drep_voting_thresholds) +} + +/// The minimum number of members in the constitutional committee. Any updates of the committee +/// must leave at least this number of members. +pub fn min_constitutional_committee_size( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 27, into_int) +} + +/// The maximum length of a constitutional committee member, expressed in number of epochs. +pub fn max_constitutional_committee_mandate( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 28, into_int) +} + +/// The lifetime of any governance proposal. An action that hasn't been approved beyond that +/// period is considered inactive and discarded. It is expressed in number of epochs. +pub fn governance_proposal_lifetime( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 29, into_int) +} + +/// The required deposit amount for governance proposal procedures, expressed in Lovelace. +pub fn governance_proposal_deposit( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 30, into_int) +} + +/// The required deposit amount when registering as a delegate representative, expressed in +/// Lovelace. +pub fn delegate_representative_deposit( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 31, into_int) +} + +/// The maximum number of epochs that a delegate representative can stay inactive (i.e. no +/// voting) without becoming _inactive_ and removed from thresholds calculations. +pub fn delegate_representative_max_idle_time( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 32, into_int) +} + +/// The base tier fee coefficient for reference scripts. Reference scripts gets increasingly +/// more expensives every ~24KB, the base coefficient is a multiplicating factor which grows +/// exponentially with each tier. +pub fn reference_scripts_tier_fee_initial_factor( + self: ProtocolParametersUpdate, +) -> Option { + get_protocol_param(self.inner, 33, into_rational) +} + +// Internals ------------------------------------------------------------------- + +type ProtocolParametersIndex = + Int + +fn get_protocol_param( + self: Pairs, + ix: ProtocolParametersIndex, + into: fn(Data) -> a, +) -> Option { + when self is { + [] -> None + [Pair(jx, param), ..tail] -> + if ix == jx { + Some(into(param)) + } else { + get_protocol_param(tail, ix, into) + } + } +} + +fn into_int(param: Data) -> Int { + expect param: Int = param + param +} + +fn into_rational(param: Data) -> Rational { + expect [numerator, denominator]: List = param + expect Some(r) = rational.new(numerator, denominator) + r +} + +fn into_execution_units(param: Data) -> ExecutionUnits { + expect [memory, cpu]: List = param + ExecutionUnits { memory, cpu } +} + +fn into_script_execution_prices(param: Data) -> ScriptExecutionPrices { + expect [memory, cpu]: List = param + let memory = into_rational(memory) + let cpu = into_rational(cpu) + ScriptExecutionPrices { memory, cpu } +} + +fn into_spo_voting_thresholds(param: Data) -> StakePoolOperatorVotingThresholds { + expect [ + motion_of_no_confidence, + constitutional_committee, + constitutional_committee_under_no_confidence, + hard_fork, + protocol_parameters_security_group, + ]: List = param + + StakePoolOperatorVotingThresholds { + motion_of_no_confidence: into_rational(motion_of_no_confidence), + constitutional_committee: ConstitutionalCommitteeThresholds { + default: into_rational(constitutional_committee), + under_no_confidence: into_rational( + constitutional_committee_under_no_confidence, + ), + }, + hard_fork: into_rational(hard_fork), + protocol_parameters: ProtocolParametersThresholds { + security_group: into_rational(protocol_parameters_security_group), + network_group: Void, + economic_group: Void, + technical_group: Void, + governance_group: Void, + }, + } +} + +fn into_drep_voting_thresholds( + param: Data, +) -> DelegateRepresentativeVotingThresholds { + trace @"drep voting thresholds": param + expect [ + motion_of_no_confidence, + constitutional_committee, + constitutional_committee_under_no_confidence, + constitution, + hard_fork, + protocol_parameters_network_group, + protocol_parameters_economic_group, + protocol_parameters_technical_group, + protocol_parameters_governance_group, + treasury_withdrawal, + ]: List = param + + DelegateRepresentativeVotingThresholds { + motion_of_no_confidence: into_rational(motion_of_no_confidence), + constitutional_committee: ConstitutionalCommitteeThresholds { + default: into_rational(constitutional_committee), + under_no_confidence: into_rational( + constitutional_committee_under_no_confidence, + ), + }, + constitution: into_rational(constitution), + hard_fork: into_rational(hard_fork), + protocol_parameters: ProtocolParametersThresholds { + security_group: Void, + network_group: into_rational(protocol_parameters_network_group), + economic_group: into_rational(protocol_parameters_economic_group), + technical_group: into_rational(protocol_parameters_technical_group), + governance_group: into_rational(protocol_parameters_governance_group), + }, + treasury_withdrawal: into_rational(treasury_withdrawal), + } +} diff --git a/lib/aiken/transaction.ak b/lib/cardano/transaction.ak similarity index 56% rename from lib/aiken/transaction.ak rename to lib/cardano/transaction.ak index eb1572e..9c152f1 100644 --- a/lib/aiken/transaction.ak +++ b/lib/cardano/transaction.ak @@ -1,30 +1,66 @@ use aiken/builtin -use aiken/dict.{Dict} -use aiken/hash.{Blake2b_224, Blake2b_256, Hash, blake2b_256} +use aiken/collection.{Index} +use aiken/collection/dict.{Dict} +use aiken/collection/list +use aiken/hash.{Blake2b_256, Hash, blake2b_256} use aiken/interval.{Interval} -use aiken/list use aiken/option -use aiken/time.{PosixTime} -use aiken/transaction/certificate.{Certificate} -use aiken/transaction/credential.{ - Address, Script, ScriptCredential, StakeCredential, VerificationKey, - VerificationKeyCredential, +use cardano/assets.{Lovelace, PolicyId, Value} +use cardano/certificate.{Certificate} +use cardano/credential.{ + Address, Credential, DatumHash, Script, ScriptHash, VerificationKey, + VerificationKeyHash, } -use aiken/transaction/value.{MintedValue, PolicyId, Value} +use cardano/governance.{GovernanceActionId, ProposalProcedure, Vote, Voter} + +pub type TransactionId = + Hash /// A context given to a script by the Cardano ledger when being executed. /// /// The context contains information about the entire transaction that contains /// the script. The transaction may also contain other scripts; to distinguish -/// between multiple scripts, the `ScriptContext` also contains a `purpose` +/// between multiple scripts, the `ScriptInfo` contains a `purpose` /// which indicates which script (or, for what purpose) of the transaction is /// being executed. pub type ScriptContext { transaction: Transaction, - purpose: ScriptPurpose, + redeemer: Redeemer, + info: ScriptInfo, } -/// Characterizes the kind of script being executed. +/// Characterizes the script information. +pub type ScriptInfo { + /// For scripts executed as minting/burning policies, to insert + /// or remove assets from circulation. It's parameterized by the identifier + /// of the associated policy. + Minting(PolicyId) + /// For scripts that are used as payment credentials for addresses in + /// transaction outputs. They govern the rule by which the output they + /// reference can be spent. + Spending(OutputReference, Option) + /// For scripts that validate reward withdrawals from a reward account. + /// + /// The argument identifies the target reward account. + Withdrawing(Credential) + /// Needed when delegating to a pool using stake credentials defined as a + /// Plutus script. This purpose is also triggered when de-registering such + /// stake credentials. + /// + /// The Int is a 0-based index of the given `TxCert` in `certificates`. + Publishing(Index, Certificate) + /// Voting for a type of voter using a governance action id to vote + /// yes / no / abstain inside a transaction. + /// + /// The voter is who is doing the governance action. + Voting(Voter) + /// Used to propose a governance action. + /// + /// A 0-based index of the given `ProposalProcedure` in `proposal_procedures`. + Proposing(Index, ProposalProcedure) +} + +/// Characterizes the script purpose. pub type ScriptPurpose { /// For scripts executed as minting/burning policies, to insert /// or remove assets from circulation. It's parameterized by the identifier @@ -37,13 +73,22 @@ pub type ScriptPurpose { /// For scripts that validate reward withdrawals from a reward account. /// /// The argument identifies the target reward account. - WithdrawFrom(StakeCredential) + Withdraw(Credential) /// Needed when delegating to a pool using stake credentials defined as a /// Plutus script. This purpose is also triggered when de-registering such /// stake credentials. /// - /// It embeds the certificate that's being validated. - Publish(Certificate) + /// The Int is a 0-based index of the given `TxCert` in `certificates`. + Publish { certificate_index: Int, certificate: Certificate } + /// Voting for a type of voter using a governance action id to vote + /// yes / no / abstain inside a transaction. + /// + /// The voter is who is doing the governance action. + Vote(Voter) + /// Used to propose a governance action. + /// + /// A 0-based index of the given `ProposalProcedure` in `proposal_procedures`. + Propose(Int, ProposalProcedure) } /// A Cardano `Transaction`, as seen by Plutus scripts. @@ -56,15 +101,24 @@ pub type Transaction { inputs: List, reference_inputs: List, outputs: List, - fee: Value, - mint: MintedValue, + fee: Lovelace, + mint: Value, certificates: List, - withdrawals: Pairs, + /// ⚠️ | Withdrawals are ordered by ascending [Credential](./credential.html#Credential). Yet, note that script credentials are treated as lower values than verification key credentials. + /// --- | --- + withdrawals: Pairs, validity_range: ValidityRange, - extra_signatories: List>, + extra_signatories: List, + /// ⚠️ | Redeemers are ordered by ascending [ScriptPurpose](./governance.html#ScriptPurpose). redeemers: Pairs, - datums: Dict, Data>, + datums: Dict, id: TransactionId, + /// ⚠️ | Votes are ordered by ascending [Voter](./governance.html#Voter) and [GovernanceActionId](./governance.html#GovernanceActionId).
First constructor variants in a type are treated as lower indices; except for [Credential](./credential.html#Credential) where stake credentials are treated as lower values than verification key credentials. + /// --- | --- + votes: Pairs>, + proposal_procedures: List, + current_treasury_amount: Option, + treasury_donation: Option, } /// A placeholder / empty `Transaction` to serve as a base in a transaction @@ -75,9 +129,8 @@ pub type Transaction { /// ```aiken /// use aiken/transaction /// -/// transaction.placeholder().id == TransactionId { -/// hash: #"0000000000000000000000000000000000000000000000000000000000000000", -/// } +/// transaction.placeholder().id == +/// #"0000000000000000000000000000000000000000000000000000000000000000" /// /// transaction.placeholder().validity_range == interval.everything() /// ``` @@ -86,31 +139,30 @@ pub fn placeholder() -> Transaction { inputs: [], reference_inputs: [], outputs: [], - fee: value.zero(), - mint: value.zero() |> value.to_minted_value(), + fee: 0, + mint: assets.zero(), certificates: [], withdrawals: [], validity_range: interval.everything(), extra_signatories: [], redeemers: [], datums: dict.new(), - id: TransactionId { - hash: #"0000000000000000000000000000000000000000000000000000000000000000", - }, + id: #"0000000000000000000000000000000000000000000000000000000000000000", + votes: [], + proposal_procedures: [], + current_treasury_amount: None, + treasury_donation: None, } } +/// A number of milliseconds since 00:00:00 UTC on 1 January 1970. +pub type PosixTime = + Int + /// An interval of POSIX time, measured in number milliseconds since 1970-01-01T00:00:00Z. pub type ValidityRange = Interval -/// A unique transaction identifier, as the hash of a transaction body. Note that the transaction id -/// isn't a direct hash of the `Transaction` as visible on-chain. Rather, they correspond to hash -/// digests of transaction body as they are serialized on the network. -pub type TransactionId { - hash: Hash, -} - /// An `Input` made of an output reference and, the resolved value associated with that output. pub type Input { output_reference: OutputReference, @@ -121,7 +173,7 @@ pub type Input { /// corresponds to the position in the output list of the transaction (identified by its id) /// that produced that output pub type OutputReference { - transaction_id: TransactionId, + transaction_id: Hash, output_index: Int, } @@ -130,14 +182,14 @@ pub type Output { address: Address, value: Value, datum: Datum, - reference_script: Option>, + reference_script: Option, } /// An output `Datum`. pub type Datum { NoDatum /// A datum referenced by its hash digest. - DatumHash(Hash) + DatumHash(DatumHash) /// A datum completely inlined in the output. InlineDatum(Data) } @@ -177,8 +229,8 @@ pub fn find_input( /// witnesses. pub fn find_datum( outputs: List, - datums: Dict, Data>, - datum_hash: Hash, + datums: Dict, + datum_hash: DatumHash, ) -> Option { datums |> dict.get(datum_hash) @@ -191,7 +243,7 @@ pub fn find_datum( InlineDatum(data) -> if blake2b_256(builtin.serialise_data(data)) == datum_hash{ - + Some(data) } else { None @@ -209,15 +261,14 @@ pub fn find_datum( /// contracts running over multiple transactions. pub fn find_script_outputs( outputs: List, - script_hash: Hash, + script_hash: ScriptHash, ) -> List { outputs |> list.filter( fn(output) { when output.address.payment_credential is { - ScriptCredential(addr_script_hash) -> - script_hash == addr_script_hash - VerificationKeyCredential(_) -> False + Script(addr_script_hash) -> script_hash == addr_script_hash + VerificationKey(_) -> False } }, )