Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Asset metadata JSON schema updates #2546

Merged
merged 8 commits into from
Mar 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ steveToken = ApiAssetMetadata
"SteveToken" "A sample description" (Just "STV")
(Just (ApiT (unsafeFromText "https://iohk.io/stevetoken")))
(Just (ApiT (W.AssetLogo "Almost a logo")))
(Just (ApiT (W.AssetUnit "MegaSteve" 6)))
(Just (ApiT (W.AssetUnit "MegaSteve" 6 Nothing)))

---
--- Helpers
Expand Down
17 changes: 14 additions & 3 deletions lib/core/src/Cardano/Wallet/Primitive/Types/TokenPolicy.hs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ instance NFData AssetMetadata
data AssetUnit = AssetUnit
{ name :: Text -- ^ Name of the larger asset.
, decimals :: Natural -- ^ Number of zeroes to add to base unit.
, ticker :: Maybe Text -- ^ Optional abbreviation of larger asset name
} deriving (Generic, Show, Eq, Ord)

instance NFData AssetUnit
Expand Down Expand Up @@ -261,7 +262,7 @@ validateMetadataName :: Text -> Either String Text
validateMetadataName = validateMinLength 1 >=> validateMaxLength 50

validateMetadataTicker :: Text -> Either String Text
validateMetadataTicker = validateMinLength 2 >=> validateMaxLength 4
validateMetadataTicker = validateMinLength 2 >=> validateMaxLength 5

validateMetadataDescription :: Text -> Either String Text
validateMetadataDescription = validateMaxLength 500
Expand All @@ -278,8 +279,18 @@ validateMetadataURL = fmap AssetURL .
| otherwise = Left $ "Scheme must be https: but got " ++ scheme

validateMetadataUnit :: AssetUnit -> Either String AssetUnit
validateMetadataUnit assetUnit@AssetUnit{name} =
(validateMinLength 1 name >>= validateMaxLength 30) $> assetUnit
validateMetadataUnit = validateName >=> validateTicker >=> validateDecimals
where
validateName u@AssetUnit{name} =
(validateMinLength 1 name >>= validateMaxLength 30) $> u
validateTicker u@AssetUnit{ticker} =
case fmap validateMetadataTicker ticker of
Just (Left e) -> Left e
_ -> Right u
validateDecimals u@AssetUnit{decimals}
| decimals > 0 && decimals < 20 = Right u
| otherwise =
Left "AssetUnit decimals must be greater than 0 and less than 20"

validateMetadataLogo :: AssetLogo -> Either String AssetLogo
validateMetadataLogo logo
Expand Down
8 changes: 6 additions & 2 deletions lib/core/src/Cardano/Wallet/TokenMetadata.hs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ data Property name = Property
-- ^ The result of JSON parsing and validating the property value.
, signatures :: [Signature]
-- ^ Zero or more signatures of the property value.
, sequenceNumber :: Int
-- ^ Counter to prevent replaying old signatures.
} deriving (Generic)

propertyName :: forall name. KnownSymbol name => Property name -> PropertyName
Expand Down Expand Up @@ -268,7 +270,6 @@ type instance PropertyValue "logo" = AssetLogo
class HasValidator (name :: Symbol) where
-- TODO: requires AllowAmbiguousTypes extension
validatePropertyValue :: PropertyValue name -> Either String (PropertyValue name)
validatePropertyValue = Right

instance HasValidator "name" where
validatePropertyValue = validateMetadataName
Expand All @@ -278,6 +279,7 @@ instance HasValidator "ticker" where
validatePropertyValue = validateMetadataTicker
instance HasValidator "url" where
-- validation is done before parsing
validatePropertyValue = Right
instance HasValidator "logo" where
validatePropertyValue = validateMetadataLogo
instance HasValidator "unit" where
Expand Down Expand Up @@ -553,7 +555,8 @@ instance FromJSON SubjectProperties where
instance (HasValidator name, FromJSON (PropertyValue name)) => FromJSON (Property name) where
parseJSON = withObject "Property value" $ \o -> Property
<$> (validate <$> o .: "value")
<*> o .:? "anSignatures" .!= []
<*> o .:? "signatures" .!= []
<*> o .:? "sequenceNumber" .!= 0
where
validate v = first (,v) $ (>>= validatePropertyValue @name) $ tryParse v
tryParse = resultToEither . fromJSON
Expand Down Expand Up @@ -581,6 +584,7 @@ instance FromJSON AssetUnit where
parseJSON = withObject "AssetUnit" $ \o -> AssetUnit
<$> o .: "name"
<*> o .: "decimals"
<*> o .:? "ticker"

