Skip to content

Commit

Permalink
fix: add input nft checks by nft
Browse files Browse the repository at this point in the history
  • Loading branch information
HarunJr committed Sep 24, 2024
1 parent 11d3691 commit 6020152
Show file tree
Hide file tree
Showing 9 changed files with 643 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ off-chain/

.vscode/
assets/
plutus.json
# plutus.json
6 changes: 3 additions & 3 deletions aiken.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
name = "aiken-lang/payment-subscription"
name = "anastasia-labs/payment-subscription"
version = "0.0.0"
compiler = "v1.0.29-alpha"
plutus = "v2"
license = "Apache-2.0"
description = "Aiken contracts for project 'aiken-lang/payment-subscription'"
description = "Aiken contracts for project 'anastasia-labs/payment-subscription'"

[repository]
user = "aiken-lang"
user = "anastasia-labs"
project = "payment-subscription"
platform = "github"

Expand Down
Binary file modified docs/catalyst/milestone-completion.pdf
Binary file not shown.
38 changes: 24 additions & 14 deletions lib/payment-subscription/account-multi-validator/validation.ak
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use aiken/list
use aiken/transaction.{Input, Output, OutputReference, Transaction}
use aiken/transaction/credential.{Address}
use aiken/transaction/value.{PolicyId, Value}
use assist/count
use assist/data
use assist/payout
use assist/types/cip68
Expand Down Expand Up @@ -120,29 +119,40 @@ pub fn validate_update_account(
}

