Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 81 additions & 37 deletions lib/cardano/assets.ak
Original file line number Diff line number Diff line change
Expand Up @@ -149,53 +149,65 @@ fn do_contains(
}
}

/// Check whether a `Value` carries any NFT from the given policy. Other assets are tolerated.
/// Check whether a `Value` contains any token under the given policy whose
/// quantity is exactly `1`. Other assets are tolerated.
///
/// This only speaks about uniqueness *within the given `Value`*.
///
/// ```aiken
/// let value = assets.from_lovelace(42)
/// |> assets.add("foo", "asset#1", 1)
/// |> assets.add("bar", "asset#2", 14)
///
/// assets.has_any_nft(value, "foo") == True
/// assets.has_any_nft(value, "bar") == False
/// assets.has_any_nft(value, "baz") == False
/// assets.has_any_unique(value, "foo") == True
/// assets.has_any_unique(value, "bar") == False
/// assets.has_any_unique(value, "baz") == False
/// ```
pub fn has_any_nft(self: Value, policy: PolicyId) -> Bool {
pub fn has_any_unique(self: Value, policy: PolicyId) -> Bool {
tokens(self, policy)
|> dict.foldr(False, fn(_, quantity, result) { result || 1 == quantity })
}

/// Check whether a `Value` carries any NFT from the given policy. Other assets (other than
/// Ada) aren't tolerated. Said differently, the check succeeds if and only if
/// the value contains no assets other than the expected NFT or Ada.
/// Backward-compatible alias for [`has_any_unique`](#has_any_unique).
///
/// This checks whether a token is unique within the given `Value`; it does not
/// prove any blockchain-wide NFT property.
pub fn has_any_nft(self: Value, policy: PolicyId) -> Bool {
has_any_unique(self, policy)
}

/// Check whether a `Value` contains exactly one token under the given policy,
/// optionally alongside Ada.
///
/// This only speaks about uniqueness *within the given `Value`*.
///
/// ```aiken
/// let value = assets.from_lovelace(42)
/// |> assets.add("foo", "asset#1", 1)
/// |> assets.add("bar", "asset#2", 14)
///
/// assets.has_any_nft_strict(value, "foo") == False
/// assets.has_any_nft_strict(value, "bar") == False
/// assets.has_any_nft_strict(value, "baz") == False
/// assets.has_any_unique_strict(value, "foo") == False
/// assets.has_any_unique_strict(value, "bar") == False
/// assets.has_any_unique_strict(value, "baz") == False
/// ```
///
/// ```aiken
/// let value = assets.from_lovelace(42)
/// |> assets.add("foo", "asset#1", 1)
///
/// assets.has_any_nft_strict(value, "foo") == True
/// assets.has_any_nft_strict(value, "bar") == False
/// assets.has_any_unique_strict(value, "foo") == True
/// assets.has_any_unique_strict(value, "bar") == False
/// ```
///
/// ```aiken
/// let value = assets.from_lovelace(42)
/// |> assets.add("foo", "asset#1", 1)
/// |> assets.add("foo", "asset#2", 1)
///
/// assets.has_any_nft_strict(value, "foo") == False
/// assets.has_any_nft_strict(value, "bar") == False
/// assets.has_any_unique_strict(value, "foo") == False
/// assets.has_any_unique_strict(value, "bar") == False
/// ```
pub fn has_any_nft_strict(self: Value, policy: PolicyId) -> Bool {
pub fn has_any_unique_strict(self: Value, policy: PolicyId) -> Bool {
let check_inner = fn(p, inner) {
and {
policy == p,
Expand All @@ -218,64 +230,84 @@ pub fn has_any_nft_strict(self: Value, policy: PolicyId) -> Bool {
}
}

/// Check whether a `Value` carries a specific NFT. Other assets are tolerated.
/// Backward-compatible alias for [`has_any_unique_strict`](#has_any_unique_strict).
///
/// This checks whether a token is unique within the given `Value`; it does not
/// prove any blockchain-wide NFT property.
pub fn has_any_nft_strict(self: Value, policy: PolicyId) -> Bool {
has_any_unique_strict(self, policy)
}

/// Check whether a `Value` contains exactly one unit of a specific token. Other
/// assets are tolerated.
///
/// This only speaks about uniqueness *within the given `Value`*.
///
/// ```aiken
/// let value = assets.from_lovelace(42)
/// |> assets.add("foo", "asset#1", 1)
/// |> assets.add("bar", "asset#2", 14)
///
/// assets.has_nft(value, "foo", "asset#1") == True
/// assets.has_nft(value, "foo", "asset#2") == False
/// assets.has_nft(value, "bar", "asset#2") == False
/// assets.has_nft(value, "baz", "asset#3") == False
/// assets.has_unique(value, "foo", "asset#1") == True
/// assets.has_unique(value, "foo", "asset#2") == False
/// assets.has_unique(value, "bar", "asset#2") == False
/// assets.has_unique(value, "baz", "asset#3") == False
/// ```
///
/// ```aiken
/// let value = assets.from_lovelace(42)
/// |> assets.add("foo", "asset#1", 1)
/// |> assets.add("foo", "asset#2", 1)
///
/// assets.has_nft(value, "foo", "asset#1") == True
/// assets.has_nft(value, "foo", "asset#2") == True
/// assets.has_nft(value, "bar", "asset#2") == False
/// assets.has_unique(value, "foo", "asset#1") == True
/// assets.has_unique(value, "foo", "asset#2") == True
/// assets.has_unique(value, "bar", "asset#2") == False
/// ```
pub fn has_nft(self: Value, policy: PolicyId, asset_name: AssetName) -> Bool {
pub fn has_unique(self: Value, policy: PolicyId, asset_name: AssetName) -> Bool {
1 == quantity_of(self, policy, asset_name)
}

/// Check whether a `Value` carries a specific NFT. Other assets (other than
/// Ada) aren't tolerated. Said differently, the check succeeds if and only if
/// the value contains no assets other than the expected NFT or Ada.
/// Backward-compatible alias for [`has_unique`](#has_unique).
///
/// This checks whether a token is unique within the given `Value`; it does not
/// prove any blockchain-wide NFT property.
pub fn has_nft(self: Value, policy: PolicyId, asset_name: AssetName) -> Bool {
has_unique(self, policy, asset_name)
}

/// Check whether a `Value` contains no assets other than exactly one unit of a
/// specific token and optional Ada.
///
/// This only speaks about uniqueness *within the given `Value`*.
///
/// ```aiken
/// let value = assets.from_lovelace(42)
/// |> assets.add("foo", "asset#1", 1)
/// |> assets.add("bar", "asset#2", 14)
///
/// assets.has_nft_strict(value1, "foo", "asset#1") == False
/// assets.has_nft_strict(value1, "bar", "asset#2") == False
/// assets.has_nft_strict(value1, "baz", "asset#3") == False
/// assets.has_unique_strict(value1, "foo", "asset#1") == False
/// assets.has_unique_strict(value1, "bar", "asset#2") == False
/// assets.has_unique_strict(value1, "baz", "asset#3") == False
/// ```
///
/// ```aiken
/// let value = assets.from_lovelace(42)
/// |> assets.add("foo", "asset#1", 1)
///
/// assets.has_nft_strict(value, "foo", "asset#1") == True
/// assets.has_nft_strict(value, "foo", "asset#2") == False
/// assets.has_nft_strict(value, "bar", "asset#2") == False
/// assets.has_unique_strict(value, "foo", "asset#1") == True
/// assets.has_unique_strict(value, "foo", "asset#2") == False
/// assets.has_unique_strict(value, "bar", "asset#2") == False
/// ```
///
/// ```aiken
/// let value = assets.from_lovelace(42)
/// |> assets.add("foo", "asset#1", 1)
/// |> assets.add("foo", "asset#2", 1)
///
/// assets.has_nft_strict(value3, "foo", "asset#1") == False
/// assets.has_nft_strict(value3, "foo", "asset#2") == False
/// assets.has_unique_strict(value3, "foo", "asset#1") == False
/// assets.has_unique_strict(value3, "foo", "asset#2") == False
/// ```
pub fn has_nft_strict(
pub fn has_unique_strict(
self: Value,
policy: PolicyId,
asset_name: AssetName,
Expand All @@ -294,6 +326,18 @@ pub fn has_nft_strict(
)
}

/// Backward-compatible alias for [`has_unique_strict`](#has_unique_strict).
///
/// This checks whether a token is unique within the given `Value`; it does not
/// prove any blockchain-wide NFT property.
pub fn has_nft_strict(
self: Value,
policy: PolicyId,
asset_name: AssetName,
) -> Bool {
has_unique_strict(self, policy, asset_name)
}

/// Check is a `Value` is zero. That is, it has no assets and holds no Ada/Lovelace.
pub fn is_zero(self: Value) -> Bool {
zero == self
Expand Down
47 changes: 38 additions & 9 deletions lib/cardano/assets.test.ak
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use cardano/assets.{
AssetName, PolicyId, Value, ada_asset_name, ada_policy_id, add, difference,
expect_lovelace_of, expect_match, expect_match_assets, flatten, flatten_with,
from_ascending_pairs, from_asset, from_asset_list, from_lovelace, has_any_nft,
has_any_nft_strict, has_nft, has_nft_strict, lovelace_of, match, match_assets,
has_any_nft_strict, has_any_unique, has_any_unique_strict, has_nft, has_nft_strict,
has_unique, has_unique_strict, lovelace_of, match, match_assets,
merge, negate, reduce, restricted_to, without_lovelace, zero,
}
use cardano/assets/strategy
Expand Down Expand Up @@ -516,24 +517,38 @@ test prop_contains_superset_mutation(

test has_nft_with_fixture_1() {
and {
// has_any_nft
// has_any_nft / has_any_unique
has_any_nft(has_nft_fixture_1, "foo")?,
has_any_unique(has_nft_fixture_1, "foo")?,
(!has_any_nft(has_nft_fixture_1, "bar"))?,
(!has_any_unique(has_nft_fixture_1, "bar"))?,
(!has_any_nft(has_nft_fixture_1, "baz"))?,
// has_any_nft_strict
(!has_any_unique(has_nft_fixture_1, "baz"))?,
// has_any_nft_strict / has_any_unique_strict
(!has_any_nft_strict(has_nft_fixture_1, "foo"))?,
(!has_any_unique_strict(has_nft_fixture_1, "foo"))?,
(!has_any_nft_strict(has_nft_fixture_1, "bar"))?,
(!has_any_unique_strict(has_nft_fixture_1, "bar"))?,
(!has_any_nft_strict(has_nft_fixture_1, "baz"))?,
// has_nft
(!has_any_unique_strict(has_nft_fixture_1, "baz"))?,
// has_nft / has_unique
has_nft(has_nft_fixture_1, "foo", "asset#1")?,
has_unique(has_nft_fixture_1, "foo", "asset#1")?,
(!has_nft(has_nft_fixture_1, "foo", "asset#2"))?,
(!has_unique(has_nft_fixture_1, "foo", "asset#2"))?,
(!has_nft(has_nft_fixture_1, "bar", "asset#2"))?,
(!has_unique(has_nft_fixture_1, "bar", "asset#2"))?,
(!has_nft(has_nft_fixture_1, "baz", "asset#1"))?,
// has_nft_strict
(!has_unique(has_nft_fixture_1, "baz", "asset#1"))?,
// has_nft_strict / has_unique_strict
(!has_nft_strict(has_nft_fixture_1, "foo", "asset#1"))?,
(!has_unique_strict(has_nft_fixture_1, "foo", "asset#1"))?,
(!has_nft_strict(has_nft_fixture_1, "foo", "asset#2"))?,
(!has_unique_strict(has_nft_fixture_1, "foo", "asset#2"))?,
(!has_nft_strict(has_nft_fixture_1, "bar", "asset#2"))?,
(!has_unique_strict(has_nft_fixture_1, "bar", "asset#2"))?,
(!has_nft_strict(has_nft_fixture_1, "baz", "asset#1"))?,
(!has_unique_strict(has_nft_fixture_1, "baz", "asset#1"))?,
}
}

Expand Down Expand Up @@ -563,24 +578,38 @@ test has_nft_with_fixture_1_without_lovelace() {

test has_nft_with_fixture_2() {
and {
// has_any_nft
// has_any_nft / has_any_unique
has_any_nft(has_nft_fixture_2, "foo")?,
has_any_unique(has_nft_fixture_2, "foo")?,
(!has_any_nft(has_nft_fixture_2, "bar"))?,
(!has_any_unique(has_nft_fixture_2, "bar"))?,
(!has_any_nft(has_nft_fixture_2, "baz"))?,
// has_any_nft_strict
(!has_any_unique(has_nft_fixture_2, "baz"))?,
// has_any_nft_strict / has_any_unique_strict
has_any_nft_strict(has_nft_fixture_2, "foo")?,
has_any_unique_strict(has_nft_fixture_2, "foo")?,
(!has_any_nft_strict(has_nft_fixture_2, "bar"))?,
(!has_any_unique_strict(has_nft_fixture_2, "bar"))?,
(!has_any_nft_strict(has_nft_fixture_2, "baz"))?,
// has_nft
(!has_any_unique_strict(has_nft_fixture_2, "baz"))?,
// has_nft / has_unique
has_nft(has_nft_fixture_2, "foo", "asset#1")?,
has_unique(has_nft_fixture_2, "foo", "asset#1")?,
(!has_nft(has_nft_fixture_2, "foo", "asset#2"))?,
(!has_unique(has_nft_fixture_2, "foo", "asset#2"))?,
(!has_nft(has_nft_fixture_2, "bar", "asset#2"))?,
(!has_unique(has_nft_fixture_2, "bar", "asset#2"))?,
(!has_nft(has_nft_fixture_2, "baz", "asset#1"))?,
// has_nft_strict
(!has_unique(has_nft_fixture_2, "baz", "asset#1"))?,
// has_nft_strict / has_unique_strict
has_nft_strict(has_nft_fixture_2, "foo", "asset#1")?,
has_unique_strict(has_nft_fixture_2, "foo", "asset#1")?,
(!has_nft_strict(has_nft_fixture_2, "foo", "asset#2"))?,
(!has_unique_strict(has_nft_fixture_2, "foo", "asset#2"))?,
(!has_nft_strict(has_nft_fixture_2, "bar", "asset#2"))?,
(!has_unique_strict(has_nft_fixture_2, "bar", "asset#2"))?,
(!has_nft_strict(has_nft_fixture_2, "baz", "asset#1"))?,
(!has_unique_strict(has_nft_fixture_2, "baz", "asset#1"))?,
}
}

Expand Down