Coloured coins work by making use of OP_RETURN.
I'll discuss the Omni Layer, which is currently the primary coloured coin implementation on Bitcoin.
Omni works by encoding additional data within an OP_RETURN.
Let's say I have a BTC address A, and hold 100 USDT in that address. Now, I want to transfer this USDT to B.
I will make a transaction from A to B with the following format:
Any BTC utxo for my address A
A small dust output to B <- This is used to identify the recipient of the coloured coin
An OP_RETURN that encodes the asset ID and amount <- This will identify that I am moving USDT, and 100 units of it
An optional change output that is larger than the dust limit <- any left over from my utxo.
If we look at this sample tx, the OP_RETURN value is
6f6d6e69000000000000001f00000000000003e8. In this,
6f6d6e69 is Hex for
omni, identifying it as an omni layer tx.
1f is the asset ID for USDT,
31 in decimal. Finally,
03e8 is the amount,
Looking at the same tx on a regular explorer shows us the dust and change outputs as well.
Lastly, it is not important for omni layer transactions to spend a utxo from the same output that deposited the coloured coins to the address (i.e., you do not need to spend the dust when spending the USDT in the above tx). Omni uses a secondary accounting system maintained by the omni nodes, which simply tracks OP_RETURNs for balance calculations.
To prevent double spends, Omni will simply credit or debit accounts in the order transactions appear on the Bitcoin chain. If I attempt to transfer the 100 USDT from the first example to C in addition to B, it will get transferred to B or C depending on which tx appears first in the Bitcoin chain. The second tx, although successfully mined as it does not violate and bitcoin rules, will fail at an omni layer, and no coins will be transferred.