Skip to content

Commit

Permalink
feat: building content registry token
Browse files Browse the repository at this point in the history
  • Loading branch information
HinsonSIDAN committed Nov 26, 2023
1 parent 780eae4 commit e0e7f5c
Show file tree
Hide file tree
Showing 6 changed files with 299 additions and 86 deletions.
67 changes: 56 additions & 11 deletions lib/aiken-content-ownership/common.ak
Original file line number Diff line number Diff line change
@@ -1,21 +1,62 @@
use aiken/bytearray
use aiken/list
use aiken/transaction.{Output}
use aiken/transaction.{Input, Output}
use aiken/transaction/credential.{Address}
use aiken/transaction/value.{
AssetName, MintedValue, PolicyId, flatten, from_minted_value, quantity_of,
AssetName, MintedValue, PolicyId, Value, flatten, from_minted_value,
quantity_of,
}

pub fn utxos_at(outputs: List<Output>, address: Address) {
pub fn inputs_at(inputs: List<Input>, address: Address) -> List<Input> {
list.filter(inputs, fn(input) { input.output.address == address })
}

pub fn inputs_with(
inputs: List<Input>,
policy: PolicyId,
name: AssetName,
) -> List<Input> {
list.filter(
inputs,
fn(input) { quantity_of(input.output.value, policy, name) == 1 },
)
}

pub fn inputs_at_with(
inputs: List<Input>,
address: Address,
policy: PolicyId,
name: AssetName,
) -> List<Input> {
list.filter(
inputs,
fn(input) {
input.output.address == address && quantity_of(
input.output.value,
policy,
name,
) == 1
},
)
}

pub fn outputs_at(outputs: List<Output>, address: Address) -> List<Output> {
list.filter(outputs, fn(output) { output.address == address })
}

pub fn utxos_at_with(
pub fn outputs_with(outputs: List<Output>, policy: PolicyId, name: AssetName) {
list.filter(
outputs,
fn(output) { quantity_of(output.value, policy, name) == 1 },
)
}

pub fn outputs_at_with(
outputs: List<Output>,
address: Address,
policy: PolicyId,
name: AssetName,
) {
) -> List<Output> {
list.filter(
outputs,
fn(output) {
Expand Down Expand Up @@ -62,16 +103,20 @@ fn go_get_number_digit(newInt: Int, digit: Int) -> Int {
}
}

test byte_conversion() {
convert_int_to_bytes(1) == "1" && convert_int_to_bytes(123) == "123" && convert_int_to_bytes(
672912,
) == "672912"
}

pub fn key_signed(witnesses: List<ByteArray>, key: ByteArray) {
list.has(witnesses, key)
}

pub fn all_key_signed(witnesses: List<ByteArray>, keys: List<ByteArray>) {
list.all(keys, fn(key) { key_signed(witnesses, key) })
}

pub fn value_length(value: Value) -> Int {
list.length(flatten(value))
}

test byte_conversion() {
convert_int_to_bytes(1) == "1" && convert_int_to_bytes(123) == "123" && convert_int_to_bytes(
672912,
) == "672912"
}
58 changes: 56 additions & 2 deletions lib/aiken-content-ownership/placeholder.ak
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
use aiken/transaction.{NoDatum, Output, OutputReference, TransactionId}
use aiken/dict.{Dict}
use aiken/transaction.{
InlineDatum, NoDatum, Output, OutputReference, TransactionId,
}
use aiken/transaction/credential.{
Address, Credential, ScriptCredential, VerificationKeyCredential,
}
use aiken/transaction/value.{PolicyId, from_lovelace}
use aiken/transaction/value.{PolicyId, add, from_asset, from_lovelace}
use aiken_content_ownership/types.{ContentRegistryDatum, OracleDatum}
use aiken_content_ownership/utils.{get_registry_token_name}

pub fn mock_policy_id() -> PolicyId {
#"1c1b7afe8affbee1505cf3ec5a58bd2734d4ffdfcc9b9f059625bd76"
Expand Down Expand Up @@ -115,3 +120,52 @@ pub fn mock_script_address_3(stake_credential) -> Address {
stake_credential,
}
}

// Smart contract specific placeholders
pub fn mock_oracle_datum() {
OracleDatum {
oracle_nft: mock_policy_id(),
oracle_address: mock_script_address(None),
content_registry_ref_token: mock_policy_id_2(),
content_registry_address: mock_script_address_2(None),
ownership_registry_ref_token: mock_policy_id_3(),
ownership_registry_address: mock_script_address_3(None),
content_registry_count: 0,
ownership_registry_count: 0,
operation_key: mock_vkey_hex(),
stop_key: mock_vkey_hex_2(),
}
}

pub fn mock_oracle_output(oracle_datum: OracleDatum) -> Output {
Output {
address: mock_script_address(None),
value: from_asset(mock_policy_id(), "", 1) |> add(#"", #"", 2_000_000),
datum: InlineDatum(oracle_datum),
reference_script: None,
}
}

pub fn mock_content_registry_datum(
count: Int,
registry: Dict<Int, ByteArray>,
) -> ContentRegistryDatum {
ContentRegistryDatum { count, registry }
}

pub fn mock_content_registry_output(
registry_count: Int,
registry_datum: ContentRegistryDatum,
) -> Output {
Output {
address: mock_script_address_2(None),
value: from_asset(
mock_policy_id_2(),
get_registry_token_name(registry_count),
1,
)
|> add(#"", #"", 2_000_000),
datum: InlineDatum(registry_datum),
reference_script: None,
}
}
38 changes: 38 additions & 0 deletions lib/aiken-content-ownership/types.ak
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use aiken/dict.{Dict}
use aiken/transaction/credential.{Address}
use aiken/transaction/value.{AssetName, PolicyId}

pub type MintPolarity {
RMint
RBurn
}

pub type OracleDatum {
oracle_nft: PolicyId,
oracle_address: Address,
content_registry_ref_token: PolicyId,
content_registry_address: Address,
content_registry_count: Int,
ownership_registry_ref_token: PolicyId,
ownership_registry_address: Address,
ownership_registry_count: Int,
operation_key: ByteArray,
stop_key: ByteArray,
}

pub type OracleRedeemer {
CreateContentRegistry
CreateOwnershipRegistry
RotateKey { new_operation_key: ByteArray, new_stop_key: ByteArray }
StopApp
}

pub type ContentRegistryDatum {
count: Int,
registry: Dict<Int, ByteArray>,
}

pub type OwnershipRegistryDatum {
count: Int,
registry: Dict<Int, (PolicyId, AssetName)>,
}
116 changes: 116 additions & 0 deletions validators/content_registry_ref_token.ak
Original file line number Diff line number Diff line change
@@ -1 +1,117 @@
use aiken/dict
// use aiken/list
use aiken/transaction.{
InlineDatum, Input, Mint, ScriptContext, Transaction, placeholder,
}
use aiken/transaction/value.{PolicyId, from_asset, to_minted_value}
use aiken_content_ownership/common.{inputs_with, outputs_at_with, value_length}
use aiken_content_ownership/placeholder.{
mock_content_registry_datum, mock_content_registry_output, mock_oracle_datum,
mock_oracle_output, mock_policy_id, mock_policy_id_2, mock_utxo_ref,
}
use aiken_content_ownership/types.{
ContentRegistryDatum, MintPolarity, OracleDatum, RBurn, RMint,
}
use aiken_content_ownership/utils.{get_registry_token_name}

validator(oracle_nft: PolicyId) {
fn content_registry_ref_token(
redeemer: MintPolarity,
context: ScriptContext,
) -> Bool {
let ScriptContext { purpose, transaction } = context
let Transaction { inputs, outputs, .. } = transaction
when purpose is {
Mint(_) ->
when (redeemer, inputs_with(inputs, oracle_nft, "")) is {
(RMint, [oracle_input]) -> {
expect InlineDatum(inline_datum) = oracle_input.output.datum
expect input_datum: OracleDatum = inline_datum
let OracleDatum {
oracle_address,
content_registry_ref_token,
content_registry_address,
content_registry_count,
..
} = input_datum
when
(
outputs_at_with(outputs, oracle_address, oracle_nft, ""),
outputs_at_with(
outputs,
content_registry_address,
content_registry_ref_token,
get_registry_token_name(content_registry_count),
),
)
is {
([oracle_output], [registry_output]) -> {
expect InlineDatum(raw_oracle_datum) = oracle_output.datum
expect InlineDatum(raw_registry_datum) = registry_output.datum
expect oracle_datum: OracleDatum = raw_oracle_datum
expect ContentRegistryDatum { count, registry }: ContentRegistryDatum =
raw_registry_datum
let oracle_datum_updated =
oracle_datum == OracleDatum {
..input_datum,
content_registry_count: content_registry_count + 1,
}
let registry_initial_datum_correct =
count == 0 && registry == dict.new()
let oracle_output_value_clean =
value_length(oracle_output.value) == 2
let registry_output_value_clean =
value_length(registry_output.value) == 2
oracle_datum_updated && registry_initial_datum_correct && oracle_output_value_clean && registry_output_value_clean
}
_ -> False
}
}
(RBurn, _) -> True
_ -> False
}
_ -> False
}
}
}

fn make_mock_tx_body(record_count: Int) -> Transaction {
Transaction {
..placeholder(),
mint: to_minted_value(
from_asset(mock_policy_id_2(), get_registry_token_name(record_count), 1),
),
inputs: [
Input {
output_reference: mock_utxo_ref(1),
output: mock_oracle_output(mock_oracle_datum()),
},
],
outputs: [
mock_oracle_output(
OracleDatum {
..mock_oracle_datum(),
content_registry_count: record_count + 1,
},
),
mock_content_registry_output(
record_count,
mock_content_registry_datum(0, dict.new()),
),
],
}
}

test success_mint() {
let redeemer = RMint
let tx = make_mock_tx_body(0)
let ctx = ScriptContext { purpose: Mint(mock_policy_id_2()), transaction: tx }
content_registry_ref_token(mock_policy_id(), redeemer, ctx)
}

test fail_mint_without_update_oracle() {
let redeemer = RMint
let tx = make_mock_tx_body(0)
let ctx = ScriptContext { purpose: Mint(mock_policy_id()), transaction: tx }
!content_registry_ref_token(mock_policy_id(), redeemer, ctx)
}
11 changes: 5 additions & 6 deletions validators/one_time_minting_policy.ak
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ use aiken/transaction/value.{
use aiken_content_ownership/placeholder.{
mock_output, mock_policy_id, mock_policy_id_2, mock_utxo_ref,
}

type Redeemer {
RMint
RBurn
}
use aiken_content_ownership/types.{MintPolarity, RBurn, RMint}

validator(utxo_ref: OutputReference) {
fn one_time_minting_policy(redeemer: Redeemer, context: ScriptContext) -> Bool {
fn one_time_minting_policy(
redeemer: MintPolarity,
context: ScriptContext,
) -> Bool {
let ScriptContext { purpose, transaction } = context
when purpose is {
Mint(current_policy) ->
Expand Down
Loading

0 comments on commit e0e7f5c

Please sign in to comment.