Skip to content

Commit

Permalink
simplify the minting logic in tunav2
Browse files Browse the repository at this point in the history
  • Loading branch information
MicroProofs committed May 7, 2024
1 parent 3f6dc1f commit abc0e7f
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 65 deletions.
6 changes: 3 additions & 3 deletions aiken.lock
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ requirements = []
source = "github"

[etags]
"aiken-lang/fuzz@main" = [{ secs_since_epoch = 1715034518, nanos_since_epoch = 262434000 }, "d7aadd4a9b25589bd6d5e3bbedcd809cdf97fe3eddb365cf89cd6ac6bc829643"]
"aiken-lang/sparse-merkle-tree@main" = [{ secs_since_epoch = 1715034518, nanos_since_epoch = 457834000 }, "c2269ba7d11b13b8ed2f3cd383b1dbfc525bead047d83e9ccbcca169d71e70d6"]
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1715034518, nanos_since_epoch = 77943000 }, "5ee55dc5ccf269bb493f4cacb32096f0191a6adb2ef39d62a1f79b8c5a8fcc7f"]
"aiken-lang/fuzz@main" = [{ secs_since_epoch = 1715114053, nanos_since_epoch = 34164000 }, "d7aadd4a9b25589bd6d5e3bbedcd809cdf97fe3eddb365cf89cd6ac6bc829643"]
"aiken-lang/sparse-merkle-tree@main" = [{ secs_since_epoch = 1715114053, nanos_since_epoch = 286332000 }, "c2269ba7d11b13b8ed2f3cd383b1dbfc525bead047d83e9ccbcca169d71e70d6"]
"aiken-lang/stdlib@main" = [{ secs_since_epoch = 1715114052, nanos_since_epoch = 761271000 }, "5ee55dc5ccf269bb493f4cacb32096f0191a6adb2ef39d62a1f79b8c5a8fcc7f"]
5 changes: 4 additions & 1 deletion lib/fortunav2.ak
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ pub const counter_prefix = "COUNTER"

pub const nominated_prefix = "NOMA"

