Skip to content

Commit

Permalink
feat: building test cases for transfer ownership
Browse files Browse the repository at this point in the history
  • Loading branch information
HinsonSIDAN committed Nov 28, 2023
1 parent 8fdd397 commit 7a1202e
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 20 deletions.
11 changes: 11 additions & 0 deletions lib/aiken-content-ownership/common.ak
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,17 @@ pub fn compare_output_reference(x, y) {
)
}

pub fn inputs_token_quantity(
inputs: List<Input>,
token: (PolicyId, AssetName),
) -> Int {
list.map(
inputs,
fn(input) { quantity_of(input.output.value, token.1st, token.2nd) },
)
|> list.foldr(0, fn(n, total) { n + total })
}

test byte_conversion() {
convert_int_to_bytes(1) == "1" && convert_int_to_bytes(123) == "123" && convert_int_to_bytes(
672912,
Expand Down
4 changes: 4 additions & 0 deletions lib/aiken-content-ownership/placeholder.ak
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ pub fn mock_policy_id_4() -> PolicyId {
#"c0f778be07f8b129d2546ad37b0e13b3486747dfe1767ff8e7e8a4f3"
}

pub fn mock_policy_id_5() -> PolicyId {
#"ab4e38cc1e95e42c6f6e56d8d4243731c483bb57e49da5047c38e9d8"
}

pub fn mock_utxo_ref(output_index: Int) -> OutputReference {
OutputReference {
transaction_id: TransactionId(
Expand Down
2 changes: 1 addition & 1 deletion lib/aiken-content-ownership/types.ak
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub type OwnershipRegistryDatum {
pub type OwnershipRegistryRedeemer {
CreateOwnershipRecord
TransferOwnership {
new_owner_toen: (PolicyId, AssetName),
new_owner_token: (PolicyId, AssetName),
content_number: Int,
}
StopOwnershipRegistry
Expand Down
62 changes: 57 additions & 5 deletions lib/aiken-content-ownership/validators/ownership_registry.ak
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
use aiken/dict
use aiken/int
use aiken/list
use aiken/transaction.{
InlineDatum, ScriptContext, ScriptPurpose, Spend, Transaction,
}
use aiken/transaction/value.{PolicyId}
use aiken_content_ownership/common.{inputs_at, inputs_with}
use aiken/transaction/value.{PolicyId, flatten}
use aiken_content_ownership/common.{
inputs_at, inputs_at_with_policy, inputs_token_quantity, inputs_with,
outputs_at_with_policy,
}
use aiken_content_ownership/types.{
ContentRegistryRedeemer, CreateContent, CreateOwnershipRecord, OracleDatum,
OwnershipRegistryDatum, OwnershipRegistryRedeemer,
OwnershipRegistryDatum, OwnershipRegistryRedeemer, TransferOwnership,
}

pub fn ownership_registry_logic(
Expand All @@ -16,7 +21,8 @@ pub fn ownership_registry_logic(
context: ScriptContext,
) {
let ScriptContext { purpose, transaction } = context
let Transaction { reference_inputs, redeemers, inputs, .. } = transaction
let Transaction { reference_inputs, redeemers, inputs, outputs, .. } =
transaction
expect Spend(_): ScriptPurpose = purpose
when (redeemer, inputs_with(reference_inputs, oracle_nft, "")) is {
(CreateOwnershipRecord, [oracle_ref_utxo]) -> {
Expand All @@ -36,7 +42,53 @@ pub fn ownership_registry_logic(
_ -> False
}
}

(TransferOwnership { new_owner_token, content_number }, [oracle_ref_utxo]) -> {
expect InlineDatum(inline_datum) = oracle_ref_utxo.output.datum
expect OracleDatum {
ownership_registry_address,
ownership_registry_ref_token,
..
}: OracleDatum = inline_datum
when
(
inputs_at_with_policy(
inputs,
ownership_registry_address,
ownership_registry_ref_token,
),
outputs_at_with_policy(
outputs,
ownership_registry_address,
ownership_registry_ref_token,
),
)
is {
([ownership_input], [ownership_output]) -> {
expect InlineDatum(raw_input_datum) = ownership_input.output.datum
expect input_datum: OwnershipRegistryDatum = raw_input_datum
expect InlineDatum(raw_output_datum) = ownership_output.datum
expect output_datum: OwnershipRegistryDatum = raw_output_datum
expect Some(original_owner) =
dict.get(input_datum.registry, content_number)
let is_original_owner_authorized =
inputs_token_quantity(inputs, original_owner) > 0
let is_registry_updated =
output_datum == OwnershipRegistryDatum {
count: input_datum.count,
registry: dict.insert(
input_datum.registry,
content_number,
new_owner_token,
int.compare,
),
}
let is_registry_value_clean =
list.length(flatten(ownership_output.value)) == 2
is_original_owner_authorized && is_registry_updated && is_registry_value_clean
}
_ -> False
}
}
_ -> False
}
}
197 changes: 183 additions & 14 deletions validators/tests/unit-tests/ownership_registry.ak
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,30 @@ use aiken/transaction/value.{AssetName, PolicyId, add, from_asset}
use aiken_content_ownership/common.{compare_output_reference}
use aiken_content_ownership/placeholder.{
mock_content_registry_output, mock_oracle_datum, mock_oracle_output,
mock_ownership_registry_output, mock_policy_id, mock_policy_id_2,
mock_policy_id_3, mock_policy_id_4, mock_utxo_ref,
mock_output, mock_ownership_registry_output, mock_policy_id, mock_policy_id_2,
mock_policy_id_3, mock_policy_id_4, mock_policy_id_5, mock_utxo_ref,
}
use aiken_content_ownership/types.{
ContentRegistryDatum, CreateContent, CreateOwnershipRecord,
OwnershipRegistryDatum, StopContentRegistry,
OwnershipRegistryDatum, StopContentRegistry, TransferOwnership,
}
use aiken_content_ownership/utils.{get_registry_token_name}
use aiken_content_ownership/validators/ownership_registry.{
ownership_registry_logic,
}

type TestCase {
type CreateTestCase {
has_input_from_content_registry: Bool,
is_content_registry_redeemer_correct: Bool,
}

fn make_mock_tx_body(
fn make_mock_tx_body_for_create(
record_count: Int,
content_registry: Dict<Int, ByteArray>,
ownership_registry: Dict<Int, (PolicyId, AssetName)>,
content_hash: ByteArray,
owner: (PolicyId, AssetName),
test_case: TestCase,
test_case: CreateTestCase,
) -> Transaction {
let content_registry_value =
from_asset(mock_policy_id_2(), get_registry_token_name(0), 1)
Expand Down Expand Up @@ -160,40 +160,209 @@ fn make_mock_tx_body(
}
}

fn base_case(test_case: TestCase) {
fn create_base_case(test_case: CreateTestCase) {
let redeemer = CreateOwnershipRecord
let dat = OwnershipRegistryDatum { count: 0, registry: dict.new() }
let content_hash = "QmWBaeu6y1zEcKbsEqCuhuDHPL3W8pZouCPdafMCRCSUWk"
let owner = (mock_policy_id_4(), "my_token_name")
let tx =
make_mock_tx_body(0, dict.new(), dict.new(), content_hash, owner, test_case)
make_mock_tx_body_for_create(
0,
dict.new(),
dict.new(),
content_hash,
owner,
test_case,
)
let ctx = ScriptContext { purpose: Spend(mock_utxo_ref(2)), transaction: tx }
ownership_registry_logic(mock_policy_id(), dat, redeemer, ctx)
}

test success_create_ownership_record() {
base_case(
TestCase {
create_base_case(
CreateTestCase {
has_input_from_content_registry: True,
is_content_registry_redeemer_correct: True,
},
)
}

test fail_create_ownership_record_without_content_input() {
!base_case(
TestCase {
!create_base_case(
CreateTestCase {
has_input_from_content_registry: False,
is_content_registry_redeemer_correct: True,
},
)
}

test fail_create_ownership_record_with_incorrect_redeemer() {
!base_case(
TestCase {
!create_base_case(
CreateTestCase {
has_input_from_content_registry: True,
is_content_registry_redeemer_correct: False,
},
)
}

type UpdateTestCase {
is_original_owner_authorized: Bool,
is_registry_updated: Bool,
is_registry_value_clean: Bool,
}

fn make_mock_tx_body_for_update(
record_count: Int,
ownership_registry: Dict<Int, (PolicyId, AssetName)>,
original_owner: (PolicyId, AssetName),
new_owner: (PolicyId, AssetName),
test_case: UpdateTestCase,
) -> Transaction {
let ownership_registry_value =
from_asset(mock_policy_id_3(), get_registry_token_name(0), 1)
|> add(#"", #"", 2_000_000)
let auth_token =
if test_case.is_original_owner_authorized {
original_owner
} else {
new_owner
}
let original_owner_output =
Output {
..mock_output(),
value: mock_output().value
|> add(auth_token.1st, auth_token.2nd, 1)
|> if test_case.is_registry_value_clean {
add(_, #"", #"", 2_000_000)
} else {
add(_, mock_policy_id_4(), "another_token", 1)
},
}
let inputs =
[
Input {
output_reference: mock_utxo_ref(2),
output: Output {
..mock_ownership_registry_output(
0,
OwnershipRegistryDatum {
count: record_count,
registry: ownership_registry,
},
),
value: ownership_registry_value,
},
},
Input {
output_reference: mock_utxo_ref(3),
output: original_owner_output,
},
]

let outputs =
[
Output {
..mock_ownership_registry_output(
0,
OwnershipRegistryDatum {
count: record_count,
registry: if test_case.is_registry_updated {
dict.insert(
ownership_registry,
record_count,
new_owner,
int.compare,
)
} else {
ownership_registry
},
},
),
value: if test_case.is_registry_value_clean {
ownership_registry_value
} else {
ownership_registry_value
|> add(mock_policy_id_4(), "another_token", 1)
},
},
original_owner_output,
]

Transaction {
..placeholder(),
reference_inputs: [
Input {
output_reference: mock_utxo_ref(0),
output: mock_oracle_output(mock_oracle_datum()),
},
],
inputs: inputs,
outputs: outputs,
}
}

fn update_base_case(test_case: UpdateTestCase) {
let current_registry =
dict.new()
|> dict.insert(0, (mock_policy_id(), "my_token_name"), int.compare)
|> dict.insert(1, (mock_policy_id(), "my_token_name"), int.compare)
|> dict.insert(2, (mock_policy_id(), "my_token_name"), int.compare)
|> dict.insert(3, (mock_policy_id(), "my_token_name"), int.compare)
|> dict.insert(4, (mock_policy_id_4(), "my_token_name"), int.compare)
|> dict.insert(5, (mock_policy_id(), "my_token_name"), int.compare)
let dat = OwnershipRegistryDatum { count: 0, registry: current_registry }
let original_owner = (mock_policy_id_4(), "my_token_name")
let new_owner = (mock_policy_id_5(), "my_another_token_name")
let tx =
make_mock_tx_body_for_update(
4,
current_registry,
original_owner,
new_owner,
test_case,
)
let redeemer =
TransferOwnership { new_owner_token: new_owner, content_number: 4 }
let ctx = ScriptContext { purpose: Spend(mock_utxo_ref(2)), transaction: tx }
ownership_registry_logic(mock_policy_id(), dat, redeemer, ctx)
}

test success_update_ownership_record() {
update_base_case(
UpdateTestCase {
is_original_owner_authorized: True,
is_registry_updated: True,
is_registry_value_clean: True,
},
)
}

test fail_update_ownership_record_without_auth_token() {
!update_base_case(
UpdateTestCase {
is_original_owner_authorized: False,
is_registry_updated: True,
is_registry_value_clean: True,
},
)
}

test fail_update_ownership_record_without_registry_update() {
!update_base_case(
UpdateTestCase {
is_original_owner_authorized: True,
is_registry_updated: False,
is_registry_value_clean: True,
},
)
}

test fail_update_ownership_record_without_clean_registry_value() {
!update_base_case(
UpdateTestCase {
is_original_owner_authorized: True,
is_registry_updated: True,
is_registry_value_clean: False,
},
)
}

0 comments on commit 7a1202e

Please sign in to comment.