diff --git a/MetaLamp/nft-marketplace/cabal.project b/MetaLamp/nft-marketplace/cabal.project index be1d0c6fe..3881ae532 100644 --- a/MetaLamp/nft-marketplace/cabal.project +++ b/MetaLamp/nft-marketplace/cabal.project @@ -26,7 +26,7 @@ source-repository-package plutus-use-cases quickcheck-dynamic web-ghc - tag: v2021-11-05 + tag: v2021-11-22 -- The following sections are copied from the 'plutus-apps' repository cabal.project at the revision diff --git a/MetaLamp/nft-marketplace/config/plutus-pab.template.yaml b/MetaLamp/nft-marketplace/config/plutus-pab.template.yaml index 93144ee88..e622717bd 100644 --- a/MetaLamp/nft-marketplace/config/plutus-pab.template.yaml +++ b/MetaLamp/nft-marketplace/config/plutus-pab.template.yaml @@ -22,7 +22,7 @@ nodeServerConfig: mscKeptBlocks: 100 mscNetworkId: "1097911063" # Testnet network ID (main net = empty string) mscSlotConfig: - scSlotZeroTime: 1591566291000 # Wednesday, July 29, 2020 21:44:51 - shelley launch time in milliseconds + scSlotZeroTime: 1596059091000 # Wednesday, July 29, 2020 21:44:51 - shelley launch time in milliseconds scSlotLength: 1000 # In milliseconds mscFeeConfig: fcConstantFee: diff --git a/MetaLamp/nft-marketplace/nix/pkgs/haskell/haskell.nix b/MetaLamp/nft-marketplace/nix/pkgs/haskell/haskell.nix index 1b6ce59ae..d6401f530 100644 --- a/MetaLamp/nft-marketplace/nix/pkgs/haskell/haskell.nix +++ b/MetaLamp/nft-marketplace/nix/pkgs/haskell/haskell.nix @@ -19,7 +19,7 @@ let inherit compiler-nix-name; sha256map = { - "https://github.com/input-output-hk/plutus-apps.git"."v2021-11-05" = "00pv5ds99lf6lmws3a3ipsn9amg56ayc9b0wqki2gky464dm6gzr"; + "https://github.com/input-output-hk/plutus-apps.git"."v2021-11-22" = "10m0gmnakjnpnzyvjs3ksfpxgjcq3pdphr4gf8v7fjhr9fjbc45n"; "https://github.com/Quid2/flat.git"."ee59880f47ab835dbd73bea0847dab7869fc20d8" = "1lrzknw765pz2j97nvv9ip3l1mcpf2zr4n56hwlz0rk7wq7ls4cm"; "https://github.com/input-output-hk/purescript-bridge.git"."366fc70b341e2633f3ad0158a577d52e1cd2b138" = "18j0rysfccbmfpbw2d1rsjkpd5h84alpsn6b5rwzdxw9h5vqi9m5"; "https://github.com/input-output-hk/servant-purescript.git"."ebea59c7bdfc0338d83fca772b9a57e28560bcde" = "0gjcq4y61kwb4w70pnswn5dp23wd13dac8d9hz84j374cm1kshsn"; @@ -34,7 +34,6 @@ let "https://github.com/input-output-hk/cardano-node.git"."b6ca519f97a0e795611a63174687e6bb70c9f752" = "0z5lpmqc98fwg3xzpzxkfslbxdjwfyyw8bn8yq0574sf4942vqdn"; "https://github.com/input-output-hk/Win32-network"."3825d3abf75f83f406c1f7161883c438dac7277d" = "19wahfv726fa3mqajpqdqhnl9ica3xmf68i254q45iyjcpj1psqx"; "https://github.com/input-output-hk/hedgehog-extras"."edf6945007177a638fbeb8802397f3a6f4e47c14" = "0wc7qzkc7j4ns2rz562h6qrx2f8xyq7yjcb7zidnj7f6j0pcd0i9"; - "https://github.com/input-output-hk/cardano-wallet"."ae7569293e94241ef6829139ec02bd91abd069df" = "1mv1dhpkdj9ridm1fvq6jc85qs6zvbp172228rq72gyawjwrgvi6"; "https://github.com/input-output-hk/cardano-addresses"."d2f86caa085402a953920c6714a0de6a50b655ec" = "0p6jbnd7ky2yf7bwb1350k8880py8dgqg39k49q02a6ij4ld01ay"; "https://github.com/input-output-hk/plutus"."3f089ccf0ca746b399c99afe51e063b0640af547" = "1nx8xmdgwmnsla4qg4k67f5md8vm3p1p9i25ndalrqdg40z90486"; "https://github.com/j-mueller/cardano-wallet"."6be73ab852c0592713dfe78218856d4a8a0ee69e" = "0rx5hvmbdv5dwb4qq39vyhisj0v75j21jbiivn3s3q9za6m6x1p4"; diff --git a/MetaLamp/nft-marketplace/nix/sources.json b/MetaLamp/nft-marketplace/nix/sources.json index cbee24ba0..2d3e32c68 100644 --- a/MetaLamp/nft-marketplace/nix/sources.json +++ b/MetaLamp/nft-marketplace/nix/sources.json @@ -5,10 +5,10 @@ "homepage": "", "owner": "input-output-hk", "repo": "plutus-apps", - "rev": "v2021-11-05", - "sha256": "00pv5ds99lf6lmws3a3ipsn9amg56ayc9b0wqki2gky464dm6gzr", + "rev": "v2021-11-22", + "sha256": "10m0gmnakjnpnzyvjs3ksfpxgjcq3pdphr4gf8v7fjhr9fjbc45n", "type": "tarball", - "url": "https://github.com/input-output-hk/plutus-apps/archive/v2021-11-05.tar.gz", + "url": "https://github.com/input-output-hk/plutus-apps/archive/v2021-11-22.tar.gz", "url_template": "https://github.com///archive/.tar.gz" } } \ No newline at end of file diff --git a/MetaLamp/nft-marketplace/plutus-starter.cabal b/MetaLamp/nft-marketplace/plutus-starter.cabal index 61a3aa69b..3d63dfb35 100644 --- a/MetaLamp/nft-marketplace/plutus-starter.cabal +++ b/MetaLamp/nft-marketplace/plutus-starter.cabal @@ -41,6 +41,7 @@ common lang library import: lang exposed-modules: + Ext.Plutus.Ledger.Index Ext.Plutus.Ledger.Time Ext.Plutus.Ledger.Value Ext.Plutus.PAB.Webserver.Server diff --git a/MetaLamp/nft-marketplace/src/Ext/Plutus/Ledger/Index.hs b/MetaLamp/nft-marketplace/src/Ext/Plutus/Ledger/Index.hs new file mode 100644 index 000000000..114834f90 --- /dev/null +++ b/MetaLamp/nft-marketplace/src/Ext/Plutus/Ledger/Index.hs @@ -0,0 +1,11 @@ +module Ext.Plutus.Ledger.Index where + +import Ledger.Index (minAdaTxOut) +import Plutus.V1.Ledger.Ada (Ada, fromValue, lovelaceValueOf, + toValue) +import Plutus.V1.Ledger.Value (Value) + +-- TODO: That should be configurable in future: +-- Read minUTxOValue from `testnet-shelley-genesis.json` cardano-node config +minAdaTxOutValue :: Value +minAdaTxOutValue = toValue minAdaTxOut diff --git a/MetaLamp/nft-marketplace/src/Ext/Plutus/Ledger/Value.hs b/MetaLamp/nft-marketplace/src/Ext/Plutus/Ledger/Value.hs index fed38275a..4acccdba2 100644 --- a/MetaLamp/nft-marketplace/src/Ext/Plutus/Ledger/Value.hs +++ b/MetaLamp/nft-marketplace/src/Ext/Plutus/Ledger/Value.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE NumericUnderscores #-} module Ext.Plutus.Ledger.Value where import Control.Lens (view) diff --git a/MetaLamp/nft-marketplace/src/Plutus/Abstract/Percentage.hs b/MetaLamp/nft-marketplace/src/Plutus/Abstract/Percentage.hs index 3ff22da4e..c44dc2346 100644 --- a/MetaLamp/nft-marketplace/src/Plutus/Abstract/Percentage.hs +++ b/MetaLamp/nft-marketplace/src/Plutus/Abstract/Percentage.hs @@ -31,3 +31,4 @@ mkPercentage percentage@(numerator, denominator) = if denominator /= 0 && 0 <= roundedPercentage && roundedPercentage <= 100 then pure $ Percentage percentage else Nothing + diff --git a/MetaLamp/nft-marketplace/src/Plutus/Contracts/NftMarketplace/OffChain/Owner.hs b/MetaLamp/nft-marketplace/src/Plutus/Contracts/NftMarketplace/OffChain/Owner.hs index b1be1dedb..07f61bd72 100644 --- a/MetaLamp/nft-marketplace/src/Plutus/Contracts/NftMarketplace/OffChain/Owner.hs +++ b/MetaLamp/nft-marketplace/src/Plutus/Contracts/NftMarketplace/OffChain/Owner.hs @@ -16,6 +16,7 @@ import qualified Data.Aeson as J import Data.Proxy (Proxy (..)) import Data.Text (Text) import qualified Data.Text as T +import Ext.Plutus.Ledger.Index (minAdaTxOutValue) import qualified GHC.Generics as Haskell import Ledger import Ledger.Ada (Ada (..)) @@ -31,6 +32,7 @@ import Plutus.Contract.Request (ownPubKeyHash) import Plutus.Contract.StateMachine import Plutus.Contracts.Currency as Currency import qualified Plutus.Contracts.NftMarketplace.OnChain.Core as Core +import Plutus.V1.Ledger.Ada (lovelaceValueOf) import qualified PlutusTx import qualified PlutusTx.AssocMap as AssocMap import PlutusTx.Prelude hiding @@ -54,7 +56,7 @@ start StartMarketplaceParams {..} = do saleFeePercentage <- maybe (throwError "Operator's fee value should be in [0, 100]") pure $ mkPercentage saleFee let marketplace = Core.Marketplace pkh (Lovelace creationFee) saleFeePercentage let client = Core.marketplaceClient marketplace - void $ mapError (T.pack . Haskell.show @SMContractError) $ runInitialise client (Core.MarketplaceDatum AssocMap.empty AssocMap.empty) mempty + void $ mapError (T.pack . Haskell.show @SMContractError) $ runInitialise client (Core.MarketplaceDatum AssocMap.empty AssocMap.empty) minAdaTxOutValue logInfo @Haskell.String $ printf "started Marketplace %s at address %s" (Haskell.show marketplace) (Haskell.show $ Core.marketplaceAddress marketplace) pure marketplace diff --git a/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Auction/Endpoints.hs b/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Auction/Endpoints.hs index 009aacd90..1efa34a09 100644 --- a/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Auction/Endpoints.hs +++ b/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Auction/Endpoints.hs @@ -23,6 +23,7 @@ import qualified Data.Aeson as J import Data.Monoid (Last (..)) import Data.Semigroup.Generic (GenericSemigroupMonoid (..)) import qualified Data.Text as T +import Ext.Plutus.Ledger.Index (minAdaTxOutValue) import GHC.Generics (Generic) import Ledger (Ada, PubKeyHash, @@ -83,7 +84,7 @@ startAuction StartAuctionParams{..} = do _ <- handleError (\e -> do { logError (AuctionFailed e); throwError (StateMachineContractError e) }) - (SM.runInitialise client (initialState aOwner) aAsset) + (SM.runInitialise client (initialState aOwner) (aAsset + minAdaTxOutValue)) logInfo $ AuctionStarted auction pure auction diff --git a/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Auction/StateMachine.hs b/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Auction/StateMachine.hs index 8ab5bf1b7..e66c83562 100644 --- a/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Auction/StateMachine.hs +++ b/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Auction/StateMachine.hs @@ -19,6 +19,7 @@ import Data.Aeson (FromJSON, ToJSON) import qualified Data.Aeson as J import Data.Monoid (Last (..)) import Data.Semigroup.Generic (GenericSemigroupMonoid (..)) +import Ext.Plutus.Ledger.Index (minAdaTxOutValue) import GHC.Generics (Generic) import Ledger (Ada, PubKeyHash, Slot, Value) @@ -140,7 +141,7 @@ auctionTransition getAdditionalPayoutConstraints params@Auction{..} state@State{ let additionalConstraints = getAdditionalPayoutConstraints params state constraints = - Constraints.mustPayToPubKey highestBidder aAsset -- and the highest bidder the asset + Constraints.mustPayToPubKey highestBidder (aAsset + minAdaTxOutValue) -- and the highest bidder the asset <> additionalConstraints <> Constraints.mustValidateIn (Interval.from aEndTime) -- When the auction has ended, newState = State { stateData = Finished h, stateValue = mempty } @@ -151,7 +152,8 @@ auctionTransition getAdditionalPayoutConstraints params@Auction{..} state@State{ constraints = Constraints.mustValidateIn (Interval.to aEndTime) -- While the auction hasn't ended, <> Constraints.mustPayToPubKey highestBidder (Ada.toValue highestBid) -- and the highest bidder the asset - <> Constraints.mustPayToPubKey aOwner aAsset -- and the highest bidder the asset + <> Constraints.mustPayToPubKey aOwner (aAsset + minAdaTxOutValue) -- and the highest bidder the asset + -- TODO: is it okay that buyer receive additional 2ADA? Should we initially add them to the bid price? newState = State { stateData = Canceled, stateValue = mempty } in Just (constraints, newState) diff --git a/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Sale/Endpoints.hs b/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Sale/Endpoints.hs index 9d241d411..e3e4c21c1 100644 --- a/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Sale/Endpoints.hs +++ b/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Sale/Endpoints.hs @@ -31,6 +31,7 @@ import qualified Plutus.Contracts.NftMarketplace.OnChain.Core.Marketplace as Mar import qualified Plutus.Contracts.Services.Sale.Core as Core import qualified Plutus.Contracts.Services.Sale.StateMachine as Core +import Ext.Plutus.Ledger.Index (minAdaTxOutValue) import Plutus.Contract.Request (ownPubKeyHash) import qualified PlutusTx import qualified PlutusTx.AssocMap as AssocMap @@ -66,7 +67,7 @@ openSale OpenSaleParams {..} = do saleOperatorFee = ospSaleFee } let client = Core.saleClient sale - void $ mapError (T.pack . Haskell.show @SMContractError) $ runInitialise client Core.SaleOngoing ospSaleValue + void $ mapError (T.pack . Haskell.show @SMContractError) $ runInitialise client Core.SaleOngoing (ospSaleValue + minAdaTxOutValue) logInfo @Haskell.String $ printf "Opened Sale %s at address %s" (Haskell.show sale) (Haskell.show $ Core.saleAddress sale) pure sale diff --git a/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Sale/StateMachine.hs b/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Sale/StateMachine.hs index d981a15d0..04fea950a 100644 --- a/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Sale/StateMachine.hs +++ b/MetaLamp/nft-marketplace/src/Plutus/Contracts/Services/Sale/StateMachine.hs @@ -15,6 +15,7 @@ module Plutus.Contracts.Services.Sale.StateMachine where import qualified Control.Lens as Lens import qualified Data.Aeson as J import qualified Data.Text as T +import Ext.Plutus.Ledger.Index (minAdaTxOutValue) import qualified GHC.Generics as Haskell import Ledger import qualified Ledger.Ada as Ada @@ -71,18 +72,20 @@ transition :: GetAdditionalConstraints -> Sale -> State SaleDatum -> SaleRedeeme transition additionalConstraints sale@Sale{..} state redeemer = case (stateData state, redeemer) of (SaleOngoing, Redeem) -> Just ( Constraints.mustBeSignedBy saleOwner <> - Constraints.mustPayToPubKey saleOwner val + Constraints.mustPayToPubKey saleOwner saleValueWithMinAdaTxOut , State SaleClosed mempty ) - (SaleOngoing, Buy buyer) | saleValue == val + (SaleOngoing, Buy buyer) | saleValueWithMinAdaTxOut == val -> Just ( Constraints.mustBeSignedBy buyer <> - Constraints.mustPayToPubKey buyer saleValue <> + Constraints.mustPayToPubKey buyer saleValueWithMinAdaTxOut <> + -- TODO: is it okay that buyer receive additional 2ADA? Should we initially add them to the sale price? additionalConstraints sale , State SaleClosed mempty ) _ -> Nothing where val = stateValue state + saleValueWithMinAdaTxOut = saleValue + minAdaTxOutValue {-# INLINABLE isFinal #-} isFinal :: SaleDatum -> Bool diff --git a/MetaLamp/nft-marketplace/test/Main.hs b/MetaLamp/nft-marketplace/test/Main.hs index 03c58bcd0..42c7dac2b 100644 --- a/MetaLamp/nft-marketplace/test/Main.hs +++ b/MetaLamp/nft-marketplace/test/Main.hs @@ -20,6 +20,6 @@ tests = "All tests" [ testGroup "NFT Marketplace" - [Start.tests, CreateNft.tests, Bundles.tests, Sale.tests, Auction.tests] + [Start.tests, CreateNft.tests, Bundles.tests, Auction.tests, Sale.tests] , testGroup "Abstract" [RemoteData.tests, Percentage.tests] ] diff --git a/MetaLamp/nft-marketplace/test/Marketplace/Fixtures/Script.hs b/MetaLamp/nft-marketplace/test/Marketplace/Fixtures/Script.hs index 4e2b00d01..3123792d5 100644 --- a/MetaLamp/nft-marketplace/test/Marketplace/Fixtures/Script.hs +++ b/MetaLamp/nft-marketplace/test/Marketplace/Fixtures/Script.hs @@ -1,6 +1,6 @@ -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE OverloadedStrings #-} - +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NumericUnderscores #-} +{-# LANGUAGE OverloadedStrings #-} module Marketplace.Fixtures.Script where import Ledger (Address, @@ -10,6 +10,7 @@ import Ledger.Ada (Ada (..)) import qualified Ledger.Value as V import qualified Marketplace.Fixtures.Wallet as Fixtures import Plutus.Abstract.Percentage (Percentage (..)) +import Plutus.Abstract.PercentageInterface (calculatePercentageRounded) import qualified Plutus.Contracts.NftMarketplace.OnChain.Core as Marketplace import Wallet.Emulator.Types (Wallet (..), walletPubKeyHash) @@ -19,11 +20,17 @@ marketplace = Marketplace.Marketplace { Marketplace.marketplaceOperator = walletPubKeyHash Fixtures.ownerWallet, Marketplace.marketplaceSaleFee = percentage, - Marketplace.marketplaceNFTFee = Lovelace 100000 -- 0.1 ADA + Marketplace.marketplaceNFTFee = marketplaceCreationFee } +marketplaceCreationFee :: Ada +marketplaceCreationFee = Lovelace 2_100_000 -- 2.1 ADA (should be gte then minAdaTxOut) + percentage :: Percentage -percentage = Percentage (5, 2) +percentage = Percentage (7, 2) + +roundedPercentage :: Integer -> Integer +roundedPercentage price = calculatePercentageRounded percentage price marketplaceAddress :: Address marketplaceAddress = Marketplace.marketplaceAddress marketplace diff --git a/MetaLamp/nft-marketplace/test/Marketplace/Spec/Auction.hs b/MetaLamp/nft-marketplace/test/Marketplace/Spec/Auction.hs index 43daa91e0..1b46fd35d 100644 --- a/MetaLamp/nft-marketplace/test/Marketplace/Spec/Auction.hs +++ b/MetaLamp/nft-marketplace/test/Marketplace/Spec/Auction.hs @@ -18,7 +18,10 @@ import Data.Void (Void) import Ext.Plutus.Ledger.Time (Seconds (..), addToBeginningOfTime) import Ledger (Value) -import Ledger.Ada (lovelaceValueOf) +import Ledger.Ada (Ada (..), + lovelaceValueOf, + toValue) +import Ledger.Index (minAdaTxOut) import qualified Ledger.Value as V import qualified Marketplace.Fixtures as Fixtures import qualified Marketplace.Spec.Bundles as Bundles @@ -37,6 +40,8 @@ import qualified PlutusTx.AssocMap as AssocMap import Test.Tasty import qualified Utils import Wallet.Emulator.Wallet (walletAddress) + + tests :: TestTree tests = testGroup @@ -158,10 +163,14 @@ closeLotParams :: Marketplace.CloseLotParams closeLotParams = Marketplace.CloseLotParams { Marketplace.clpItemId = Marketplace.UserNftId Fixtures.catTokenIpfsCid } + +highestBid :: Integer +highestBid = 75 * Fixtures.oneAdaInLovelace + bidOnAuctionParams :: Marketplace.BidOnAuctionParams bidOnAuctionParams = Marketplace.BidOnAuctionParams { Marketplace.boapItemId = Marketplace.UserNftId Fixtures.catTokenIpfsCid, - Marketplace.boapBid = fromInteger $ 25 * Fixtures.oneAdaInLovelace + Marketplace.boapBid = fromInteger $ 75 * Fixtures.oneAdaInLovelace } startAnAuctionTrace :: Trace.EmulatorTrace (Trace.ContractHandle (ContractResponse String Text Marketplace.UserContractState) Marketplace.MarketplaceUserSchema Void) @@ -353,10 +362,13 @@ closeLotParamsB = Marketplace.CloseLotParams { Marketplace.clpItemId = Marketplace.UserBundleId Fixtures.cids } +highestBidB :: Integer +highestBidB = 95 * Fixtures.oneAdaInLovelace + bidOnAuctionParamsB :: Marketplace.BidOnAuctionParams bidOnAuctionParamsB = Marketplace.BidOnAuctionParams { Marketplace.boapItemId = Marketplace.UserBundleId Fixtures.cids, - Marketplace.boapBid = fromInteger $ 35 * Fixtures.oneAdaInLovelace + Marketplace.boapBid = fromInteger highestBidB } startAnAuctionTraceB :: Trace.EmulatorTrace (Trace.ContractHandle (ContractResponse String Text Marketplace.UserContractState) Marketplace.MarketplaceUserSchema Void) @@ -495,23 +507,30 @@ buyOnAuctionValueCheckB = marketplaceOperatorFeeCheck :: TracePredicate marketplaceOperatorFeeCheck = - walletFundsChange Fixtures.ownerWallet $ lovelaceValueOf 725000 - -- 25000000 * 2.5 /100 = 625000 - fee by complete auction - -- 100000 - fee by minting token + walletFundsChange Fixtures.ownerWallet $ toValue (Fixtures.marketplaceCreationFee + auctionFee - minAdaTxOut) + where + auctionFee = Lovelace $ Fixtures.roundedPercentage highestBid sellerProfitWithFeeCheck :: TracePredicate sellerProfitWithFeeCheck = - walletFundsChange Fixtures.userWallet $ lovelaceValueOf 24275000 - -- 25000000 - 725000 = 24275000 + walletFundsChange Fixtures.userWallet $ toValue (highestBidAda - Fixtures.marketplaceCreationFee - minAdaTxOut - auctionFee) + where + auctionFee = Lovelace $ Fixtures.roundedPercentage highestBid + highestBidAda = Lovelace highestBid marketplaceOperatorFeeCheckB :: TracePredicate marketplaceOperatorFeeCheckB = - walletFundsChange Fixtures.ownerWallet $ lovelaceValueOf 1175000 - -- 35000000 * 2.5 /100 = 875000 - fee by complete auction - -- 100000 * 2 = 200000 - fee by minting 2 tokens - -- 100000 - fee by bundling + walletFundsChange Fixtures.ownerWallet $ toValue (totalMintingFee + totalBundlingFee + auctionFee - minAdaTxOut) + where + totalMintingFee = Fixtures.marketplaceCreationFee * 2 + totalBundlingFee = Fixtures.marketplaceCreationFee + auctionFee = Lovelace $ Fixtures.roundedPercentage highestBidB sellerProfitWithFeeCheckB :: TracePredicate sellerProfitWithFeeCheckB = - walletFundsChange Fixtures.userWallet $ lovelaceValueOf 33825000 - -- 35000000 - 1175000 = 33825000 + walletFundsChange Fixtures.userWallet $ toValue (highestBidAda - totalMintingFee - totalBundlingFee - minAdaTxOut - auctionFee) + where + totalMintingFee = Fixtures.marketplaceCreationFee * 2 + totalBundlingFee = Fixtures.marketplaceCreationFee + auctionFee = Lovelace $ Fixtures.roundedPercentage highestBidB + highestBidAda = Lovelace highestBidB diff --git a/MetaLamp/nft-marketplace/test/Marketplace/Spec/Bundles.hs b/MetaLamp/nft-marketplace/test/Marketplace/Spec/Bundles.hs index 629a9eb1e..1c51a4b56 100644 --- a/MetaLamp/nft-marketplace/test/Marketplace/Spec/Bundles.hs +++ b/MetaLamp/nft-marketplace/test/Marketplace/Spec/Bundles.hs @@ -13,7 +13,8 @@ import Data.Maybe (isNothing) import Data.Proxy import Data.Text (Text) import Data.Void (Void) -import Ledger.Ada (lovelaceValueOf) +import Ledger.Ada (toValue) +import Ledger.Index (minAdaTxOut) import qualified Marketplace.Fixtures as Fixtures import qualified Marketplace.Spec.Start as Start import Plutus.Abstract.ContractResponse (ContractResponse) @@ -33,7 +34,7 @@ tests = checkPredicateOptions Fixtures.options "Should create a bundle for two NFTs transforming Marketplace store" - (bundleDatumsCheck .&&. marketplaceOperatorFeeCheck) + (bundleDatumsCheck .&&. marketplaceOperatorFundsCheck) (void bundleTrace), checkPredicateOptions Fixtures.options @@ -150,8 +151,9 @@ unbundleDatumsCheck = maybe False (Fixtures.hasPhotoTokenRecord . Marketplace.nftRecord) (AssocMap.lookup Fixtures.photoTokenIpfsCidHash store) -marketplaceOperatorFeeCheck :: TracePredicate -marketplaceOperatorFeeCheck = - walletFundsChange Fixtures.ownerWallet $ lovelaceValueOf 300000 --- 100000 * 2 = 200000 - fee by minting 2 tokens --- 100000 - fee by bundling +marketplaceOperatorFundsCheck :: TracePredicate +marketplaceOperatorFundsCheck = + walletFundsChange Fixtures.ownerWallet $ toValue (totalMintingFee + totalBundlingFee - minAdaTxOut) + where + totalBundlingFee = Fixtures.marketplaceCreationFee + totalMintingFee = Fixtures.marketplaceCreationFee * 2 diff --git a/MetaLamp/nft-marketplace/test/Marketplace/Spec/CreateNft.hs b/MetaLamp/nft-marketplace/test/Marketplace/Spec/CreateNft.hs index 0b260a6bc..ae3ba278e 100644 --- a/MetaLamp/nft-marketplace/test/Marketplace/Spec/CreateNft.hs +++ b/MetaLamp/nft-marketplace/test/Marketplace/Spec/CreateNft.hs @@ -13,7 +13,8 @@ import Control.Monad (void) import Data.Maybe (isNothing) import Data.Text (Text) import Data.Void (Void) -import Ledger.Ada (lovelaceValueOf) +import Ledger.Ada (toValue) +import Ledger.Index (minAdaTxOut) import qualified Ledger.Value as V import qualified Marketplace.Fixtures as Fixtures import qualified Marketplace.Spec.Start as Start @@ -35,12 +36,12 @@ tests = [ checkPredicateOptions Fixtures.options "Should mint NFT token into the user wallet and create the Marketplace entry hiding issuer" - (datumsCheck .&&. valueCheck .&&. marketplaceOperatorFeeCheck) + (datumsCheck .&&. valueCheck .&&. marketplaceOperatorFundsCheck) (void createNftTrace), checkPredicateOptions Fixtures.options "Should mint NFT token into the user wallet and create the Marketplace entry revealing issuer" - (datumsCheck' .&&. valueCheck .&&. marketplaceOperatorFeeCheck) + (datumsCheck' .&&. valueCheck .&&. marketplaceOperatorFundsCheck) createNftTrace' ] @@ -99,6 +100,6 @@ valueCheck = where hasNft v = (v ^. _2 & V.unTokenName) == Fixtures.catTokenIpfsCidBs -marketplaceOperatorFeeCheck :: TracePredicate -marketplaceOperatorFeeCheck = - walletFundsChange Fixtures.ownerWallet $ lovelaceValueOf 100000 +marketplaceOperatorFundsCheck :: TracePredicate +marketplaceOperatorFundsCheck = + walletFundsChange Fixtures.ownerWallet $ toValue (Fixtures.marketplaceCreationFee - minAdaTxOut) diff --git a/MetaLamp/nft-marketplace/test/Marketplace/Spec/Sale.hs b/MetaLamp/nft-marketplace/test/Marketplace/Spec/Sale.hs index 399b9b1c4..7fea2705d 100644 --- a/MetaLamp/nft-marketplace/test/Marketplace/Spec/Sale.hs +++ b/MetaLamp/nft-marketplace/test/Marketplace/Spec/Sale.hs @@ -15,7 +15,10 @@ import Data.Maybe (isNothing) import Data.Proxy import Data.Text (Text) import Data.Void (Void) -import Ledger.Ada (lovelaceValueOf) +import Ledger.Ada (Ada (..), + lovelaceValueOf, + toValue) +import Ledger.Index (minAdaTxOut) import qualified Ledger.Value as V import qualified Marketplace.Fixtures as Fixtures import qualified Marketplace.Spec.Bundles as Bundles @@ -106,10 +109,14 @@ tests = ]] -- \/\/\/ "NFT singletons" + +singletonNftPrice :: Integer +singletonNftPrice = 60 * Fixtures.oneAdaInLovelace + openSaleParams :: Marketplace.OpenSaleParams openSaleParams = Marketplace.OpenSaleParams { Marketplace.ospItemId = Marketplace.UserNftId Fixtures.catTokenIpfsCid, - Marketplace.ospSalePrice = 44 * Fixtures.oneAdaInLovelace + Marketplace.ospSalePrice = singletonNftPrice } closeLotParams :: Marketplace.CloseLotParams @@ -226,11 +233,16 @@ errorCheckClose = Utils.assertCrError (Proxy @"closeSale") (Marketplace.userEndp errorCheckBuyer :: TracePredicate errorCheckBuyer = Utils.assertCrError (Proxy @"buyItem") (Marketplace.userEndpoints Fixtures.marketplace) (Trace.walletInstanceTag Fixtures.buyerWallet) + -- \/\/\/ "NFT bundles" + +bundleNftPrice :: Integer +bundleNftPrice = 85 * Fixtures.oneAdaInLovelace + openSaleParamsB :: Marketplace.OpenSaleParams openSaleParamsB = Marketplace.OpenSaleParams { Marketplace.ospItemId = Marketplace.UserBundleId Fixtures.cids, - Marketplace.ospSalePrice = 65 * Fixtures.oneAdaInLovelace + Marketplace.ospSalePrice = bundleNftPrice } closeLotParamsB :: Marketplace.CloseLotParams @@ -324,23 +336,30 @@ buyItemValueCheckB = marketplaceOperatorFeeCheck :: TracePredicate marketplaceOperatorFeeCheck = - walletFundsChange Fixtures.ownerWallet $ lovelaceValueOf 1200000 - -- 44000000 * 2.5 /100 = 1100000 - fee by complete sale - -- 100000 - fee by minting token + walletFundsChange Fixtures.ownerWallet $ toValue (Fixtures.marketplaceCreationFee + saleFee - minAdaTxOut) + where + saleFee = Lovelace $ Fixtures.roundedPercentage singletonNftPrice sellersProfitWithPayingFeeCheck :: TracePredicate sellersProfitWithPayingFeeCheck = - walletFundsChange Fixtures.userWallet $ lovelaceValueOf 42800000 - -- 44000000 - 1200000 = 42800000 - seller's profit + walletFundsChange Fixtures.userWallet $ toValue (nftPriceAda - saleFee - Fixtures.marketplaceCreationFee - minAdaTxOut) + where + nftPriceAda = Lovelace singletonNftPrice + saleFee = Lovelace $ Fixtures.roundedPercentage singletonNftPrice marketplaceOperatorFeeCheckB :: TracePredicate marketplaceOperatorFeeCheckB = - walletFundsChange Fixtures.ownerWallet $ lovelaceValueOf 1925000 - -- 65000000 * 2.5 /100 = 1625000 - fee by complete sale - -- 100000 * 2 = 200000 - fee by minting 2 tokens - -- 100000 - fee by bundling + walletFundsChange Fixtures.ownerWallet $ toValue (totalMintingFee + totalBundlingFee + saleFee - minAdaTxOut) + where + totalMintingFee = Fixtures.marketplaceCreationFee * 2 + totalBundlingFee = Fixtures.marketplaceCreationFee + saleFee = Lovelace $ Fixtures.roundedPercentage bundleNftPrice sellersProfitWithPayingFeeCheckB :: TracePredicate sellersProfitWithPayingFeeCheckB = - walletFundsChange Fixtures.userWallet $ lovelaceValueOf 63075000 - -- 65000000 - 1925000 = 63075000 + walletFundsChange Fixtures.userWallet $ toValue (bundlePriceAda - totalMintingFee - totalBundlingFee - minAdaTxOut - saleFee) + where + totalMintingFee = Fixtures.marketplaceCreationFee * 2 + totalBundlingFee = Fixtures.marketplaceCreationFee + saleFee = Lovelace $ Fixtures.roundedPercentage bundleNftPrice + bundlePriceAda = Lovelace bundleNftPrice diff --git a/MetaLamp/nft-marketplace/test/Marketplace/Spec/Start.hs b/MetaLamp/nft-marketplace/test/Marketplace/Spec/Start.hs index c41e29d41..759fc016e 100644 --- a/MetaLamp/nft-marketplace/test/Marketplace/Spec/Start.hs +++ b/MetaLamp/nft-marketplace/test/Marketplace/Spec/Start.hs @@ -1,5 +1,6 @@ -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NumericUnderscores #-} +{-# LANGUAGE OverloadedStrings #-} module Marketplace.Spec.Start ( tests, startTrace @@ -7,6 +8,9 @@ module Marketplace.Spec.Start import Control.Monad (void) import Data.Text (Text) +import Ledger.Ada (Ada (..), + toValue) +import Ledger.Index (minAdaTxOut) import qualified Ledger.Value as V import qualified Marketplace.Fixtures as Fixtures import Plutus.Abstract.Percentage (getPercentage) @@ -26,7 +30,7 @@ tests = [ checkPredicateOptions Fixtures.options "Should start a new marketplace with empty store" - datumsCheck + (datumsCheck .&&. marketplaceOpenedWithMinAdaTxOut .&&. marketplaceOperatorPayedMinAdaTxOut) startTrace ] @@ -38,7 +42,7 @@ startTrace = do startMarketplaceParams :: StartMarketplaceParams startMarketplaceParams = StartMarketplaceParams { - creationFee = 100000, -- 0.1 ADA + creationFee = getLovelace $ Fixtures.marketplaceCreationFee, saleFee = getPercentage Fixtures.percentage } @@ -51,3 +55,11 @@ datumsCheck = dataAtAddress Fixtures.marketplaceAddress (== [Marketplace.MarketplaceDatum AssocMap.empty AssocMap.empty]) + +marketplaceOpenedWithMinAdaTxOut :: TracePredicate +marketplaceOpenedWithMinAdaTxOut = + valueAtAddress Fixtures.marketplaceAddress (toValue minAdaTxOut ==) + +marketplaceOperatorPayedMinAdaTxOut :: TracePredicate +marketplaceOperatorPayedMinAdaTxOut = + walletFundsChange Fixtures.ownerWallet $ toValue (- minAdaTxOut)