CHIP 2021-02 Unforgeable Groups for Bitcoin Cash

Have you considered allowing miners to claim excess tokens? The rule could be that the coinbase outputs can include token outputs. Given that burning tokens normally isn’t allowed, I guess the point is moot.

It would move the tokens to nearer equal status to BCH, and that may be undesirable.

Hi thanks for reading! Note that line will only hold until we introduce the MELT authority later in the document. Before that we’re describing only a minimal token system. In technical description, we’re introducing the whole system bottom-up, building it up from the minimal system which is just the TRANSFER+GENESIS where you can do minting exactly 1 time, and there you can only transfer and freely melt. Then we introduce MINT to let you mint later and transfer ownership of minting capability, and then we introduce MELT and set the balancing rule to == so no more accidental melts. With MELT authority there is clear intent and authority to melt, which makes auditing the “official” supply easy while also preventing accidental burns by users. Finally, the BATON makes the distinction between one-time use authorities, and those that are allowed to be transferred.

This is not-applicable to the scope of the proposal, and as you said it may be undesirable. In an old draft, I did ponder a hypothetical solution where tokens would be really equal, and it would have problems.

While tokens can be plugged into all interfaces where BCH can, they’re not really equal and shouldn’t be – because we need the incentives around BCH not only for the blockchain to work, but for the whole ecosystem to align their incentives and share the same goal, and also for security because the price will not just have an impact for lives of everyone holding BCH, it will also have an impact on increasing our % of the SHA256 hash-power.

Adding token based transaction fees would be of moderate complexity. It is conceptually pretty simple and doesn’t have to many side effects.

Miners could be paid from multiple sources. It could make tx fees/tipping miners less hassle for users. OTOH, it removes the need to obtain BCH to pay tx fees.

Minting tokens to pay miners would be a free rider problem though. All tokens benefit from the security of paying miners with minted tokens but only some tokens pay towards it.

Having a primary currency that all the tokens reference seems reasonable.

Your point that having BCH in every output ensures the incentive to consolidate outputs is a good point. This can be maintained even if tokens can be paid as tx fees.

I agree that keeping things simple is better though.

1 Like

True, it could be as simple as introducing another authority, e.g. a FEE authority which would work exactly like MELT but the excess wouldn’t be destroyed and instead would be claimed by miners. Just to be clear, I have no intention of including such a feature in the current proposal, because assessing the impact could detract the proposal from moving forward.

Glad we agree here!

After a days long discussion with Emil Oldenburg, I accepted his proposal to simplify the authority system to just one UTXO per tokenID, now called the baton output, have fixed minting capacity, and add lockable metadata fields to the baton. I believe that this will give the CHIP wider acceptance, make it more friendly for full stack product builders, address previous concerns about complexity, and make it more defensible and likely to be activated.

More details here: New Group Tokenization Scheme - One Token Standard (WIP)

and it’s already been implemented into the CHIP, which is still WIP and now the Specification needs to be rewritten too.

I would like the ability to provably back tokens with BCH similar to how ETH contracts can have coins deposited into them. There are 4 prerequisites to having this functionality thought and I have made a new issue in on gitlab for each one. Issues 30, 31, 32, and 33.

To summarise here the following 4 features are needed

  1. infinite mint capability
  2. Separate MELT and MINT permissions
  3. Allow for fenced BCH groups
  4. Subgroups

The least trivial of those changes is subgroups. Subgroups are required because a fenced BCH group can not also have a token, the token needs to be a subgroup of the fence to have the token be backed by BCH (or the token can be the main group and the fenced bch group can be the subgroup).

I’ll add back 1. & 2. to the proposal, IMO there isn’t a strong argument NOT to have them, as you say they’re trivial to implement, and having them has its merits.

Best I got against 1. was sum overflow, but isn’t this, like, trivial to guard against? As for 2., it’s rather awkward NOT to have it which I realized while trying to write a spec where 0-flag baton could still melt even when MINT was given up.

