2

We have a specific Datum, taken from Orcfax oracle UTXO: https://preprod.cexplorer.io/datum/9ced750ebbb2c9a9eac2e07a91525cadd3bfab23950089faa3e3a55517d1033f

the part we are interested in is the very first field, map:

"map": [
        {
            "k": {
                "bytes": "40636f6e74657874"
            },
            "v": {
                "bytes": "68747470733a2f2f736368656d612e6f7267"
            }
        },
        {
            "k": {
                "bytes": "5f3a636f6e74656e745369676e6174757265"
            },
            "v": {
                "bytes": "61346230303130306537313331386533633130373266343332643930373264376530356230386530666338353333656363323531323861623934653737323937"
            }
        },
        {
            "k": {
                "bytes": "6964656e746966696572"
            },
            "v": {
                "map": [
                    {
                        "k": {
                            "bytes": "70726f70657274794944"
                        },
                        "v": {
                            "bytes": "41726b6c79204964656e746966696572"
                        }
                    },
                    {
                        "k": {
                            "bytes": "74797065"
                        },
                        "v": {
                            "bytes": "50726f706572747956616c7565"
                        }
                    },
                    {
                        "k": {
                            "bytes": "76616c7565"
                        },
                        "v": {
                            "bytes": "75726e3a6f72636661783a61636130373632622d326661372d346461622d396261352d663935333631373430633738"
                        }
                    }
                ]
            }
        },
        {
            "k": {
                "bytes": "6e616d65"
            },
            "v": {
                "bytes": "4144412d5553447c5553442d414441"
            }
        },
        .........................

The strange thing is, values are of a different type. Some are strings, some are lists or integers. As far as I understand, in Plutus/Haskell, AssocMap can contain only values of the same type, and there is no way to declare a type for this Map.

The closest I get to this structure in Plutus is this:

import PlutusTx.AssocMap (Map, fromList)

data OrcfaxDatum = OrcfaxDatum {
    testOne  :: BuiltinByteString,
    testTwo  :: (Map BuiltinByteString BuiltinByteString, Map BuiltinByteString Integer, Map BuiltinByteString [Integer])
  } deriving Show
PlutusTx.makeIsDataIndexed ''OrcfaxDatum [('OrcfaxDatum, 0)]
PlutusTx.makeLift ''OrcfaxDatum

-- in offchain code:
let datum = OrcfaxDatum "test" (fromList [("test", "test")], fromList [("test", 1)], fromList [("test", [1])])
let dr = encode (scriptDataToJson ScriptDataJsonDetailedSchema $ fromPlutusData (PlutusTx.toData datum))
Haskell.error $ Haskell.show $ dr

which produces the following JSON output:

{
   "constructor":0,
   "fields":[
      {
         "bytes":"74657374"
      },
      {
         "constructor":0,
         "fields":[
            {
               "map":[
                  {
                     "v":{
                        "bytes":"74657374"
                     },
                     "k":{
                        "bytes":"74657374"
                     }
                  }
               ]
            },
            {
               "map":[
                  {
                     "v":{
                        "int":1
                     },
                     "k":{
                        "bytes":"74657374"
                     }
                  }
               ]
            },
            {
               "map":[
                  {
                     "v":{
                        "list":[
                           {
                              "int":1
                           }
                        ]
                     },
                     "k":{
                        "bytes":"74657374"
                     }
                  }
               ]
            }
         ]
      }
   ]
}

But these are just a separate maps, and Orcfax Datum JSON won't be parsed correctly. If Map in Orcfax Datum would contain values of identical type, parsing would be easy:

import PlutusTx.AssocMap (Map, fromList)

data OrcfaxDatum = OrcfaxDatum {
    testOne  :: BuiltinByteString,
    testTwo  :: Map BuiltinByteString BuiltinByteString
  } deriving Show
PlutusTx.makeIsDataIndexed ''OrcfaxDatum [('OrcfaxDatum, 0)]
PlutusTx.makeLift ''OrcfaxDatum

-- offchain code
let orcfaxMap = fromList [("test", "test"), ("test", "test")]
let datum = OrcfaxDatum "test" orcfaxMap
let dr = encode (scriptDataToJson ScriptDataJsonDetailedSchema $ fromPlutusData (PlutusTx.toData datum))
Haskell.error $ Haskell.show $ dr

Result:

{
   "constructor":0,
   "fields":[
      {
         "bytes":"74657374"
      },
      {
         "map":[
            {
               "v":{
                  "bytes":"74657374"
               },
               "k":{
                  "bytes":"74657374"
               }
            },
            {
               "v":{
                  "bytes":"74657374"
               },
               "k":{
                  "bytes":"74657374"
               }
            }
         ]
      }
   ]
}

As you can see, the structure is identical.

I think this Datum was built with Mesh or something similar:

import { resolveDataHash } from '@meshsdk/core';
import type { Data } from '@meshsdk/core';

const datumMap: Data = new Map<Data, Data>();
datumMap.set('token', 'meshtoken');
datumMap.set('price', '12345678');
const datumMapHash = resolveDataHash(datumMap);
// datahash: 406f12b8df90412d7af0ff40e80ce62234602ed0b5af2633042b866b1a22b8f4

const datumMap2: Data = new Map<Data, Data>();
datumMap2.set([1, 2], ['meshtoken', 123]);
datumMap2.set([3, 4], 12345678);
const datumMap2Hash = resolveDataHash(datumMap2);
// datahash: 9017cbec493c851cf0f19ff0e69a8188266cefdd9af2210496c55e7a1d743bdb

What am I missing?

How to parse this Datum onchain with PlutusV2?

How to define type for this map?

thanks

1 Answer 1

2

You could define a union type for values, something like

data Val = B BuiltinByteString
  | M (AssocMap BuiltinByteString Val)

type OrcFax = AssocMap BuiltinByteString Val

then you can deserialise the Datum to a raw Data and "parse" it manually, pattern matching on the parts you are interested in. Data being a generic description of any data structure, allows to mix types this way.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.