From ef082e1ca2f31be4194fc07f409a6b34e2f62e97 Mon Sep 17 00:00:00 2001 From: Ziyang Liu Date: Thu, 14 Dec 2023 01:28:53 -0800 Subject: [PATCH] Add functions for converting between Lovelace and Value (#5682) --- doc/read-the-docs-site/simple-example.rst | 4 ++-- .../tutorials/AuctionValidator.hs | 13 +++++++------ .../tutorials/BasicValidators.hs | 3 ++- .../exe/PlutusBenchmark/Marlowe/Util.hs | 2 -- .../20231213_133936_unsafeFixIO_lovelace.md | 5 +++++ .../src/PlutusLedgerApi/V1/Value.hs | 19 ++++++++++++++----- 6 files changed, 30 insertions(+), 16 deletions(-) create mode 100644 plutus-ledger-api/changelog.d/20231213_133936_unsafeFixIO_lovelace.md diff --git a/doc/read-the-docs-site/simple-example.rst b/doc/read-the-docs-site/simple-example.rst index 4dd6e4df83f..8e82352d08b 100644 --- a/doc/read-the-docs-site/simple-example.rst +++ b/doc/read-the-docs-site/simple-example.rst @@ -153,7 +153,7 @@ The ``refundsPreviousHighestBid`` condition checks that the transaction pays the It uses ``PlutusTx.find`` to find the transaction output (a UTXO) that pays to the previous bidder the amount equivalent to the previous highest bid, and verifies that there is at least one such output. -``singleton adaSymbol adaToken amt`` constructs a ``Value`` with ``amt`` Lovelaces (the subunit of the Ada currency). +``lovelaceValue amt`` constructs a ``Value`` with ``amt`` Lovelaces (the subunit of the Ada currency). ``Value`` is a multi-asset type that represents a collection of assets, including Ada. An asset is identified by a (symbol, token) pair, where the symbol represents the policy that controls the minting and burning of tokens, and the token represents a particular kind of token manipulated by the policy. ``(adaSymbol, adaToken)`` is the special identifier for Ada/Lovelace. @@ -284,7 +284,7 @@ Libraries for writing Plutus Tx scripts This auction example shows a relatively low-level way of writing scripts using Plutus Tx. In practice, you may consider using a higher-level library that abstracts away some of the details. For example, `plutus-apps `_ provides a constraint library for writing Plutus Tx. -Using these libraries, writing a validator in Plutus Tx becomes a matter of defining state transactions and the corresponding constraints, e.g., the condition ``refundsPreviousHighestBid`` can simply be written as ``Constraints.mustPayToPubKey bidder (singleton adaSymbol adaToken amt)``. +Using these libraries, writing a validator in Plutus Tx becomes a matter of defining state transactions and the corresponding constraints, e.g., the condition ``refundsPreviousHighestBid`` can simply be written as ``Constraints.mustPayToPubKey bidder (lovelaceValue amt)``. Alternatives to Plutus Tx ----------------------------- diff --git a/doc/read-the-docs-site/tutorials/AuctionValidator.hs b/doc/read-the-docs-site/tutorials/AuctionValidator.hs index 7eedd6470ed..60e94db0b00 100644 --- a/doc/read-the-docs-site/tutorials/AuctionValidator.hs +++ b/doc/read-the-docs-site/tutorials/AuctionValidator.hs @@ -20,9 +20,10 @@ module AuctionValidator where import PlutusCore.Version (plcVersion100) -import PlutusLedgerApi.V1 (POSIXTime, PubKeyHash, Value, adaSymbol, adaToken, singleton) +import PlutusLedgerApi.V1 (Lovelace, POSIXTime, PubKeyHash, Value) import PlutusLedgerApi.V1.Address (pubKeyHashAddress) import PlutusLedgerApi.V1.Interval (contains) +import PlutusLedgerApi.V1.Value (lovelaceValue) import PlutusLedgerApi.V2 (Datum (..), OutputDatum (..), ScriptContext (..), TxInfo (..), TxOut (..), from, to) import PlutusLedgerApi.V2.Contexts (getContinuingOutputs) @@ -39,7 +40,7 @@ data AuctionParams = AuctionParams -- ^ The asset being auctioned. It can be a single token, multiple tokens of the same -- kind, or tokens of different kinds, and the token(s) can be fungible or non-fungible. -- These can all be encoded as a `Value`. - apMinBid :: Integer, + apMinBid :: Lovelace, -- ^ The minimum bid in Lovelace. apEndTime :: POSIXTime -- ^ The deadline for placing a bid. This is the earliest time the auction can be closed. @@ -50,8 +51,8 @@ PlutusTx.makeLift ''AuctionParams data Bid = Bid { bBidder :: PubKeyHash, -- ^ Bidder's wallet address. - bAmount :: Integer - -- ^ Bid amount. + bAmount :: Lovelace + -- ^ Bid amount in Lovelace. } PlutusTx.deriveShow ''Bid @@ -126,7 +127,7 @@ auctionTypedValidator params (AuctionDatum highestBid) redeemer ctx@(ScriptConte Just (Bid bidder amt) -> case PlutusTx.find (\o -> txOutAddress o PlutusTx.== pubKeyHashAddress bidder - PlutusTx.&& txOutValue o PlutusTx.== singleton adaSymbol adaToken amt) + PlutusTx.&& txOutValue o PlutusTx.== lovelaceValue amt) (txInfoOutputs txInfo) of Just _ -> True Nothing -> PlutusTx.traceError ("Not found: refund output") @@ -168,7 +169,7 @@ auctionTypedValidator params (AuctionDatum highestBid) redeemer ctx@(ScriptConte case PlutusTx.find ( \o -> txOutAddress o PlutusTx.== pubKeyHashAddress (apSeller params) - PlutusTx.&& txOutValue o PlutusTx.== singleton adaSymbol adaToken amt + PlutusTx.&& txOutValue o PlutusTx.== lovelaceValue amt ) (txInfoOutputs txInfo) of Just _ -> True diff --git a/doc/read-the-docs-site/tutorials/BasicValidators.hs b/doc/read-the-docs-site/tutorials/BasicValidators.hs index 4376d5d6f1c..5dde554e8c2 100644 --- a/doc/read-the-docs-site/tutorials/BasicValidators.hs +++ b/doc/read-the-docs-site/tutorials/BasicValidators.hs @@ -1,5 +1,6 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE NumericUnderscores #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} @@ -80,7 +81,7 @@ validatePayment _ _ ctx = values = pubKeyOutputsAt myKeyHash txinfo -- 'fold' sums up all the values, we assert that there must be more -- than 1 Ada (more stuff is fine!) - in check $ valueOf (fold values) adaSymbol adaToken >= 1 + in check $ lovelaceValueOf (fold values) >= 1_000_000 --- BLOCK5 -- We can serialize a 'Validator' directly to CBOR serialisedDateValidator :: SerialisedScript diff --git a/plutus-benchmark/marlowe/exe/PlutusBenchmark/Marlowe/Util.hs b/plutus-benchmark/marlowe/exe/PlutusBenchmark/Marlowe/Util.hs index 2dac2137b21..cd00fba12c9 100644 --- a/plutus-benchmark/marlowe/exe/PlutusBenchmark/Marlowe/Util.hs +++ b/plutus-benchmark/marlowe/exe/PlutusBenchmark/Marlowe/Util.hs @@ -98,5 +98,3 @@ makeBuiltinData = . LBS.fromStrict . fromBuiltin . getLedgerBytes - - diff --git a/plutus-ledger-api/changelog.d/20231213_133936_unsafeFixIO_lovelace.md b/plutus-ledger-api/changelog.d/20231213_133936_unsafeFixIO_lovelace.md new file mode 100644 index 00000000000..fc90538e953 --- /dev/null +++ b/plutus-ledger-api/changelog.d/20231213_133936_unsafeFixIO_lovelace.md @@ -0,0 +1,5 @@ + +### Added + +- Added functions for converting between `Lovelace` and `Value`: `lovelaceValue` + and `lovelaceValueOf`. diff --git a/plutus-ledger-api/src/PlutusLedgerApi/V1/Value.hs b/plutus-ledger-api/src/PlutusLedgerApi/V1/Value.hs index 9e16c5f1c03..988fc1dd964 100644 --- a/plutus-ledger-api/src/PlutusLedgerApi/V1/Value.hs +++ b/plutus-ledger-api/src/PlutusLedgerApi/V1/Value.hs @@ -38,6 +38,8 @@ module PlutusLedgerApi.V1.Value ( , Value(..) , singleton , valueOf + , lovelaceValue + , lovelaceValueOf , scale , symbols -- * Partial order operations @@ -69,6 +71,7 @@ import PlutusTx.AssocMap qualified as Map import PlutusTx.Lift (makeLift) import PlutusTx.Ord qualified as Ord import PlutusTx.Prelude as PlutusTx hiding (sort) +import PlutusTx.Show qualified as PlutusTx import PlutusTx.These (These (..)) import Prettyprinter (Pretty, (<>)) import Prettyprinter.Extras (PrettyShow (PrettyShow)) @@ -176,10 +179,6 @@ quotes and we write the latter with a lower case "v" and without the quotes, i.e -- See Note [Value vs value]. {- | The 'Value' type represents a collection of amounts of different currencies. We can think of 'Value' as a vector space whose dimensions are currencies. -To create a value of 'Value', we need to specify a currency. This can be done -using 'Ledger.Ada.adaValueOf'. To get the ada dimension of 'Value' we use -'Ledger.Ada.fromValue'. Plutus contract authors will be able to define modules -similar to 'Ledger.Ada' for their own currencies. Operations on currencies are usually implemented /pointwise/. That is, we apply the operation to the quantities for each currency in turn. So @@ -262,6 +261,15 @@ symbols (Value mp) = Map.keys mp singleton :: CurrencySymbol -> TokenName -> Integer -> Value singleton c tn i = Value (Map.singleton c (Map.singleton tn i)) +lovelaceValue :: Lovelace -> Value +-- | A 'Value' containing the given quantity of Lovelace. +lovelaceValue = singleton adaSymbol adaToken . getLovelace + +{-# INLINABLE lovelaceValueOf #-} +-- | Get the quantity of Lovelace in the 'Value'. +lovelaceValueOf :: Value -> Lovelace +lovelaceValueOf v = Lovelace (valueOf v adaSymbol adaToken) + {-# INLINABLE assetClassValue #-} -- | A 'Value' containing the given amount of the asset class. assetClassValue :: AssetClass -> Integer -> Value @@ -443,7 +451,7 @@ eqMapWith is0 eqV (Map.toList -> xs1) (Map.toList -> xs2) = unordEqWith is0 eqV eq :: Value -> Value -> Bool eq (Value currs1) (Value currs2) = eqMapWith (Map.all (0 ==)) (eqMapWith (0 ==) (==)) currs1 currs2 -newtype Lovelace = Lovelace Integer +newtype Lovelace = Lovelace { getLovelace :: Integer } deriving stock (Generic) deriving (Pretty) via (PrettyShow Lovelace) deriving newtype @@ -461,6 +469,7 @@ newtype Lovelace = Lovelace Integer , PlutusTx.AdditiveSemigroup , PlutusTx.AdditiveMonoid , PlutusTx.AdditiveGroup + , PlutusTx.Show ) makeLift ''CurrencySymbol