3. and 4. require some additional logic circuits on the consensus layer, but the bulk of the cost would be on other layers: block explorers, wallets, etc. would have to deal with more kinds of tokens, check for token balance in 2 places instead of 1 (BCH amount for colored / tokenAmount for others), and so on.

Compared with some pure Script solution the advantage of 3. and 4. would be that we could lock only their authority UTXO in a Script covenant and have it be publicly accessible to apply BCH coloring or token coloring (subgroups) if the right stuff was presented to the TX, so only such operations would have to be P2SH. The tokens themselves would remain P2PKH so could move more easily on the blockchain and be more widely supported by wallets etc.

If anyone wants to weigh in, here are the threads for each feature:
1. infinite MINT, 2. MELT flag, 3. fence/coloredBCH, 4. subgroups/coloredTokens

The other applications need to add support for a new token scheme regardless of which is used.
There is only one kind of token in op_group. the only difference between a group and a subgroup is the group ID of a subgroup will indicate a parent group and applications will have to parse the groupids anyway. At most subgroups are asking the wallets to make an indication of a relationship between two groups and not much else.
Fenced BCH values are in the same location as regular BCH transaction values.

Assuming parsing group tokens is already implemented, the additional burden of checking for fenced bch and subgroups consists of a couple more if statements.

1 Like

@Griffith I worked out an example of how you could create backed tokens even without the “fence” feature. It is possible as a consequence of locking the authority (aka baton) to exactly 1 UTXO in the “base” proposal. Maybe an easy SmartBCH bridge could be created this way, too! Including hash of the first prevout output in the tokenID preimage could allow a token authority to prove it was created by another token’s authority.

Token Group Script Covenant

The below example requires CHIP-2021-02: Native Introspection Opcodes.

It also assumes that introspection opcodes for reading Group annotation will be added:

  • OP_TOKENID,
  • OP_TOKENQTY,
  • OP_TOKENFLAGS,
  • OP_TOKENLEFTTOMINT,
  • OP_TOKENMETA,
    all with variations for accessing different TX local outputs.

Recall that tokenID is generated by hashing a preimage consisting of parts of that token’s genesis transaction:

  1. Hash of first input’s prevout output;
  2. First input’s prevout TXID;
  3. First input’s prevout output index;
  4. Output index of the genesis output being generated.
  5. The genesis output being generated with tokenID left out;

Recall that consensus also enforces that:

  • The genesis output must be of token authority type;
  • When an authority output is spent, it can create any number of ordinary token outputs but only one authority output.

Because of consensus rules placed on token genesis and token authorities, it takes little to prove that a pubKeyScript placed on a token authority is the same as the one set at genesis and that it couldn’t have been tampered with.
The pubKeyScript only has to prove that it’s been tied to the token authority output since genesis, and such proof will be of fixed size.

Redeem script:
OP_DUP OP_DUP
OP_OUTPUTBYTECODE OP_INPUTINDEX OP_UTXOBYTECODE OP_EQUAL // I must be carried forward…
OP_SWAP
OP_OUTPUTTOKENQTY OP_NOT OP_AND // … to a token authority output…
OP_SWAP
OP_OUTPUTTOKENID OP_TOKENID OP_EQUAL OP_AND// … with the same tokenID as me.
OP_SWAP
OP_INPUTINDEX OP_UTXOBYTECODE OP_CAT OP_HASH256 // Also, my pubKeyScript…
OP_TOKENID OP_EQUAL OP_AND // … must be the same as set on my token’s genesis.
OP_SWAP<...>OP_AND // Any other conditions.

Signature:
<...><genDataHeader><outputIndex>

The genDataHeader part of the signature is the tokenID preimage with genesis pubKeyScript left out, and the outputIndex refers to the “change” output of the token authority being spent.

The size of the above covenant boilerplate code is given below:

