plutarch-ledger-api
Safe HaskellSafe-Inferred
LanguageHaskell2010

Plutarch.LedgerApi.V3.Value

Description

Conversions between ledger API representations of Values and the new PBuiltinValue, plus some utility functions.

Why is this module necessary?

In almost all situations, Values will be provided to a script as their Data encodings, whether this is through an input or a PScriptContext. plutarch-ledger-api has an extensive collection of functions for dealing with such representations, as well as a range of newtype wrappers to provide guarantees of form when doing so.

However, as these operations have to work over (effectively) nested cons lists, they are not efficient for many operations, especially simpler ones like lookups or primitive insertions. In this regard, PBuiltinValue excels, as these are calls to builtin operations, which are much more efficient. However, some conversion cost must be paid to go from the Data encoding to a PBuiltinValue.

In addition to this, the UnValueData primitive has quite specific expectations of any Data it is given. More precisely, the argument must:

  • Be made using the Map constructor;
  • Every 'key' must be encoded using the B constructor, and be at most 32 bytes in length;
  • Every 'value' must be a non-empty list of key-value pairs.
  • Every 'inner key' must be encoded using the B constructor, and be at most 32 bytes in length;
  • Every 'inner value' must be encoded using the I constructor, and be non-zero, as well as fitting within a 128-bit signed integer;
  • 'Keys', both 'outer' and 'inner', must be in strictly ascending order, which implies no duplicates.

Any deviation from this will cause the builtin to error. Thus, of all the newtypes provided for structural safety by plutarch-ledger-api, only PMintValue is suitable.

To make matters worse, the inverse ValueData builtin does not guarantee that an arbitrary PBuiltinValue will satisfy the structural requirements of a PMintValue, as it may contain an Ada entry. Thus, if 'converting back' is required, we can only guarantee a PSortedValue. Any other conversion is technically speaking unsafe and may error. Worse still, there is no straightforward way to verify what kind of 'inner' or 'outer' keys a PBuiltinValue contains without converting it first!

Thus, this module provides clearly labelled conversions, safe and unsafe, as well as some helper wrapper functions to make PBuiltinValue easier to use with other types provided by plutarch-ledger-api.

Since: 3.7.0

Synopsis

Conversions

Safe

pfromRawValue :: forall (r :: S -> Type) (s :: S). Term s PRawValue -> Term s r -> Term s (PBuiltinValue :--> r) -> Term s r Source #

After verifying the conversion is safe, convert a PRawValue Data representation into a PBuiltinValue. To save on allocations, this is written in a continuation-passing style:

  • The second argument is what should happen if validation fails; and
  • The third argument is what should happen if validation succeeds.

Important note

This operation is slow, as it has to check the entire input.

Since: 3.7.0

pfromSortedValue :: forall (r :: S -> Type) (s :: S). Term s PSortedValue -> Term s r -> Term s (PBuiltinValue :--> r) -> Term s r Source #

As pfromRawValue, except for PSortedValues instead. This is more efficient, as we only need to check for the absence of zero amounts.

Since: 3.7.0

pfromMintValue :: forall (s :: S). Term s (PAsData PMintValue) -> Term s PBuiltinValue Source #

Convert the Data representation of a PMintValue to a PBuiltinValue. This is done via a builtin (thus efficient), and is safe.

Since: 3.7.0

ptoSortedValue :: forall (s :: S). Term s PBuiltinValue -> Term s (PAsData PSortedValue) Source #

Convert a PBuiltinValue into the Data representation of a PSortedValue. This is done via a builtin (thus efficient), and is safe.

If you need to convert to something less specific, use pupcast.

Since: 3.7.0

ptoLedgerValue :: forall (r :: S -> Type) (s :: S). Term s PBuiltinValue -> Term s r -> Term s (PAsData PLedgerValue :--> r) -> Term s r Source #

Checks for an Ada entry in the input PBuiltinValue. If none is found, produce the second argument; otherwise, convert the PBuiltinValue into a PAsData PLedgerValue and call the third argument with it.

Since: 3.7.0

ptoLedgerValue' :: forall (s :: S). Term s PBuiltinValue -> Term s PLedgerValue Source #

As ptoLedgerValue, but 'fills in' a zero ADA entry if one is missing. This is a costly operation, as it must be done after conversion. Use with care.

