Skip to content

Commit

Permalink
Merge #2546
Browse files Browse the repository at this point in the history
2546: Asset metadata JSON schema updates r=rvl a=rvl

### Issue Number

ADP-770

### Overview

- Increase max length of `ticker` field to 5.
- Clarify OpenAPI documentation strings.
- Add a `ticker` sub-field to `unit`.
- Require `unit` field `decimals` to be positive. If it is 0, then `unit` wouldn't be needed.
- Rename `anSignatures` to `signatures`and add `sequenceNumber` in properties of the metadata-server JSON response. These are not used yet, but I may as well update it so we're ready to check signatures.


Co-authored-by: Rodney Lorrimar <rodney.lorrimar@iohk.io>
  • Loading branch information
iohk-bors[bot] and rvl committed Mar 4, 2021
2 parents 1b42a42 + ae61ff8 commit 954a804
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 57 deletions.
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

0 comments on commit 954a804

Please sign in to comment.