6   Signature push opcodes (3+1+1+1)
1   OP_0
25  Redeem script boilerplate code
63  Covenant proof part of signature, assuming NULL metadata.
-------------------------------------------------------------
95

Because token authorities can be created with or without capability to mint tokens, such covenanted output could be used as:

  • As NFT with a BCH balance entirely controlled by the covenant;
  • As a token authority with variable BCH balance.

When used as a NFT the covenant could serve as BCH vault, requiring arbitrary proofs to add or remove BCH.

When used with token minting and melting capability, the covenant could require BCH to be paid in/out of the covenant which would make tokens backed by BCH possible where such tokens would remain free P2PKH citizens.

Covenanted Ordinary Token Outputs

If the covenant is placed at token’s genesis then it is possible to envelop ordinary token outputs in the covenant by extending the code above to require indexes of a number of ordinary token outputs.

The covenant could then verify that it’s being passed on to them and tally up the balances in order to verify that outputs haven’t been omitted.

This would allow fanning out of covenanted outputs.

The above would work only with finite mint tokens.

For infinite mint the covenant would have to enforce that the total number of outputs in a transaction matches the number of provided indexes.

Supporting covenanted outputs merging would be achieved the same way, by requiring indexes of a number of inputs to be included in the balance calculation.

For example, this could be used to implement “colored” BCH where the covenant could enforce tokenQty == satoshiAmount.

It could also allow any owner to burn the color and reclaim the BCH by coding the covenant so that it allows being spent to a token OP_RETURN under some conditions.

MAJOR UPDATE - 4.1 Unforgeable Groups for Bitcoin Cash

This was prompted by some discussions I had with @im_uname and after realizing that the groupID can be used as a cryptographic “commitment” primitive required to construct unforgeable Script covenants. These would then let us implement all advanced supply and metadata management features from within Script, while letting token amounts be free P2PKH citizens, giving us the best of both worlds, consensus and Script.

Also, pure commitment mode is supported, which would enable fixed-size inductive proof covenant contracts that would work the same as PMv3 “detached proof” examples but reconstructing the groupID preimage instead of TXID preimage as proof.

4.1 Tweak GENESIS and add NFT group flag

  • Add a NFT group flag so we can have NFTs that carry some state
  • Tweak GENESIS to compress each input in the preimage
  • Add PMv3 GENESIS and SIGHASH sections
  • Wording

4.0 Unforgeable Groups

  • Simplified the output format and consensus layer
  • Generalized output groups as “carried witness”, having only the GENESIS rule enforced
  • Amount field is now optional and indicated using the LSB of groupID so the whole group must have or not have it
  • Native token groups and Satoshi token groups (aka “holds BCH”) are then a more restricted variant of a generalized group, having token logic enforced over respective amount fields, and NFT logic enforced over amountless token groups.
  • 0-amount indicates “singulary” i.e. an infinite source or an infinite sink which allows token amount creation and destruction
  • Any advanced features, such as metadata updating, are to be implemented using unforgeable Script covenants, as demonstrated in the examples section
  • Reworked CHIP sections
2 Likes

MAJOR UPDATE - 5.0

After some more iterations, and a brainstorming session on how to marry with PMv3 features (detached signatures and detached proofs), the proposal was made much less complex while still preserving the possibility to implement desired behaviors by using Script covenant placed on token baton.

In short, the proposal now only introduces:

  • A simple genesis setup: 1st prevout txid and vout index + genesis output index + genesis output itself
  • Only the “native token” group type, which enforces a “super-contract” over grouped outputs by using native consensus code to enforce token balances across a TX, and by induction the accounting equation is then guaranteed for the whole group.
  • 4 unary introspection opcodes to access groupID and groupAmount that will allow interaction with covenants

Most sections are now written, including specification (3 pages), security considerations and rather elaborate costs analysis.

MAJOR UPDATE - 6.0

