From 1a5dc5003a280bc8495ede6a481e6ddce1d5f38e Mon Sep 17 00:00:00 2001 From: microproofs Date: Tue, 14 May 2024 23:44:33 -0400 Subject: [PATCH] finish up contract --- aiken.lock | 6 +- validators/tunav2.ak | 149 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 150 insertions(+), 5 deletions(-) diff --git a/aiken.lock b/aiken.lock index 5dd1f9b..7a6e981 100644 --- a/aiken.lock +++ b/aiken.lock @@ -35,6 +35,6 @@ requirements = [] source = "github" [etags] -"aiken-lang/fuzz@main" = [{ secs_since_epoch = 1715554770, nanos_since_epoch = 207151000 }, "d7aadd4a9b25589bd6d5e3bbedcd809cdf97fe3eddb365cf89cd6ac6bc829643"] -"aiken-lang/sparse-merkle-tree@main" = [{ secs_since_epoch = 1715554770, nanos_since_epoch = 427312000 }, "c2269ba7d11b13b8ed2f3cd383b1dbfc525bead047d83e9ccbcca169d71e70d6"] -"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1715554770, nanos_since_epoch = 17658000 }, "3d3d948e66503986746dfdf33ca5e80ac634b356c928321987188473d813b2db"] +"aiken-lang/fuzz@main" = [{ secs_since_epoch = 1715741615, nanos_since_epoch = 791411000 }, "d7aadd4a9b25589bd6d5e3bbedcd809cdf97fe3eddb365cf89cd6ac6bc829643"] +"aiken-lang/sparse-merkle-tree@main" = [{ secs_since_epoch = 1715741616, nanos_since_epoch = 5835000 }, "bfef445771d3be9c165c8d2e0a2b6eb437ef55f94ab061470ac921b00cfbf17e"] +"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1715741615, nanos_since_epoch = 554058000 }, "3d3d948e66503986746dfdf33ca5e80ac634b356c928321987188473d813b2db"] diff --git a/validators/tunav2.ak b/validators/tunav2.ak index 995e0d7..b9c2405 100644 --- a/validators/tunav2.ak +++ b/validators/tunav2.ak @@ -19,12 +19,14 @@ use aiken/transaction/value.{from_minted_value} use fortuna use fortuna/parameters.{ epoch_number, halving_number, initial_payout, miner_threshold, + supply_threshold, vote_threshold, } use fortuna/types.{Statev2} use fortuna/utils.{ get_inline_datum, integer_to_bytes, quantity_of, resolve_output_reference, } use fortunav2.{count_votes, flip_hash, genesis_v2, voting_period} +use hardfork.{calculate_emission} use hardfork/hftypes.{Lock, NftForkAction} type TunaAction { @@ -41,7 +43,7 @@ type TunaSpendAction { TokenVoteFor TokenVoteAgainst MinerVoteFor(Int, Int) - TransitionState + TransitionState(Int) } type TunaUpgradeProcess { @@ -597,7 +599,150 @@ validator(fortuna_v1_hash: Data, fork_script_hash: Data) { } } - TransitionState -> todo + TransitionState(block_number) -> { + expect ScriptContext { transaction: tx, purpose: Spend(own_ref) } = ctx + + let Transaction { + inputs, + reference_inputs, + outputs, + validity_range, + mint, + redeemers, + .. + } = tx + + let Output { address: in_address, value: in_value, .. } = + resolve_output_reference(inputs, own_ref) + + expect ScriptCredential(own_script_hash) = in_address.payment_credential + + expect IntervalBound { bound_type: Finite(lower_bound), .. } = + validity_range.lower_bound + + let common_checks = + fn(script_hash) { and { + value.quantity_of( + in_value, + own_script_hash, + bytearray.concat(fortunav2.nominated_prefix, script_hash), + ) == 1, + list.any( + reference_inputs, + fn(input) { + let Output { address, value, .. } = input.output + + let block_number_as_bytes = integer_to_bytes(block_number, "") + + let counter_token_name = + bytearray.concat( + fortunav2.counter_prefix, + block_number_as_bytes, + ) + + when address.payment_credential is { + ScriptCredential(script_hash) -> { + expect [Pair(token_name, 1), Pair(token_name2, 1)] = + value |> value.tokens(own_script_hash) |> dict.to_list + + and { + token_name == bytearray.concat( + fortunav2.big_tuna_prefix, + script_hash, + ), + token_name2 == counter_token_name, + } + } + _ -> False + } + }, + ), + } } + + when dat is { + Nominated { script_hash, for_count, against_count, deadline, .. } -> { + let Output { + address: out_address, + value: out_value, + datum: out_datum, + .. + } = utils.list_at(outputs, 0) + + let expected_datum = + InlineDatum( + Mining { + script_hash, + miner_support_count: 0, + block_height_deadline: block_number + epoch_number, + }, + ) + + let emitted_supply = calculate_emission(block_number) + + and { + or { + and { + in_address == out_address, + value.without_lovelace(in_value) == value.without_lovelace( + out_value, + ), + out_datum == expected_datum, + for_count >= ( for_count + against_count ) * vote_threshold / 1000, + for_count + against_count >= emitted_supply * supply_threshold / 1000, + }, + and { + mint + |> from_minted_value + |> quantity_of( + own_script_hash, + bytearray.concat( + fortunav2.nominated_prefix, + script_hash, + ), + ) + |> builtin.equals_integer(-1), + for_count < ( for_count + against_count ) * vote_threshold / 1000 || for_count + against_count < emitted_supply * supply_threshold / 1000, + }, + }, + deadline <= lower_bound, + common_checks(script_hash), + } + } + + // Validate passed in block number is real + Mining { script_hash, miner_support_count, block_height_deadline } -> + and { + or { + and { + miner_support_count >= epoch_number * miner_threshold / 1000, + { + expect Some(upgrade_rdmr) = + alist.get_first(redeemers, Mint(own_script_hash)) + + expect FinalizeNomination { .. }: TunaAction = upgrade_rdmr + + True + }, + }, + and { + miner_support_count < epoch_number * miner_threshold / 1000, + mint + |> from_minted_value + |> quantity_of( + own_script_hash, + bytearray.concat( + fortunav2.nominated_prefix, + script_hash, + ), + ) + |> builtin.equals_integer(-1), + }, + }, + block_height_deadline <= block_number, + common_checks(script_hash), + } + } + } } } }