When I deploy an ERC20 on Polkadot JS Apps, i can see that the return type of total_supply is u128, however according to the contract metadata it should display Balance. Noticed also for ERC1155 messages, for example create

Is this intentional or is it a bug?

1 Answer 1


You are most-probably assuming that something with a displayName of Balance conveys more information than it does. It does not refer to a specific instance of a Balance type on-chain nor to a specific pallet that ties it into any display formatting. For Substrate there is no real "one-balance-rules-all" indicator.

In terms of the balances pallet itself, something that has displayName: Balance is provided as a type in the config to the pallet instance, i.e. where it is instantiated in the runtime. The following is done (which the metadata then converts into the actual primitive type as well as displayName as used in the pallet code) -

impl pallet_balances::Config for Runtime {
    type Balance = Balance;

Now bear in mind that the chain itself can have multiple instances of this pallet (chains are not required to have only a single Balance instance and indeed a growing number does not) and for each of these instances, even if they do point to the same primitive type in terms of storage size, the formatting would be different in terms of token and decimals.

In the same fashion, there are multiple pallets that also take a config param of Balance, but in their cases it is not something that reflects native tokens or can be formatted in that way. An example is assets which also gets configured with a type Balance = ... whith a subsequent displayName: Balance but the formatting there is purely driven by the on-chain metadata for a specific asset instance. So here a Balance displayName cannot be equated to a Balance displayName that is in-use anywhere else. [1]

In the runtime contracts instantiation, the mapping for Balances is done via the type Currency = Balances where Balances refers to a specific instance of the balance pallet, here no type Balance = ... is injected into the config.

Contracts, as to be deployed via a .contract file, are even more loosely defined, since there is no trait config information that gets supplied or that can be used to tie a displayName to any runtime pallet that is available on-chain. Here the Balance formatting is up to the user intent.

So there is nothing in the metadata for the contracts pallet, nor in the contract-as-deployed types itself, that ties displayName: Balance to a type in the runtime, aka a specific instance of a balances runtime pallet. The Currency = Balances is not in the metadata mapping to infer which Balance instance is used. Contracts are certainly not tied to a specific runtime. What can be deduced 100% is the size of the type since that is absolutely specified, not the meaning and/or formatting. [2]

So in the current iteration, by design, unless the UI itself applies display overrides, each generic formatter only displays the primitive - as mapped to by the metadata type, never on the inexact string-name. There is just not enough information to actually try and map any single type to a specific instance of a same-name-type elsewhere. The apps UI deals in absolutes - unless it known 100% that there is an is exact match, it doesn't attempt it.

[1] They could refer, despite having the same name, to different underlying primitives, or the same primitive with obviously different meanings

[2] Not sure what happens when you deploy a contract containing types mapping Balance as u128 on a chain with a Balance as u64. (e.g. ERC* doesn't really reflect an actual movable balances-pallet-instance balance, so no reason not to work, just not sure if there is checks or not...)

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.