diff --git a/lib/assist/types/token.ak b/lib/assist/types/token.ak index 9f908b4..55efa38 100644 --- a/lib/assist/types/token.ak +++ b/lib/assist/types/token.ak @@ -4,6 +4,7 @@ //// instead of building out the value type directly which could be harmful. //// +use aiken/dict use aiken/list use aiken/transaction/value.{AssetName, PolicyId, Value} @@ -239,3 +240,47 @@ test add_and_subtract_tokens_to_value() { let token2: Token = Token { pid: #"", tkn: #"", amt: -10 } add_tokens_to_value(zero, [token1, token2]) == zero } + +/// Convert a value into a list of tokens. This conversation is a fast way +/// to be able to do multiplication on a value. +/// +/// ```aiken +/// token.from_value(this_value) +/// ``` +pub fn from_value(v: Value) -> Tokens { + value.to_dict(v) + |> dict.foldl( + [], + fn(pid, assets, tokens) { + dict.foldl( + assets, + tokens, + fn(tkn, amt, tokens) { list.push(tokens, Token { pid, tkn, amt }) }, + ) + }, + ) +} + +test from_zero_value() { + let v: Value = value.zero() + let e: Tokens = + [] + from_value(v) == e +} + +test from_lovelace_value() { + let v: Value = value.from_lovelace(123) + let e: Tokens = + [Token { pid: value.ada_policy_id, tkn: value.ada_asset_name, amt: 123 }] + from_value(v) == e +} + +test from_general_value() { + let v: Value = value.from_lovelace(123) |> value.add(#"acab", #"cafe", 41) + let e: Tokens = + [ + Token { pid: #"acab", tkn: #"cafe", amt: 41 }, + Token { pid: value.ada_policy_id, tkn: value.ada_asset_name, amt: 123 }, + ] + from_value(v) == e +} diff --git a/lib/assist/values.ak b/lib/assist/values.ak index 0642daf..10c1611 100644 --- a/lib/assist/values.ak +++ b/lib/assist/values.ak @@ -52,6 +52,27 @@ fn do_from_tokens(val: Value, tokens: Tokens) -> Value { } } +test from_value_then_multiply_back_to_value() { + let v: Value = value.from_lovelace(2) + let ts: Tokens = token.from_value(v) + let n: Int = 52314523 + let ans: Value = product([], ts, n) |> from_tokens() + let exp: Value = value.from_lovelace(104629046) + ans == exp +} + +fn product(ans: Tokens, ts: Tokens, n: Int) -> Tokens { + when ts is { + // take a token and add it to the value + [tkn, ..tkns] -> + ans + |> list.push(Token { pid: tkn.pid, tkn: tkn.tkn, amt: n * tkn.amt }) + |> product(tkns, n) + // everything is negative + [] -> ans + } +} + /// Multiply some value by `n`. This is just a linear scaling to the quantity /// of each token. /// @@ -59,18 +80,8 @@ fn do_from_tokens(val: Value, tokens: Tokens) -> Value { /// values.multiply(bundle_value, bundle_size) /// ``` pub fn multiply(val: Value, n: Int) -> Value { - do_multiply(value.zero(), val, n) -} - -// Internal only -fn do_multiply(total: Value, add_val: Value, n: Int) -> Value { - // 4 * v = v + v + v + v - if n <= 0 { - total - } else { - // add to total - do_multiply(value.merge(total, add_val), add_val, n - 1) - } + let ts: Tokens = token.from_value(val) + product([], ts, n) |> from_tokens() } test values_multiply_by_0() { @@ -85,6 +96,12 @@ test values_multiply_by_4() { multiply(val, 4) == ans } +test values_multiply_by_52314523() { + let val: Value = value.from_lovelace(2) + let ans: Value = value.from_lovelace(104629046) + multiply(val, 52314523) == ans +} + /// Prove that the target value is contained inside another value. Each token /// inside the target must exist inside the total value. The quantity of each /// token must be at least the target amount or greater.