pub fn genesis_v2(tx, own_policy, fortuna_v1_hash, fork_script_hash) {
pub fn genesis_v2(tx, own_policy, fortuna_v1_hash: Data, fork_script_hash: Data) {
let Transaction { reference_inputs, outputs, mint, .. } = tx

expect fortuna_v1_hash: ByteArray = fortuna_v1_hash
expect fork_script_hash: ByteArray = fork_script_hash

// 2 tokens minted
expect [Pair(_, 1), Pair(_, 1)] =
mint
Expand Down
4 changes: 3 additions & 1 deletion validators/simplerfork.ak
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type LockState {
current_locked_tuna: Int,
}

/// The reason this is a withdraw based validator is for the ease of grabbing the redeemer
/// using the tunav2 validator.
validator(init_utxo_ref: OutputReference, fortuna_v1_hash: ByteArray) {
fn nft_fork(redeemer: Data, ctx: ScriptContext) -> Bool {
let ScriptContext { transaction, purpose } = ctx
Expand Down Expand Up @@ -106,7 +108,7 @@ validator(init_utxo_ref: OutputReference, fortuna_v1_hash: ByteArray) {
let own_address = Address(ScriptCredential(own_policy), None)

// Validate only a single input is used
// the state input
// i.e. the state input
expect [Input(_, Output(in_address, in_lock_value, in_datum, _))] =
list.filter(
inputs,
Expand Down
89 changes: 29 additions & 60 deletions validators/tunav2.ak
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,19 @@ use aiken/transaction.{
Mint, Output, OutputReference, ScriptContext, Spend, Transaction,
} as tx
use aiken/transaction/credential.{Inline, ScriptCredential}
use aiken/transaction/value.{from_minted_value, tokens}
use aiken/transaction/value.{from_minted_value}
use fortuna
use fortuna/parameters.{epoch_number, halving_number, initial_payout}
use fortuna/types.{Statev2}
use fortuna/utils.{
get_inline_datum, integer_to_bytes, list_at, quantity_of,
resolve_output_reference,
get_inline_datum, integer_to_bytes, quantity_of, resolve_output_reference,
}
use fortunav2.{genesis_v2}
use hardfork/hftypes.{Lock, NftForkAction}

type TunaAction {
Genesis
MineTuna(OutputReference, Int, Int)
MineTuna(OutputReference, Int)
Redeem
NominateUpgradeToken
BurnUpgradeToken
Expand All @@ -41,6 +40,11 @@ type TunaSpendAction {
MinerVoteFor
}

type Miner {
Pkh(ByteArray, Data)
Nft { policy: ByteArray, name: ByteArray, output_index: Int, extra: Data }
}

type MerkleProofBlock {
starting_side: Side,
left_proofs: ByteArray,
Expand All @@ -49,13 +53,8 @@ type MerkleProofBlock {
remaining_proofs: ByteArray,
}

type Miner {
Pkh(ByteArray, Data)
Nft { policy: ByteArray, name: ByteArray, output_index: Int, extra: Data }
}

type MineAction {
Mine(ByteArray, Miner, MerkleProofBlock)
MinePow(ByteArray, Miner, MerkleProofBlock)
Upgrade(OutputReference)
}

Expand All @@ -69,7 +68,7 @@ type TargetState {
target_number: Int,
}

validator(fortuna_v1_hash: ByteArray, fork_script_hash: ByteArray) {
validator(fortuna_v1_hash: Data, fork_script_hash: Data) {
fn tuna(redeemer: TunaAction, ctx: ScriptContext) -> Bool {
expect ScriptContext { transaction: tx, purpose: Mint(own_policy) } = ctx

Expand All @@ -79,6 +78,8 @@ validator(fortuna_v1_hash: ByteArray, fork_script_hash: ByteArray) {
Redeem -> {
let Transaction { mint, redeemers, .. } = tx

expect fork_script_hash: ByteArray = fork_script_hash

let withdraw_purpose =
tx.WithdrawFrom(Inline(ScriptCredential(fork_script_hash)))

Expand All @@ -99,8 +100,8 @@ validator(fortuna_v1_hash: ByteArray, fork_script_hash: ByteArray) {
}
}

MineTuna(input_ref, block_number, output_index) -> {
let Transaction { inputs, mint, outputs, .. } = tx
MineTuna(input_ref, block_number) -> {
let Transaction { inputs, mint, .. } = tx

expect [
Pair(tuna_name, tuna_quantity),
Expand Down Expand Up @@ -135,13 +136,6 @@ validator(fortuna_v1_hash: ByteArray, fork_script_hash: ByteArray) {

let expected_out_token_name = integer_to_bytes(block_number + 1, "")

let expect_out_value =
value.from_asset(own_policy, big_tuna_name, 1)
|> value.add(own_policy, expected_out_token_name, 1)

let Output { address: out_address, value: out_value, .. } =
list_at(outputs, output_index)

let halving_exponent = block_number / halving_number

let expected_quantity =
Expand All @@ -151,15 +145,14 @@ validator(fortuna_v1_hash: ByteArray, fork_script_hash: ByteArray) {
initial_payout / pow2(halving_exponent)
}

// We don't check the output because we expect the spend script to take care of
// transporting the tokens to the next output
// As a backup in case of a spend script exploit, we still check
// that the input has the correct 2 tokens (Lord Tuna and counter) and the payment credential is contained
// within the Lord Tuna token name.
and {
//address check
spend_address == out_address,
// input value check
in_token_name == expected_in_token_name,
// output value check
out_value
|> value.without_lovelace
|> builtin.equals_data(expect_out_value),
// minted counter check
or {
and {
Expand Down Expand Up @@ -199,7 +192,7 @@ validator(fortuna_v1_hash: ByteArray, fork_script_hash: ByteArray) {
validator(tunav2_minting_policy: ByteArray) {
fn mine(datum: Statev2, redeemer: MineAction, ctx: ScriptContext) -> Bool {
when redeemer is {
Mine(nonce, miner, merkle_proof_block) -> {
MinePow(nonce, miner, merkle_proof_block) -> {
let Statev2 {
block_number,
current_hash,
Expand All @@ -214,14 +207,12 @@ validator(tunav2_minting_policy: ByteArray) {

expect Spend(own_reference) = purpose

let Transaction { inputs, outputs, mint, validity_range, .. } =
transaction

let mint = value.from_minted_value(mint)
let Transaction { inputs, outputs, validity_range, .. } = transaction

let own_input = resolve_output_reference(inputs, own_reference)
let Output { address: in_address, value: in_value, .. } =
resolve_output_reference(inputs, own_reference)

let Output { address: in_address, value: in_value, .. } = own_input
expect ScriptCredential(own_script_hash) = in_address.payment_credential

// Spend(0) requirement: Contract has only one output with the master token going back to itself
expect Some(own_output) =
Expand Down Expand Up @@ -269,22 +260,6 @@ validator(tunav2_minting_policy: ByteArray) {
let (found_target_number, found_leading_zeros) =
fortuna.format_found_bytearray(found_bytearray)

// Spend(5) requirement: Only one type of token minted under the validator policy
expect [Pair(token_name, quantity)] =
mint
|> tokens(tunav2_minting_policy)
|> dict.to_alist

let halving_exponent = block_number / halving_number

let expected_quantity =
// This should be 32 not 29
if halving_exponent > 32 {
0
} else {
initial_payout / math.pow2(halving_exponent)
}

// Check output datum contains correct epoch time, block number, hash, and leading zeros
// Check for every divisible by 2016 block:
// - Epoch time resets
Expand Down Expand Up @@ -367,7 +342,7 @@ validator(tunav2_minting_policy: ByteArray) {

quantity == 1
}
},
}?,
// Mining Difficulty Met
// Spend(3) requirement: Found difficulty is less than or equal to the current difficulty
// We do this by checking the leading zeros and the difficulty number
Expand All @@ -382,16 +357,10 @@ validator(tunav2_minting_policy: ByteArray) {
(quantity_of(
in_value,
tunav2_minting_policy,
fortuna.master_token_name,
bytearray.concat(fortunav2.big_tuna_prefix, own_script_hash),
) == 1)?,
// Spend(6) requirement: Minted token is the correct name and amount
(token_name == fortuna.token_name)?,
(quantity == expected_quantity)?,
// Spend(7) requirement: Output has only master token and ada
fortuna.value_has_only_master_and_lovelace(
out_value,
tunav2_minting_policy,
)?,
// Spend(7) requirement: Output has same tokens as input
(value.without_lovelace(in_value) == value.without_lovelace(out_value))?,
// Spend(10) requirement: Output posix time is the averaged current time
(out_current_posix_time == averaged_current_time)?,
// Spend(11) requirement: Output block number is the input block number + 1
Expand All @@ -408,7 +377,7 @@ validator(tunav2_minting_policy: ByteArray) {
remaining_proofs |> convert_bytes_to_remainder_proofs,
merkle_root,
out_merkle,
),
)?,
}
}

Expand Down

0 comments on commit abc0e7f

Please sign in to comment.