generated from input-output-hk/plutus-starter
-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
321 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
{-# OPTIONS_GHC -Wno-orphans #-} | ||
|
||
module Tokenomia.Common.Arbitrary.AssetClass | ||
() where | ||
|
||
import Plutus.V1.Ledger.Value | ||
( AssetClass(..) | ||
, CurrencySymbol (..) | ||
, TokenName (..) | ||
) | ||
|
||
import Test.Tasty.QuickCheck | ||
( Arbitrary | ||
, arbitrary | ||
, shrink | ||
) | ||
|
||
import Tokenomia.Common.Arbitrary.Builtins () | ||
|
||
|
||
instance Arbitrary CurrencySymbol where | ||
arbitrary = CurrencySymbol <$> arbitrary | ||
shrink x = CurrencySymbol <$> shrink (unCurrencySymbol x) | ||
|
||
instance Arbitrary TokenName where | ||
arbitrary = TokenName <$> arbitrary | ||
shrink x = TokenName <$> shrink (unTokenName x) | ||
|
||
instance Arbitrary AssetClass where | ||
arbitrary = AssetClass <$> arbitrary | ||
shrink x = AssetClass <$> shrink (unAssetClass x) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{-# OPTIONS_GHC -Wno-orphans #-} | ||
|
||
module Tokenomia.Common.Arbitrary.Builtins | ||
() where | ||
|
||
import PlutusTx.Builtins.Internal | ||
( BuiltinByteString(..) ) | ||
|
||
import Test.QuickCheck.Instances.ByteString () | ||
import Test.Tasty.QuickCheck | ||
( Arbitrary | ||
, arbitrary | ||
, resize | ||
, shrink | ||
) | ||
|
||
|
||
instance Arbitrary BuiltinByteString where | ||
arbitrary = BuiltinByteString <$> resize 64 arbitrary | ||
shrink x | ||
| x == mempty = mempty | ||
| otherwise = pure mempty |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module Tokenomia.Common.Arbitrary.Modifiers | ||
( Restricted(..) | ||
) where | ||
|
||
|
||
newtype Restricted a | ||
= Restricted { getRestricted :: a } | ||
deriving (Show, Eq ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
{-# LANGUAGE FlexibleInstances #-} | ||
{-# LANGUAGE ImportQualifiedPost #-} | ||
{-# OPTIONS_GHC -Wno-orphans #-} | ||
|
||
module Tokenomia.Common.Arbitrary.MultiAsset | ||
( Restricted(..) | ||
) where | ||
|
||
import Data.Functor.Syntax ( (<$$>) ) | ||
import Data.Set qualified as Set ( toList ) | ||
import Data.Map.Strict qualified as Map ( fromList ) | ||
|
||
import Ledger.Value | ||
( AssetClass | ||
) | ||
|
||
import Test.Tasty.QuickCheck | ||
( Arbitrary | ||
, Gen | ||
, arbitrary | ||
, getPositive | ||
, shrink | ||
) | ||
|
||
import Tokenomia.Common.MultiAsset | ||
( MultiAsset(..) | ||
, MultiAssetFormat(..) | ||
) | ||
|
||
import Tokenomia.Common.Arbitrary.Modifiers ( Restricted(..) ) | ||
import Tokenomia.Common.Arbitrary.AssetClass () | ||
|
||
|
||
instance Arbitrary MultiAsset where | ||
arbitrary = MultiAsset <$> arbitrary | ||
shrink x = MultiAsset <$> shrink (unMultiAsset x) | ||
|
||
instance Arbitrary (Restricted MultiAsset) where | ||
arbitrary = Restricted . MultiAsset . Map.fromList <$> gen | ||
where | ||
gen :: Gen [(AssetClass, Integer)] | ||
gen = | ||
zip | ||
<$> (Set.toList <$> arbitrary) | ||
<*> (getPositive <$$> arbitrary) | ||
shrink x = Restricted <$> shrink (getRestricted x) | ||
|
||
instance Arbitrary MultiAssetFormat where | ||
arbitrary = MultiAssetFormat <$> arbitrary | ||
shrink x = MultiAssetFormat <$> shrink (unMultiAssetFormat x) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
{-# LANGUAGE ImportQualifiedPost #-} | ||
{-# LANGUAGE FlexibleInstances #-} | ||
{-# LANGUAGE TypeApplications #-} | ||
{-# OPTIONS_GHC -Wno-orphans #-} | ||
|
||
module Tokenomia.Common.Arbitrary.Value | ||
( Restricted(..) | ||
) where | ||
|
||
import Data.Functor.Syntax ( (<$$>) ) | ||
import Data.Set qualified as Set ( toList ) | ||
|
||
import Plutus.V1.Ledger.Value | ||
( AssetClass(..) | ||
, Value(..) | ||
, assetClassValue | ||
) | ||
|
||
import PlutusTx.AssocMap qualified as AssocMap | ||
( Map | ||
, fromList | ||
, toList | ||
) | ||
|
||
import Tokenomia.Common.MultiAsset | ||
( MultiAsset(..) | ||
, FromValue(..) | ||
, ToValue(..) | ||
) | ||
|
||
import Test.QuickCheck.Instances.ByteString () | ||
import Test.Tasty.QuickCheck | ||
( Arbitrary | ||
, Gen | ||
, arbitrary | ||
, getPositive | ||
, shrink | ||
) | ||
|
||
import Tokenomia.Common.Arbitrary.Modifiers ( Restricted(..) ) | ||
import Tokenomia.Common.Arbitrary.AssetClass () | ||
import Tokenomia.Common.Arbitrary.MultiAsset () | ||
|
||
|
||
instance (Arbitrary k, Arbitrary v) => Arbitrary (AssocMap.Map k v) where | ||
arbitrary = AssocMap.fromList <$> arbitrary | ||
shrink x = AssocMap.fromList <$> shrink (AssocMap.toList x) | ||
|
||
instance Arbitrary Value where | ||
arbitrary = Value <$> arbitrary | ||
shrink x = Value <$> shrink (getValue x) | ||
|
||
instance Arbitrary (Restricted Value) where | ||
arbitrary = | ||
Restricted . mconcat | ||
<$> uncurry assetClassValue <$$> gen | ||
where | ||
gen :: Gen [(AssetClass, Integer)] | ||
gen = | ||
zip | ||
<$> (Set.toList <$> arbitrary) | ||
<*> (getPositive <$$> arbitrary) | ||
shrink x = | ||
Restricted . toValue | ||
<$> shrink (fromValue @MultiAsset $ getRestricted x) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
{-# LANGUAGE ImportQualifiedPost #-} | ||
{-# LANGUAGE InstanceSigs #-} | ||
{-# LANGUAGE RecordWildCards #-} | ||
{-# LANGUAGE TypeApplications #-} | ||
|
||
module Tokenomia.Common.MultiAsset | ||
( MultiAsset(..) | ||
, MultiAssetFormat(..) | ||
, FromValue(..) | ||
, ToValue(..) | ||
, adjustAda | ||
, groupByAssetClass | ||
) where | ||
|
||
-- | ||
-- This wrapper module allows working on multiformat values | ||
-- with a flat representation as a map indexed by asset classes | ||
-- instead of the default nested maps representation | ||
-- indexed in turns by the components of the asset class tuple. | ||
-- | ||
-- Also, the underlying representation of plutus values | ||
-- are not true maps but lists of (key, value) pairs. | ||
-- This module provides a way to express multiformat values | ||
-- that can be indexed by unique asset class keys. | ||
-- | ||
-- Therefore, the type Value holds more inhabitants than MultiAsset. | ||
-- When duplicate keys occur in a Value, since the map is built fromList | ||
-- only the last value for the key is retained. | ||
-- In other words, the conversion fromValue :: Value -> MultiAssetFormat | ||
-- can suffer loss of data. | ||
-- | ||
-- Otherwise, for any well-formed value, there is a bijection | ||
-- between Value and MultiAsset. The following properies holds : | ||
-- fromValue . toValue == id | ||
-- toValue . fromValue == id | ||
-- | ||
|
||
import Data.List.NonEmpty ( NonEmpty, groupAllWith ) | ||
import Data.Map ( Map, fromList, toList, adjust, keysSet) | ||
import Data.Set ( Set ) | ||
|
||
import Ledger.Value | ||
( AssetClass(..) | ||
, Value(..) | ||
, assetClassValue | ||
, flattenValue | ||
) | ||
|
||
import Tokenomia.Common.AssetClass ( adaAssetClass ) | ||
|
||
|
||
newtype MultiAsset | ||
= MultiAsset { unMultiAsset :: Map AssetClass Integer } | ||
deriving (Show, Eq, Ord ) | ||
|
||
newtype MultiAssetFormat | ||
= MultiAssetFormat { unMultiAssetFormat :: Set AssetClass } | ||
deriving (Show, Eq, Ord) | ||
|
||
class FromValue a where | ||
fromValue :: Value -> a | ||
|
||
instance FromValue MultiAsset where | ||
fromValue :: Value -> MultiAsset | ||
fromValue value = | ||
MultiAsset . fromList $ | ||
(\(cs, tn, a) -> (AssetClass (cs, tn), a)) <$> flattenValue value | ||
|
||
instance FromValue MultiAssetFormat where | ||
fromValue :: Value -> MultiAssetFormat | ||
fromValue = | ||
MultiAssetFormat . keysSet . unMultiAsset . fromValue | ||
|
||
class ToValue a where | ||
toValue :: a -> Value | ||
|
||
instance ToValue MultiAsset where | ||
toValue :: MultiAsset -> Value | ||
toValue (MultiAsset xs) = | ||
mconcat $ uncurry assetClassValue <$> toList xs | ||
|
||
groupByAssetClass :: (a -> Value) -> [a] -> [NonEmpty a] | ||
groupByAssetClass value = groupAllWith $ fromValue @MultiAssetFormat . value | ||
|
||
adjustAda :: Integer -> MultiAsset -> MultiAsset | ||
adjustAda amount = | ||
wrap $ adjust (const amount) adaAssetClass | ||
where | ||
wrap f = MultiAsset . f . unMultiAsset |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
{-# LANGUAGE TypeApplications #-} | ||
|
||
module Spec.Tokenomia.Common.MultiAsset | ||
( tests | ||
) where | ||
|
||
-- | ||
-- This module tests the `MultiAsset` wrapper. | ||
-- | ||
|
||
import Test.Tasty ( TestTree, testGroup ) | ||
import Test.Tasty.QuickCheck ( testProperty ) | ||
|
||
import Tokenomia.Common.MultiAsset | ||
( MultiAsset(..) | ||
, FromValue(..) | ||
, ToValue(..) | ||
) | ||
|
||
import Tokenomia.Common.Arbitrary.Modifiers ( Restricted(..) ) | ||
import Tokenomia.Common.Arbitrary.MultiAsset () | ||
import Tokenomia.Common.Arbitrary.Value () | ||
|
||
|
||
tests :: TestTree | ||
tests = testGroup "Common.MultiAsset" [ properties ] | ||
|
||
properties :: TestTree | ||
properties = testGroup "Properties" | ||
[ testGroup "MultiAsset" | ||
[ testGroup "Bijection Laws" | ||
[ testProperty "fromValue . toValue == id" | ||
(\restricted -> | ||
let x = getRestricted restricted | ||
in (fromValue . toValue @MultiAsset $ x) == x | ||
) | ||
, testProperty "toValue . fromValue == id" | ||
(\restricted -> | ||
let x = getRestricted restricted | ||
in (toValue @MultiAsset . fromValue $ x) == x | ||
) | ||
] | ||
] | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters