Skip to content

Token migration issues

dimxy edited this page Apr 5, 2019 · 8 revisions

Notes about token migration between Komodo notarized asset chains

Extending import coin features for the migration of tokens

There already exists a framework for coin migration between asset chains. The workflow of coin migration is like this:

  • On the source asset chain user calls migrate_createburntransaction rpc and sends the burn transaction by sendrawtransaction call. This transaction burns some amount of coins by sending them to the OP_RETURN vout, making them unspendable and this amount will be restored in the destination chain providing the balance of burned and imported value.
  • Notaries periodically calculate MoM value (merkle root of merkle roots) for several blocks and send a notary tx to the KMD chain. The merkle tree for the block with the burn tx also once gets into one of the such MoM fingerprints.
  • Also, on the KMD chain notaries periodically calculate MoMoM (merkle root of MoM) value for a bunch of recent MoMs and send it along with MoMs back to asset chains.
  • On the source chain the user runs the rpc migrate_createimportransaction and passes to it the created burn transaction. The call creates a new import tx and adds to it a proof of the burn tx existence. The proof contains the subset of merkle tree nodes, including the burn tx as a leaf, which is needed for future validation
  • On the main Komodo (KMD) chain the user calls migrate_completeimpottransaction with the created import tx in hex as a parameter. On this stage the proof object inside the import transaction is additionally extended with MoMs values. This will allow to calculate the MoMoM value from this merkle tree subset and by that verify the burn transaction proof on the destination chain.
  • Finally the user sends this import transaction to the destination chain where it will be validated and added to a block.

That's okay for coins migration but for tokens this is more complicated. A token tx is actually a tx with cryptocondition vouts with token eval code and some amount, plus a specially formatted OP_RETURN vout where the token's id is stored.

A tokenid is actually a txid of the token base transaction which has basic token parameters (name and issuer pubkey).

So a token is actually token transactions with unspent vouts plus a tokenbase tx.

Note: there exist both fungible and non-fungible kinds of tokens, migration is supported for both of them. A non-fungible token is actually a non-divisible token with value always equal to 1. Fungible token could have any value. For fungible token it could be an issue with token splitting with our token migration method if token value was migrated several times into one destination chain - see later on this page considerations about this issue.

For importing tokens we use the same features that is used for coins: an import tx, which is a special transaction that is processed and validated in a special manner on Komodo daemon core level. For an import tx eval::Importcoin() validation function is called where some consensus code for validating imported tokens is added. An import tx contains the burn tx and its proof object which guarantees the burn tx really exists on the source chain.

In case of token migration, an import tx becomes a new token in the destination chain linked to the source token. A token import tx is a tokenbase tx with a token opreturn vout with the name, description and originator pubkey which are exactly the same in the source tokenbase tx (from the source chain). Also token import tx contains an additional token import data with objects needed for validating the link to the source token (burn tx and proof object).

Token migration issues

Obviously the migration of tokens is more complex than the migration of coins: we need not only to prove that the burn tx exists in the source chain but also prove that it refers to the real tokenbase transaction and verify the token base parameters.

So there are some additional token migration issues and how they are solved:

  • for imported token we want to ensure that it links to the source token. For this tokeninfo rpc now outputs the burn tx tokenid and source chain name. So a user would know that this is an imported token and that it is linked to some token in the source chain. The tombstone feature ensures that there may be only one burn transaction in the destination chain that burns this source token, and if we allow to burn only non-fungible non-divisible token it provides one-to-one relation between the source and imported token.

  • for an imported token we want to ensure that its token name, description and originator pubkey really match to the source token same params. This is needed because a token user/buyer should trust these parameters in the imported token too. For this, we put the source token creation tx marshalled into the import tx opreturn data and validate (compare) those parameters in the import tx and the source tx. We also check that the burn tx tokenid matches the hash of the source token base tx and this would mean that this token base tx is really the token creation tx for the burn tx.

  • On a destination chain we want to ensure that a burn tx is a real token tx in the source chain, that is, for it a token creation tx exist and its cc value is balanced (that is, spent cc value equals to output cc value for the same eval code). For this we need to know that a burn tx has passed validation by the token cc contract. This would ensure a burn tx is a correct token tx. In turn, a tx gets into cc contract validation code if it has this cc contract eval code in its vins. So in import tx validation code we need just to ensure that a token burn tx has cc vins with eval code EVAL_TOKENS.

  • We also should pay attention to normal vouts in token import tx. Someone could try to cheat the system adding some normal vouts that were not burned. So there is also a validation added that import tx normal vout total matches to burned normal amount (minus extra txfee for miners).

  • There is a validation rule that total burned cc token value in a burn tx equals to the import tx cc output value to prevent token leakage or injection issue while importing token value.

  • We validate that total burned value (both cc and normal) in a burn tx should be greater than total output value in the import tx because burn tx value is treated as import tx input value in the destination chain, and the difference goes to miners and is checked while the propagation of the import tx.

  • There is an issue with token splitting if a fungible token was migrated several times into one destination chain. From that there could be several new tokens created in the destination chain. Such tokens, with common source, should be considered as a single token.


Above described some extra validations (applied together with the basic validations of imported coins) to ensure validity of migrated tokens.

Clone this wiki locally