Since: 3.7.0

ptoMintValue :: forall (r :: S -> Type) (s :: S). Term s PBuiltinValue -> Term s r -> Term s (PAsData PMintValue :--> r) -> Term s r Source #

As ptoLedgerValue, except the check is for the absence of an Ada entry, and the third argument is called with a PAsData PMintValue instead when appropriate.

Since: 3.7.0

Unsafe

punsafeFromRawValue :: forall (s :: S). Term s (PAsData PRawValue) -> Term s PBuiltinValue Source #

Convert the Data representation of a PRawValue into a PBuiltinValue while not doing any checks.

This is not safe, and will error if any of the invariants of PBuiltinValue are violated. Use with care.

Since: 3.7.0

punsafeFromSortedValue :: forall (s :: S). Term s (PAsData PSortedValue) -> Term s PBuiltinValue Source #

As punsafeFromRawValue, except for PSortedValues instead. The same caveats apply.

Since: 3.7.0

punsafeToLedgerValue :: forall (s :: S). Term s PBuiltinValue -> Term s (PAsData PLedgerValue) Source #

Convert a PBuiltinValue into a PAsData PLedgerValue without checking anything. Only use this if you are certain that the PBuiltinValue does not violate any internal invariants of PLedgerValue. In particular, there must be an Ada amount in the argument PMintValue.

Since: 3.7.0

punsafeToMintValue :: forall (s :: S). Term s PBuiltinValue -> Term s (PAsData PMintValue) Source #

Convert a PBuiltinValue into a PAsData PLedgerValue without checking anything. Only use this if you are certain that the PBuiltinValue does not violate any internal invariants of PMintValue. In particular, there should not be an Ada amount in the argument PMintValue.

Since: 3.7.0

Construction

pemptyBuiltinValue :: forall (s :: S). Term s PBuiltinValue Source #

The PBuiltinValue without any amounts.

Since: 3.7.0

psingletonBuiltinValue :: forall (s :: S). Term s (PCurrencySymbol :--> (PTokenName :--> (PInteger :--> PBuiltinValue))) Source #

A PBuiltinValue containing an amount of a single currency-token name combination. If the PInteger argument is 0, this will be identical to pemptyBuiltinValue.

Since: 3.7.0

Queries

pvalueOf :: forall (s :: S). Term s (PCurrencySymbol :--> (PTokenName :--> (PBuiltinValue :--> PInteger))) Source #

Look up the amount associated with a given combination of PCurrencySymbol and PTokenName in the given PBuiltinValue. As PBuiltinValue cannot store zero amounts, if this returns 0, it means that no amount is associated with the given combination of PCurrencySymbol and PTokenName in this 'PBuiltinValue.

Since: 3.7.0

plovelaceValueOf :: forall (s :: S). Term s (PBuiltinValue :--> PInteger) Source #

As pvalueOf, but for Lovelace specifically. The same caveats apply.

Since: 3.7.0

Updates

preplaceAmountPositive :: forall (s :: S). Term s (PCurrencySymbol :--> (PTokenName :--> (PPositive :--> (PBuiltinValue :--> PBuiltinValue)))) Source #

Replace the amount at the given currency-token name combination in the given PBuiltinValue with the given amount. The new amount will be positive. If the given currency-token name combination does not exist, create it.

Note

A PBuiltinValue cannot store an amount that would not fit into a 128-bit signed integer. This function will error if the result would be forced to store such an amount.

Since: 3.7.0

preplaceAmountNegative :: forall (s :: S). Term s (PCurrencySymbol :--> (PTokenName :--> (PPositive :--> (PBuiltinValue :--> PBuiltinValue)))) Source #

Replace the amount at the given currency-token name combination in the given PBuiltinValue with the given amount. The new amount will be negative. If the given currency-token name combination does not exist, create it.

Note

A PBuiltinValue cannot store an amount that would not fit into a 128-bit signed integer. This function will error if the result would be forced to store such an amount.

Since: 3.7.0

pdeleteAmount :: forall (s :: S). Term s (PCurrencySymbol :--> (PTokenName :--> (PBuiltinValue :--> PBuiltinValue))) Source #

Remove any amount associated with the given currency-token name combination in the given PBuiltinValue. If there is no such combination in the given PBuiltinValue, this does nothing.

Since: 3.7.0