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 + 531f4ca commit 629edb4
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 58 deletions.
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

0 comments on commit 629edb4

Please sign in to comment.