1

Could you please tell me how convert a queryResult from Substrate storage into js object?

i use these two functions to get the object from chain into js object

  1. queryResult.toHuman() function, but it adds commas to numbers of u64 type, although it parses strings as text

  2. queryResult.toJSON() makes all strings hex

In polkadot/api package version 8.12.2 when specifying types for ApiPromise, all the string processed by the package are hex strings. My struct on chain is Example: { field: Vec }

it used to be that if i were to specify to pass into ApiPromise Example: { field: "Text" } it would automatically transform from a hex to a string when specified in types.

Now, doesn't matter if i say field: "Text" or field: "Vec" in types on js client side, the string parsed by a library is a hex. I also noticed that i don't need to specify example struct in types at all, it will return me the object from the chain, even though in the past it wouldn't be able to read it. I have just recently updated substrate node to a version 0.9.24.

Could you please tell me if this behavior is normal for the latest versions of polkadot js api and substrate? Is there a way to specify on js side how to parse a Vec field from the node: as a hex or as a string?

.toHuman() function returns strings but commas in numbers aren't desirable

1 Answer 1

4

As of metadata v14 you don't need to pass any type definitions - the runtime metadata fully specifies all objects and the API will use these type definitions.

In general, there are a couple of to* methods on Codec objects. They are -

  • toHuman() - this returns a human-readable presentation of the data. Generally you don't want to use these programatically, it is formatted for (slightly opinionated) display
  • toJSON() - this returns an object that is meant for passing over RPC. This means that data is presented in a format that makes sense to RPC servers, i.e. Vec<u8> appears as hex, numbers (> u32) as well.
  • toPrimitive() - this returns a best-effort JS primitive representation with boolean/string/number fields
  • toHex() - this returns a hex-based representation
  • toU8a() - this returns a SCALE representation of the data
  • toString() - this is a text data representation

Objects that represent numbers have additional utility methods, such as toNumber(), toBn() and toBigInt().

In your case you have a Rust struct. These are decoded into a JS Map object, so it has all the methods that are on normal maps.

Additionally, field getters are also added to this Map, it means you can do -

// retrieve object, it has the on-chain form
// { a: 'Vec<u8>', b: 'u64' }
const obj = await api.query.somewhere.foo();

// display the internal values as string, each field
// has a getter, so no need to use obj.get(<field>)
console.log(
  // Vec<u8>/Bytes has toUtf8() for string representation
  obj.a.toUtf8(),
  // display number as non-formatted string
  obj.b.toString()
);

So in this case for any struct, you have getters that gives you access to the specific fields (over-and-above general Map methods such as .entries(), etc.)

2
  • Thank you Jaco for your answer! I know these functions and have been using them. The problem i am facing is that i receive objects that can be different in their fields. toHuman and toJSON work nicely, but toJSON puts all strings to hex, even though it used to depend on types specified for ApiPromise object. toHuman returns all fields correctly except numbers, it turns them to strings because these are BigInts. I need a way to parse object such that string fields are text as in toHuman but number fields are numbers as in toJSON. I can write my own parser but it seems custom types' purpose.
    – cocokick
    Jul 16, 2022 at 9:16
  • toPrimitive() may yield what you are after?
    – Luna
    Aug 15, 2022 at 14:16

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.