This was prompted by exchanging notes with @bitjson and revisiting @tom 's idea of declaring the genesis, and it enables group tokens to interact so much better with Script!

Changes:

  • Whole new approach to group genesis: instead of inferring it from the TX, it will be explicitly declared as an input prefix that can use the same byte because it will be exclusive to input context.
  • One more introspection opcode to access the genesis input’s generated groupID preimage.
  • Change group amount format from VarInt to fixed width uint.

Instead of inferring genesis from orphan outputs and allowing orphans only if the groupID matches the hash, we require the genesis to be declared on the inputs, conceptually similar to a coinbase input. A new introspection opcode is added to access the input’s genesis preimage.
Advantages:

  • enables flexibility in deciding which input will be a genesis input
  • enables flexibility in deciding which input’s prevout will be committed to for later use in smart contracts
  • enables better interaction with contracts requiring or verifying the genesis operation
  • removes malleability from group genesis (outputs are signed, and orphans disallowed)
  • more consistent with Bitcoin design (coinbase input)
  • enables versioning the genesis preimage construction without having to spend scarce group type bits which will be reserved for potential “super-contract” optimizations in the future
  • opens the path to a future upgrade where user-defined parts of the genesis TX could be appended to the preimage
  • enables a dedicated genesis nonce field which simplifies grinding the group type, making the group type encoding time-space trade-off more convenient
  • opens the path to synergies with detached proofs and signatures, where hash of the real unlocking script could be appended to the groupID preimage

Example - “Jason’s Challenge” Contract - Link to Bitauth IDE Template

The user pays 10,000 satoshis to get a token. They can transfer that token to use 2-of-3, then back to single sig, then deposit the token and get back their 10,000 satoshis from the parent covenant.

There are 2 contracts:

  1. NFT, placed on the prevout which will be spent as group genesis input and generate the NFT. The prevout script will require that 10,000 sats are paid into a fixed P2SH address (depository corporation covenant). Only the 1st spend is from a P2SH, the genesis input spend: the NFT can then be moved to an ordinary P2PKH and still be able to reclaim the 10,000 by burning itself in the same TX as any covenant UTXO.

  2. The depository corporation covenant is an anyone-can-spend kind of thing, but it requires any NFT that can satisfy the proof of payment at genesis to be burned to an OP_RETURN. The NFT’s genesis script is verified to match the template hardcoded in the P2SH covenant.

Not only does this create a BCH-backed NFT, it also lets NFT holders reclaim the BCH from any covenant UTXO :slight_smile: I suspect there’s a way to make some kind of BCH mixer based on this.

UPDATE - 6.1 Fungible Tokens

Changes:

  • Acknowledge existence of “CHIP-2022-02-CashTokens: Token Primitives for Bitcoin Cash” and start working towards merging the two proposals
  • Extract groupType to its own field to enable signing group genesis from the redeem Script without the problem of malleating the nonce
  • Align groupType with CT2.0
  • Remove singularity amount overload, entire fungible token supply of the group must be minted at genesis
  • Modify genesis - prevout hash now optional

With this and the exception of genesis setup (which I argue should be implemented by CT2.0), Group is now a subset of CashTokens, and I’ll be working my way to implementing CT2.0’s way of doing NFTs which I feel is the breakthrough that eluded me.

Group v6.0 and CT2.0 were released around the same time and I feel both made some key breakthroughs:

  1. Genesis naturally belongs on inputs, and as such fits perfectly with other Script VM primitives (Group v6.0) and makes certain covenant constructions rather easy
  2. NFT is not a special type of FT with supply=1 and they must be independent (CT2.0)
  3. Allowing both the FT and NFT to be carried by the same output elegantly solves the problem of “baton”, where it’s nothing but a labelled FT amount. (CT2.0)

My goal with Group now is to use it as a sort of “peer review” document, where it could ultimately be just for information, while CT2.0 could carry this technology through the finish line.

1 Like