--
-- Helpers
Expand Down
6 changes: 4 additions & 2 deletions lib/core/src/Cardano/Wallet/TokenMetadata/MockServer.hs
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,11 @@ instance ToJSON SubjectProperties where
optionals = filter ((/= Null) . snd)

instance ToJSON (PropertyValue name) => ToJSON (Property name) where
toJSON (Property v s) = object
toJSON (Property v s c) = object
[ "value" .= either snd toJSON v
, "anSignatures" .= s ]
, "signatures" .= s
, "sequenceNumber" .= c
]

instance ToJSON Signature where
toJSON (Signature s k) = object
Expand Down
7 changes: 4 additions & 3 deletions lib/core/test/data/Cardano/Wallet/TokenMetadata/golden1.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
},
"name": {
"value": "SteveToken",
"anSignatures": [
"sequenceNumber": 1,
"signatures": [
{
"signature": "7ef6ed44ba9456737ef8d2e31596fdafb66d5775ac1a254086a553b666516e5895bb0c6b7ba8bef1f6b4d9bd9253b4449d1354de2f9e043ea4eb43fd42f87108",
"publicKey": "0ee262f062528667964782777917cd7139e19e8eb2c591767629e4200070c661"
Expand All @@ -34,7 +35,7 @@
},
"description": {
"value": "A sample description",
"anSignatures": [
"signatures": [
{
"signature": "83ef5c04882e43e5f1c8e9bc386bd51cdda163f5cbd1996d1d066238de063d4b79b1648b48aec63dddff05649911ca116579842c8e9a08a3bc7ae1a0ec7ef000",
"publicKey": "1446c9d327b0f07aa691014c08578867674f3a88b36f2017a58c37a8a7799058"
Expand Down Expand Up @@ -62,7 +63,7 @@
"subject": "missing sigs",
"name": {
"value": "Token1",
"anSignatures": []
"signatures": []
},
"description": {
"value": "description1"
Expand Down
27 changes: 22 additions & 5 deletions lib/core/test/data/Cardano/Wallet/TokenMetadata/golden2.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"name": {
"value": "SteveToken",
"anSignatures": [
"signatures": [
{
"signature": "7ef6ed44ba9456737ef8d2e31596fdafb66d5775ac1a254086a553b666516e5895bb0c6b7ba8bef1f6b4d9bd9253b4449d1354de2f9e043ea4eb43fd42f87108",
"publicKey": "0ee262f062528667964782777917cd7139e19e8eb2c591767629e4200070c661"
Expand All @@ -34,7 +34,7 @@
},
"description": {
"value": "A sample description",
"anSignatures": [
"signatures": [
{
"signature": "83ef5c04882e43e5f1c8e9bc386bd51cdda163f5cbd1996d1d066238de063d4b79b1648b48aec63dddff05649911ca116579842c8e9a08a3bc7ae1a0ec7ef000",
"publicKey": "1446c9d327b0f07aa691014c08578867674f3a88b36f2017a58c37a8a7799058"
Expand Down Expand Up @@ -62,10 +62,14 @@
"subject": "missing sigs",
"name": {
"value": "Token1",
"anSignatures": []
"signatures": []
},
"description": {
"value": "description1"
},
"ticker": {
"value": "tck1",
"sequenceNumber": 2
}
},
{ "subject": "bad00000000000000000000000000000000000000000000000000000",
Expand All @@ -75,9 +79,22 @@
},
{
"subject": "extra fields",
"name": { "value": "Token2" },
"name": { "value": "Token2", "hello": true },
"description": { "value": "description2" },
"ticker": { "value": "ticker2" }
"ticker": { "value": "ticker2" },
"custom": { "value": "meta" }
},
{
"subject": "unit with ticker",
"name": { "value": "Token3" },
"description": { "value": "description3" },
"unit": {
"value": {
"name": "BigToken3",
"decimals": 3,
"ticker": "tck3"
}
}
}
]
}
30 changes: 27 additions & 3 deletions lib/core/test/data/Cardano/Wallet/TokenMetadata/golden4.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
{
"subject": "malformed unit - wrong type",
"name": {
"value": "token9"
"value": "Token9"
},
"description": {
"value": "description9"
Expand All @@ -27,7 +27,7 @@
{
"subject": "malformed unit - name too long",
"name": {
"value": "token10"
"value": "Token10"
},
"description": {
"value": "description10"
Expand All @@ -42,14 +42,38 @@
{
"subject": "malformed url - wrong scheme",
"name": {
"value": "token11"
"value": "Token11"
},
"description": {
"value": "description11"
},
"url": {
"value": "javascript:window.alert('hello')"
}
},
{
"subject": "malformed ticker - too short",
"name": {
"value": "Token12"
},
"description": {
"value": "description12"
},
"ticker": {
"value": "x"
}
},
{
"subject": "malformed ticker - too long",
"name": {
"value": "Token13"
},
"description": {
"value": "description13"
},
"ticker": {
"value": "ticker13"
}
}
]
}
57 changes: 34 additions & 23 deletions lib/core/test/unit/Cardano/Wallet/TokenMetadataSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import Data.Aeson
import Data.Either
( isRight )
import Data.Maybe
( isJust, isNothing )
( isNothing )
import Network.URI
( parseURI )
import System.FilePath
Expand All @@ -55,44 +55,53 @@ spec :: Spec
spec = do
describe "JSON decoding" $ do
describe "BatchResponse" $ do
it "golden1.json" $ do
it "golden1.json - Simple valid WKP" $ do
decodeGoldenBatch golden1File `shouldReturn` golden1Properties

it "golden2.json" $ do
it "golden2.json - Valid WKP" $ do
rs <- decodeGoldenBatch (dir </> "golden2.json")
length rs `shouldBe` 4
length rs `shouldBe` 5

it "golden3.json" $ do
it "golden3.json - Required WKP are invalid" $ do
rs <- decodeGoldenBatch (dir </> "golden3.json")
rs `shouldNotBe` []
length rs `shouldBe` 5

it "golden4.json" $ do
it "golden4.json - Non-required WKP are invalid" $ do
rs <- decodeGoldenBatch (dir </> "golden4.json")
rs `shouldNotBe` []
length rs `shouldBe` 6

describe "metadataFromProperties" $ do
it "golden1.json" $ do
it "golden1.json - Simple valid WKP" $ do
map metadataFromProperties golden1Properties
`shouldBe` (Just <$> [golden1Metadata0,golden1Metadata1,golden1Metadata2])

it "golden2.json" $ do
it "golden2.json - Valid WKP" $ do
rs <- decodeGoldenBatch (dir </> "golden2.json")
map metadataFromProperties rs `shouldBe`
[ Just golden1Metadata0
, Just (AssetMetadata "Token1" "description1" Nothing Nothing Nothing Nothing)
, Just (AssetMetadata "Token1" "description1" (Just "tck1") Nothing Nothing Nothing)
, Nothing
, Just (AssetMetadata "Token2" "description2" Nothing Nothing Nothing Nothing)
, Just (AssetMetadata "Token3" "description3" Nothing Nothing Nothing (Just (AssetUnit "BigToken3" 3 (Just "tck3"))))
]

it "golden3.json" $ do
it "golden3.json - Required WKP are invalid" $ do
rs <- decodeGoldenBatch (dir </> "golden3.json")
rs `shouldNotBe` []
map metadataFromProperties rs `shouldSatisfy` all isNothing

it "golden4.json" $ do
it "golden4.json - Non-required WKP are invalid" $ do
rs <- decodeGoldenBatch (dir </> "golden4.json")
rs `shouldNotBe` []
map metadataFromProperties rs `shouldSatisfy` all isJust
map metadataFromProperties rs `shouldBe`
map Just
[ AssetMetadata "Token7" "description7" Nothing Nothing Nothing Nothing
, AssetMetadata "Token9" "description9" Nothing Nothing Nothing Nothing
, AssetMetadata "Token10" "description10" Nothing Nothing Nothing Nothing
, AssetMetadata "Token11" "description11" Nothing Nothing Nothing Nothing
, AssetMetadata "Token12" "description12" Nothing Nothing Nothing Nothing
, AssetMetadata "Token13" "description13" Nothing Nothing Nothing Nothing
]

traceSpec $ describe "Using mock server" $ do
it "testing empty req" $ \tr ->
Expand Down Expand Up @@ -145,7 +154,7 @@ spec = do
(Just "acr2")
(AssetURL <$> parseURI "https://iohk.io")
(Just $ AssetLogo $ unsafeFromBase64 "QWxtb3N0IGEgbG9nbw==")
(Just $ AssetUnit "unit2" 14)
(Just $ AssetUnit "unit2" 14 Nothing)
golden2File = dir </> "golden2.json"

sig s k = Signature (unsafeFromHex s) (unsafeFromHex k)
Expand All @@ -161,13 +170,15 @@ spec = do
, sig "f88692b13212bac8121151a99a4de4d5244e5f63566babd2b8ac20950ede74073af0570772b3ce3d11b72e972079199f02306e947cd5fcca688a9d4664eddb04" "8899d0777f399fffd44f72c85a8aa51605123a7ebf20bba42650780a0c81096a"
, sig "c2b30fa5f2c09323d81e5050af681c023089d832d0b85d05f60f4278fba3011ab03e6bd9bd2b8649080a368ecfe51573cd232efe8f1e7ca69ff8334ced7b6801" "d40688a3eeda1f229c64efc56dd53b363ff981f71a7462f78c8cc444117a03db"
]
1
, Just $ Property (Right "A sample description")
[ sig "83ef5c04882e43e5f1c8e9bc386bd51cdda163f5cbd1996d1d066238de063d4b79b1648b48aec63dddff05649911ca116579842c8e9a08a3bc7ae1a0ec7ef000" "1446c9d327b0f07aa691014c08578867674f3a88b36f2017a58c37a8a7799058"
, sig "4e29a00feaeb24b25315f0eac28bbfc550dabfb847bf6a06cb8086120201f90c64fab778037d0ef009ab4669121a38fe9b8c0a6aec99c68366c5187c0889520a" "1910312a9a6998c7e4f585dc138f85a90f50a28397b8ea05eb23355fb8ea4fa0"
, sig "ce939acca5677bc6d436bd8f054ed8fb03d143e0a9792c1f58592c43f175e89bb72d4d7114c1474b86e0d8fbf7807f4506325b56fcc6b87b2cb7002872527106" "4c5bbbbe7caaa18372aa8edc1ef2d2a770d18a5c2d142b9d695619c3365dd297"
, sig "5a1d55048234d92057dfd1938f49935a33751ee604b7dbd02a315418ced6f0836a51107512b192eae6133403bb437c6850b1af1c62c3b17a372acce77adf9903" "57fa73123c3b39489c4d6c2ff3cab9952e56e556daab9f8f333bc5ca6984fa5e"
, sig "e13c9ba5b084dc126d34f3f1120fff75495b64a41a98a69071b5c5ed01bb9d273f51d570cf4fdaa42969fa2c775c12ec05c496cd8f61323d343970136781f60e" "8cc8963b65ddd0a49f7ce1acc2915d8baff505bbc4f8727a22bd1d28f8ad6632"
]
0
, Nothing
, Nothing
, Nothing
Expand All @@ -178,8 +189,8 @@ spec = do
{ subject = "missing sigs"
, owner = Nothing
, properties =
( Just $ Property (Right "Token1") []
, Just $ Property (Right "description1") []
( Just $ Property (Right "Token1") [] 0
, Just $ Property (Right "description1") [] 0
, Nothing
, Nothing
, Nothing
Expand All @@ -190,12 +201,12 @@ spec = do
{ subject = "extra fields"
, owner = Nothing
, properties =
( Just $ Property (Right "Token2") []
, Just $ Property (Right "description2") []
, Just $ Property (Right "acr2") []
, Just $ Property (parseAssetURL "https://iohk.io") []
, Just $ Property (Right (AssetLogo $ unsafeFromBase64 "QWxtb3N0IGEgbG9nbw==")) []
, Just $ Property (Right (AssetUnit "unit2" 14)) []
( Just $ Property (Right "Token2") [] 0
, Just $ Property (Right "description2") [] 0
, Just $ Property (Right "acr2") [] 0
, Just $ Property (parseAssetURL "https://iohk.io") [] 0
, Just $ Property (Right (AssetLogo $ unsafeFromBase64 "QWxtb3N0IGEgbG9nbw==")) [] 0
, Just $ Property (Right (AssetUnit "unit2" 14 Nothing)) [] 0
)
}
]
Expand Down
Loading