I was thinking if I could implement custom ERC-20-like token in Move using Libra standard library
A Libra::T<CoinType>
resource is intended to be a generic representation of currency that supports adding custom tokens that share the same underlying logic.
-
Libra::CurrencyInfo<CoinType>.total_value
is the equivalent of ERC20’s totalSupply
- To create a custom coin, add a new module that declares a type to instantiate the
CoinType
type parameter. Here are two examples of this: Coin1
(a very simple custom coin) and LBR
(a synthetic currency backed by an on-chain reserve of Coin1
and Coin2
).
- If a
LibraAccount
wishes to begin accepting a new currency MyCoin::T
, it can call LibraAccount::add_currency<MyCoin::T>
(which will publish a LibraAccount::Balance<MyCoin::T>
under the sender’s account).
An important way that Libra
differs from ERC20 is that it does not require (or allow) the custom token creator to reimplement logic that should be similar for all coins (e.g., computing the total value, joining/splitting coins, transfers,getting the value of a particular coin). The custom token implementer only needs to define additional constraints on minting (for example, it is possible to implement a currency that has a maximum total supply of 1000, or Bitcoin-like coin whose total supply increases in a predictable fashion over time) or burning (for example, it is possible to create a coin that can never be burned or a coin that costs 1 LBR to burn).
Do you have any plans or open proposals on traits/interfaces like in Rust? Will it be possible in future to do custom type/impl constraints (like or <T: copyable>)?
We are not currently planning to support traits or interfaces. We feel that dynamic dispatch is not an appropriate feature for a smart contract language (as we sometimes cheekily say: “in a world where code is law, interfaces are a crime”). Move’s ability to read/write global storage with a generic type parameter chosen at runtime (e.g., borrow_global<Libra::T<CoinType>>(addr)
where CoinType
is chosen at runtime) is quite powerful. Many patterns that would use an interface in a conventional language can also be implemented using this safer, more restrictive “storage polymorphism” (see LibraConfig
for another example of this).
Hope this helps and let me know if you have more questions! Storage polymorphism and its associated design patterns are (in my view) subtle, but very flexible once you’ve gotten comfortable with it.