Mina Token Standard Smart Contract Implementation Discussion

Simple Summary

I am trying to implement simple tokens on top of Mina, which would provide basic functionality to transfer tokens. This could in the future be transformed into a standard interface that allows any tokens on Mina to be re-used by other applications: from wallets to other Snapps.

Motivation

From my understanding, Mina used to have a documentation explaining the protocol layer support for tokens. Yet the previous documentation regarding the token section (https://docs.minaprotocol.com/en/architecture/tokens) seems to be not visible now.

This forum could be used as a starting point for developers to discuss about implementations of different token standards on top of Mina. Furthermore the forum could be used as a place to discuss future directions of the protocol from application developers’ point of view.

StandardToken Abstract Design Proposal (Transfer)

Offchain State

  • ledger

    • a ledger with name of the token and map<publicKey, balance>
    {
        "name": "TestToken",
        "14933d7feba1bb10426b11a2a8a2690ebb3b597a2228a6de04c6f87897f1946": 300,
        "293a488389f4df0f79d0991342dc1a4ec356dc207c043a967ac0f3e8e8390e60" : 100,
        "26a06a4a6f64c1e4a75e8b0a450af8417891e663ebbba4a33f62ff4d8c5e1830" : 200,
        commitment: () => Field,    // Poseidon.hash([..])
        ...
    }
    

Onchain State

  • commitment: Field
    • commitment hash for current ledger state
  • contentID: Field
    • serialized data of the content address for the current ledger.
    • In an example of a IPFS, it would be the byte array data of the CID, which could be deserialized to get the label used to point to the data stored in the IPFS.
class TokenContract extends SmartContract {
    ledger: Ledger;
    @state(Field) commitment: State<Field>;
    @state(Field) serializedContentID: State<Field>;
    ...
}

Use Case Description

User A transfers X tokens to user B

  • Breif Description: user A tries to transfer token to user B
  • Basic flow of events
    1. User A connects wallet to the deployed contract
    2. The contract tells user A the CID for the current ledger with the commitment hash
    3. User A checks the IPFS for the current ledger and verifies against the commitment hash for ledger integrity
    4. User A get balance value from ledger and subtracts X from User A and adds X to User B.
    5. User A generates a Signature against the updated ledger’s commitment hash
    6. User A calls the transfer method and requests the contract to update to the new ledger
    7. After the smart contract verifies, it adds the new the ledger to IPFS and updates the commitment hash and the CID.

Methods

transfer

  • Parameters
    • sender: PublicKey
    • recipient: PublicKey
    • amount: UInt64
    • currentLedger: Ledger,
    • newLedger: Ledger,
    • signature: SignatureWithSiger
  • Feature
    • Update the commitment hash and the CID for the ledger to a new state ledger’s commitment.
    • Assuming the following
      • User A called the method to subtract User A’s balance
        • current signature is verified against the commitment of the newLedger
        • sender signed message
      • sender has a balance of at least ‘amount’
      • use currentLedger to replay the ‘transaction’ and check if it equals the newLedger

Implementation

There should be various ways to implement this feature. Various implementations should be written by various teams that have different trade-offs. This forum should be updated to keep track of example implmentations for future references.

4 Likes

Hey there, thanks for the very detailed and thought out idea!

As you mentioned correctly, Mina (at least used to) support token on protocol level, so I am very curious to see if that still is the case (which I believe), and how to deal with working with token.

The only issue I personally see with your proposed way of handling a token standard on Mina is the off-chain ledger. Now, that is by no ways your fault but rather one disadvantage (if you want to consider off-chain data a disadvantage) of Mina. The entire balance relies on the off-chain ledge, rather than an on-chain stored state. While my concern might be too nit picky, I believe that in the case of that that ledger (wherever it might be stored) will be deleted for whatever reason, is a huge single point of failure for token. All token holders will rely on that ledger being as secure as the entire blockchain itself - otherwise their entire funds are at risk - potentially at risk at any given time.

My concerns are by no means meant to discourage your detailed thoughts, but rather a way to start a discussions about “token security”!

Thanks for the post, again! Very appreciated

3 Likes

I don’t understand the issue well enough to comment, but may I ask - can the tokens be implemented similar to the MINA token on the base layer, whose off chain storage model has proven to be safe enough (at least I believe so)? Or do you think the MINA token also has a single point of failure?

3 Likes

Mina is stored on-chain in the form of the ledger, it’s basically a list that maps accounts to their corresponding balances - that is set in stone in the Mina chain (its part of the current state that nodes hold, and it does grow linearly). So what I think is that if tokens continue to be supported on the protocol level, we will likely see a similar way of storing those token - we would simply add another column per token to that ledger (very simply said).

Chains like Ethereum take the approach of token standards, like the ERC-20. All the corresponding token data (and the ledger, account <=> balance map) is stored within the smart contract, on-chain. But I would have to dig deeper into how exactly tokens are handled on Mina, but now that the docs page is gone (probably in preperation for the upcoming snapps testnet/release), it might require some more digging

3 Likes

Thanks for the explanation, it makes sense!

3 Likes

I agree with your feedback and with the issue regarding the “point of failure”. Maybe there could be a way to access the archive nodes from the snarky? If not, aren’t all snapps that integrate offchain approach vulnerable to the same point of failure?

Or would there be other implementations that you may have in mind? I would love to talk about it!

3 Likes

Archives aren’t really considered a part of the network, therefor also not trustless and accessing one of them would end up in a trusted scenario again.

Certainly all off-chain data is somewhat of a point of failure, for all snapps, simply due to the architecture of the protocol and the snapps - however, I think that a ledger which stores token bares a huge responsibility because once the ledger is gone or corrupted, no users will be able to transfer their token - basically considering all funds to be burned/lost forever.

In that case, maybe the ledger could be stored not on one, but rather on a variety of decentralized storages - that would sound better.

I am still waiting how token are dealt with on Mina, sine they are supposed to be native.

2 Likes

I think in this case, perhaps worth asking the team (eg those involved with this issue) to clarify (might be better on discord).
[Edit]: I can see Conner has already referred this post there, so nvm.

2 Likes

I can confirm: we are planning to finish the implementation ‘tokens’ within the protocol early in the new year. I believe SnarkyJS support is also planned soon after, although necessarily not before the protocol-level changes are ready.

Broadly, the proposed implementation supports:

  • storing token accounts in the main ledger;
  • management of balances and other account updates by a ‘token owner’ account, which may be governed by a snapp smart contract;
  • token accounts as ‘full accounts’, so that they can host their own snapps, own another token, etc. in turn.

This has some trade-offs vs storing the token balances and other associated data in a dedicated merkle tree inside the snapp:

  • token accounts in the ledger have to pay the account creation fee to reserve their position in the ledger;
  • token accounts are first-class, and can be used in interaction with any other accounts as part of a snapp transaction, including executing their own smart-contract code;
  • there is no need to handle off-chain state for the token accounts;
  • merkle lookups are handled by the usual transaction logic, instead of within the snapp’s code;
  • token accounts must use the same format as other mina accounts.

Side note: We considered renaming ‘token_id’ to ‘management_id’ during the design process, since a smart contract could use these token accounts to store any per-user state in the ledger, not just tokens. For example, I have heard proposals to use these accounts to store an ‘ELO’ rating for each public key in a chess smart contract, or to use these accounts for user voting information in a distributed voting system.

Personally, I was keen that we have some native support and have the option for snapps to manage this data separately, but we would appreciate any proposals, concerns, or any other feedback on this approach!

6 Likes

Thanks for the clarification! I have a question: it seems like there may be a steep growth of # of accounts on the mainnet once tokens go live, and the 300k account limit might be filled pretty quickly if one token becomes popular. Will the hard fork be upping the limit?

2 Likes

The current limit on mainnet should be ~1,000,000 (2^20), based on the config file. As far as I’m aware, we’re not planning to raise this limit at the hardfork, but I will confirm with the team.

5 Likes

Great Stuff, thanks for sharing

1 Like