Great proposal. I’ve been experimenting the past month+ using ERC6909 for a few multi-token ideas and I love it. It’s clean, consistent, expressive, and flexible. It’s the multi-token standard of the future.
Metadata Extension Feedback
The one point of inconsistency is in the Metadata Extension — static name()
, static symbol()
, but dynamic decimals(uint256)
does not make sense imo. I struggle to find a use case that would benefit from dynamic decimal values based on token ID, but not also from dynamic names/symbols.
NFTs
For the case of ERC721-style NFTs, decimals always equal 1, and there is a single, unifying name and symbol for the collection. So, doesn’t benefit afaict from dynamic anything here.
Token Wrappers
For an ERC20 token wrapper, which I believe was the initial inspiration for supporting dynamic decimals values per token ID, it will also be useful to have dynamic names/symbols. Let’s take as an example, a single 6909 contract wrapping USDC, DAI, FRAX, etc — the former could return 6 decimals, the latter two 18.
But how is a user or integrator to disambiguate between which ERC20 is being wrapped by which token ID? That is a perfect use case for name/symbol — “xyzUSDC”, “xyzDAI”, “xyzFRAX”, etc. Otherwise, for this use case, we would be leaving it up individual implementors to decide how to map token ID to an explanatory name or other indicator of what token is being wrapped (perhaps the underlying ERC20 contract address). Which then puts pressure on downstream integrators and marketplaces to support custom implementations to display this info to end users.
DeFi Derivatives
For a similar use case of a derivative or some kind of synthetic asset, developers may be more likely to want to define a consistent scalar unit and return that from decimals(), but give an expressive name/symbol to each token ID. For example, take a tokenized options protocol — decimals() might always return 18 but depending on the underlying asset(s) and instrument type of a given token ID, both name and symbol might return “xyz-ETH-USDC-1DEC23-2100-C”.
It’s important that name(id)
, symbols(id)
, and decimals(id)
are all dynamic based on token ID, for any use case that looks like, “combine multiple ERC20 contract deploys into a single, unified multi-token contract.”
Again, without this, we rely on each implementor to disambiguate the semantic meaning of various token IDs in their own way, which fragments the common usage of ERC6909 and creates headaches for downstream integrators and marketplaces.
DeFi LP Tokens
This is another use case where it is more likely for a developer to be okay with static decimals but want dynamic names/symbols. Think of Uniswap v4’s planned ERC1155 balance accounting (or perhaps ERC6909 =), or any singleton AMM design — the name/symbol can specify what the LP token is.
Gaming
For gaming, the original motivation behind ERC1155, the content of in-game items may be best suited to definition in URI JSON. And potentially this is a use case where a developer would want a single unifying name and symbol for their collection, and dynamic decimals values (eg, in-game collectible items vs. in-game currency). Although still I’d argue that varying decimal values between token IDs makes them conceptually and fundamentally different enough, such that having a way to disambiguate them that is more onchain-native than having to parse JSON is important for developer ergonomics.
Aside on Syntax
Semantics aside, there is one syntactic wrinkle yet in both the current Metadata Extension and my proposal, but I don’t think it’s a big deal —
Because decimals is already plural, when the function is decimals(id)
, we pedantically might be tempted to call it whatever the plural of decimals is (?), or something like decimalss, decimalz, etc =). But in practice, imo it’s idiomatic enough that developers can understand the expectations and semantics.
tl;dr
Excellent minimal multi-token spec. But for consistency and flexibility across sectors/use cases, the Metadata Extension names/symbols/decimals should either be (1) all dynamic based on token ID, or (2) all static and not take token ID as a parameter. Imo the former is significantly more powerful and more likely to provide great DevEx for future developers and integrators, while still keeping with the ‘minimalist’ spirit of this EIP.
Proposed Metadata Extension Interface
(And of course, these could be implemented as some combination of private state variables and public/external functions, which contain some business logic or just return constant values, such that not all returned values need come directly from storage.)
interface IERC6909Metadata is IERC6909 {
function names(uint256 id) external view returns (string memory);
function symbols(uint256 id) external view returns (string memory);
function decimals(uint256 id) external view returns (uint8);
}