stampchain-io / btc_stamps

Bitcoin Stamps Indexer
https://stampchain.io
GNU Affero General Public License v3.0
9 stars 2 forks source link

SRC20 Token Deployment Front-Running Prevention #305

Open btcopenstamp opened 2 weeks ago

btcopenstamp commented 2 weeks ago

Recently, many users have reported to OpenStamp that SRC20 Tokens are being front-run deployed and minted, especially for projects that wish to mint all tokens at once. To address the following two issues:

  1. Prevent SRC20 Token deploy transactions from being front-run by high fee rate transactions once they are sent to the mempool.
  2. Allow to mint all tokens at once and prevent other users from front-running the minting.

After a brief discussion with Kevin, OpenStamp has proposed the following preliminary ideas to address the above issues.

Adopt a two-phase process, where the deployer needs to send a commit transaction and a reveal transaction.

The JSON data structure of the commit transaction is as follows:

{
  "p": "src-20",
  "op": "deploy",
  "type": "commit",
  "hash": "23f2cc01d34c57eea8aa2c11d1e50ec72647ee52e4f33dea15dab915c7bf33f2" // SHA-256(commitment address + tick in the reveal transaction) both parameters are case sensitive
}

The commitment address is the first input address of the commit transaction. The above commit transaction requires three Bare Multi-Sig Outputs.

The JSON data structure of the reveal transaction is as follows:

{
  "p": "src-20",
  "op": "deploy",
  "type": "reveal",
  "tick": "STAMP",
  "max": "100000",
  "lim": "100",
  "commit": "23f2cc01d34c57eea8aa2c11d1e50ec72647ee52e4f33dea15dab915c7bf33f2", // [optional] default is the hash of the first input UTXO of the reveal transaction
  "mint": "1", // [optional] indicates whether the reveal transaction needs to mint the number of tokens specified by the lim field to the first output address. The default is 0 (not needed), 1 (needed)
  "dec": "18" // [optional]
}

A reveal transaction is considered valid if it meets the following conditions:

  1. The commit transaction has at least 6 block confirmations (including the block where the reveal transaction is included).
  2. The commitment calculated from the reveal transaction matches the hash in the commit transaction.
  3. The first output of reveal transaction is not OP_RETURN

The commitment for the reveal transaction is calculated as follows: SHA-256(first input address of reveal transaction + tick)

Additionally, the first output of the reveal transaction will be the deployer address.

Below is the TypeScript method to calculate the commitment hash:

import * as CryptoJS from 'crypto-js';

function calculateSha256(bitcoinAddress: string, tokenName: string): string {
    const data = bitcoinAddress + tokenName;

    const hash = CryptoJS.SHA256(data);

    return hash.toString(CryptoJS.enc.Hex);
}

const bitcoinAddress = '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa';
const tokenName = 'TEST';

const hashResult = calculateSha256(bitcoinAddress, tokenName);
console.log('SHA-256 Hash:', hashResult); 
//SHA-256 Hash: c8efbc27bf09fd9715657bf6143b3a166af3871855cfc86fa5620942294ed944
reinamora137 commented 2 weeks ago

A good idea. However if this is mostly for those wanting to mint 100% of the tokens deployed then the ‘premine’ alternative is probably better suited. Not opposed to doing both options if we are putting a few upgrades into the next release however.

btcopenstamp commented 2 weeks ago

Yeah. I believe that most of the situation by now is minting 100% tokens at the deployment.

The commit and reveal mechanism is to prevent front-running the token name and others parameters, like supply etc.

reinamora137 commented 2 weeks ago

How will the indexer know the token name at time of commitment to ‘reserve’ that name for the commiter considering it’s obscured in the sha hash? I guess there would still be a more minimal risk there if someone else happened to use the tick name before the reveal transaction posted. Seems a little overly complex when a deploy in the current method could just use a high fee if it was a high value token name?

reinamora137 commented 2 weeks ago

I guess that would be resolved by making all deploys require this technique. I was initially thinking it could be optional.

btcopenstamp commented 2 weeks ago

How will the indexer know the token name at time of commitment to ‘reserve’ that name for the commiter considering it’s obscured in the sha hash? I guess there would still be a more minimal risk there if someone else happened to use the tick name before the reveal transaction posted. Seems a little overly complex when a deploy in the current method could just use a high fee if it was a high value token name?

This method is to prevent the token name from being exposed in the mempool and front-run when you want to register a token. ENS and RUNES both use similar methods. It is not intended to solve the issue of multiple users wanting to mint the same token name simultaneously. The system is designed to operate on a first-come, first-served basis. This issue is allowed and there is no need to avoid it, and to some extent, it cannot be avoided.

I guess I don't see how the issue is solved if this is optional deploy technique. someone could still see the reveal in the mempool and quickly deploy the same token in the old technique. There is nothing on the commit where the indexer can reserve the nam. The downside is the two transactions for a deploy.

btcopenstamp commented 2 weeks ago

I guess that would be resolved by making all deploys require this technique. I was initially thinking it could be optional.

I think optional is fine considering the simplicity of current way. Anyway, just propose an idea about how we can avoid the Front-Running issue.

btcopenstamp commented 2 weeks ago

Issue2(Allow to mint all tokens at once and prevent other users from front-running the minting. ) can be resolved on https://github.com/stampchain-io/btc_stamps/issues/303