pub fn validate_remove_account(
account_addr: Address,
_account_addr: Address,
ref_nft: Value,
tx: Transaction,
) -> Bool {
expect [(policy_id, asset_name, _)] = value.flatten(ref_nft)

// Check that the reference NFT is burned
// Validate that there are two script inputs
expect [user_input, account_input, ..] = tx.inputs
let minted_value = value.from_minted_value(tx.mint)
let burn_quantity = value.quantity_of(minted_value, policy_id, asset_name)
let is_ref_nft_burned = burn_quantity == -1

let user_nft =
user_input.output.value
|> value.without_lovelace()

expect [(apolicy_id, ref_asset_name, _)] = value.flatten(ref_nft)
expect [(upolicy_id, usr_asset_name, _)] = value.flatten(user_nft)

// Check that the reference NFT is burned
and {
// Validate that there are two script input and one Script output back to the script address.
// two script input
count.inputs_by_addr(tx.inputs, account_addr, 2)?,
// one script output
count.outputs_by_addr(tx.outputs, account_addr, 1)?,
// Check that user input has a user nft,
(value.quantity_of(user_input.output.value, upolicy_id, usr_asset_name) == 1)?,
// Check that account input has a reference nft,
(value.quantity_of(account_input.output.value, apolicy_id, ref_asset_name) == 1)?,
// Check that the reference NFT is burned
is_ref_nft_burned?,
(value.quantity_of(minted_value, apolicy_id, ref_asset_name) == -1)?,
// Check that the user NFT is burned
(value.quantity_of(minted_value, upolicy_id, usr_asset_name) == -1)?,
// // One Script output leaving the script address.
// count.outputs_by_addr(tx.outputs, account_addr, 1)?,
// is_ref_nft_burned?,
// Ensure no output contains the reference NFT
list.all(
tx.outputs,
fn(output) { value.quantity_of(output.value, policy_id, asset_name) == 0 },
fn(output) {
value.quantity_of(output.value, apolicy_id, ref_asset_name) == 0
},
)?,
}
}
32 changes: 25 additions & 7 deletions lib/payment-subscription/service-multi-validator/validation.ak
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use aiken/transaction.{Input, Output, OutputReference, Transaction}
use aiken/transaction/credential.{Address}
use aiken/transaction/value.{PolicyId, Value}
use assist/count
use assist/data
use assist/payout
use assist/types/cip68
Expand Down Expand Up @@ -88,23 +87,30 @@ pub fn validate_update_service(
tx: Transaction,
) -> Bool {
// Find the output containing the reference NFT being sent back to this script itself
trace @"validate_update_service: 91"
let validating_output =
common_utils.output_by_addr_value(tx.outputs, service_addr, ref_nft)

// Extract the new datum from the validating output
trace @"validate_update_service: 94"
expect new_datum: ServiceDatum = data.output_datum(validating_output)

// Validate service fee changes are within acceptable range
trace @"validate_update_service: 100"
let service_fee_change_valid =
is_fee_change_valid(datum.service_fee_qty, new_datum.service_fee_qty)

and {
// Validate that the metadata of the Reference NFT is updated within acceptable bounds .
trace @"validate_update_service: 103"
is_service_metadata_valid(new_datum)?,
// Validate that the service fee should be limited to a range to prevent extreme flucutation in service
// fee by the service provider e.g +/-10%
trace @"validate_update_service: 107"
service_fee_change_valid?,
trace @"validate_update_service: 109"
payout.at_least(service_addr, ref_nft, tx.outputs)?,
trace @"validate_update_service: 111"
common_utils.check_nft_output_utxo(validating_output)?,
}
}
Expand All @@ -117,21 +123,33 @@ pub fn validate_remove_service(
) -> Bool {
let validating_output =
common_utils.output_by_addr_value(tx.outputs, service_addr, ref_nft)
expect [(policy_id, ref_asset_name, _)] = value.flatten(ref_nft)

// Validate that there are two script inputs
expect [user_input, service_input] = tx.inputs

let user_nft =
user_input.output.value
|> value.without_lovelace()

expect [(upolicy_id, usr_asset_name, _)] = value.flatten(user_nft)

// Extract the new datum from the validating output
expect new_datum: ServiceDatum = data.output_datum(validating_output)

// Ensure the service is being inactivated
let service_is_inactive = datum.is_active && !new_datum.is_active

let validating_output =
common_utils.output_by_addr_value(tx.outputs, service_addr, ref_nft)
let other_fields_unchanged =
datum.service_fee == new_datum.service_fee && datum.service_fee_qty == new_datum.service_fee_qty && datum.penalty_fee == new_datum.penalty_fee && datum.penalty_fee_qty == new_datum.penalty_fee_qty && datum.num_intervals == new_datum.num_intervals
and {
// Validate that there are two script input and two Script output back to the script address.
// two script input
count.inputs_by_addr(tx.inputs, service_addr, 2)?,
// two script output
count.outputs_by_addr(tx.outputs, service_addr, 2)?,
// Check that user input has a user nft,
(value.quantity_of(user_input.output.value, upolicy_id, usr_asset_name) == 1)?,
// Check that service input has a service nft,
(value.quantity_of(service_input.output.value, policy_id, ref_asset_name) == 1)?,
// // Validate that two Script output Leaving the script address.
// count.outputs_by_addr(tx.outputs, service_addr, 2)?,
// Check that the reference NFT is burned
service_is_inactive?,
other_fields_unchanged?,
Expand Down
16 changes: 10 additions & 6 deletions lib/payment-subscription/tests/account-multi-validator.ak
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ test succeed_update_account() {
let account_output_ref = tests.test_input_utxo_02(tests.test_224_01())

let datum = tests.test_datum_02("[email protected]", "(717) 550-1675", 1)
let new_datum = tests.test_datum_02("you@mail.com", "(717) 550-1675", 1)
let new_datum = tests.test_datum_02("me@mail.com", "(717) 550-1675", 1)

// let redeemer = UpdateAccount
let ref_tkn = values.unique_token_name(tx_hash, 1, cip68.prefix_100)
Expand Down Expand Up @@ -289,7 +289,7 @@ test succeed_update_account() {
validate_update_account(account_addr, ref_nft, context.transaction)
}

test succeed_remove_account() {
test success_remove_account() {
let own_cs = tests.test_224_01()
let tx_hash = tests.test_224_02()
let init_output_ref = tests.test_input_utxo_02(tx_hash)
Expand All @@ -301,16 +301,20 @@ test succeed_remove_account() {
let ref_tkn = values.unique_token_name(tx_hash, 1, cip68.prefix_100)
let user_tkn = values.unique_token_name(tx_hash, 1, cip68.prefix_222)

let ref_value = value.add(value.zero(), own_cs, ref_tkn, -1)
let user_value = value.add(value.zero(), own_cs, user_tkn, -1)
let minted_value = value.merge(ref_value, user_value)
let ref_value = value.add(value.zero(), own_cs, ref_tkn, 1)
let user_value = value.add(value.zero(), own_cs, user_tkn, 1)

let mint_ref_value = value.add(value.zero(), own_cs, ref_tkn, -1)
let mint_user_value = value.add(value.zero(), own_cs, user_tkn, -1)
let minted_value = value.merge(mint_ref_value, mint_user_value)

let user_input =
tests.test_context_input_02(init_output_ref, own_cs, user_value, NoDatum)
let account_input =
tests.test_context_input_02(account_output_ref, own_cs, ref_value, datum)

let user_output = tests.test_utxo_02(own_cs, user_value, 100_000_000, NoDatum)
let user_output =
tests.test_utxo_02(own_cs, mint_user_value, 100_000_000, NoDatum)

let context =
ScriptContext {
Expand Down
1 change: 1 addition & 0 deletions lib/payment-subscription/tests/service-multi-validator.ak
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ test success_remove_service() {

let ref_value = value.add(value.zero(), own_cs, ref_tkn, 1)
let user_value = value.add(value.zero(), own_cs, user_tkn, 1)

let minted_value = value.merge(ref_value, user_value)

let user_input =
Expand Down
Loading

0 comments on commit 6020152

Please sign in to comment.