CHIP-2021-09 Group Tokenization Marking

There’s been some interest in some features dropped from CHIP 2021-02 Group Tokenization for Bitcoin Cash so I thought to extract them into a separate CHIP for better focus.

CHIP-2021-09 Group Tokenization Marking

Those features were part of Andrew Stone’s original proposal but here I modified the subgroup feature with rationale given below.

I will first copy Griffith’s request for features:

3. and 4. could be a same feature if we deviate from Andrew’s original design: a feature to mark (apply coloring) to units of the underlying asset, either some BCH or some tokens.

I have drafted a separate CHIP in order to capture this feature. This way there’s no need for a Subgroup authority flag with the trade-off that you then can’t use arbitrary bytes for the subgroupID, it is to be generated similarly to how new tokenID is generated.

The token is the fence, it’s some coloredBCH with the supply equal to locked BCH, and 1 unit of the token redeemable for 1 unit of BCH. I could be misunderstanding, but even in Andrew’s proposal there was never support for subdivision of BCH ‘backed’ tokens as I think you imagine them, or for tokens backed by tokens (fenced or not):

  • with fencing, the tokenAmount is disabled and satoshi amount used as the token amount, so no subdivision, but ‘backed’ by BCH
  • with subgroups, they only inherit the global group settings and ID, but supply is minted independently as another token so not really backed by anything
1 Like

The token is the fence, it’s some coloredBCH with the supply equal to locked BCH

This breaks my intended usecase as a fixed 1:1 ratio is not desirable.

There is no constraint in OP_GROUP on the value equivalence ratio for how much fenced BCH a token can represent. Yes, Andrew uses a 1:1 ratio in his prediction markets exmaple in the op_group document but it is only as an example. The only rules are that the inputs and outputs must balance and that fenced BCH does not use separate tokens quantities because it is not a token. For my intended usecase the BCH value of a token is able to change based on data outside of the blockchain itself. For example, a statement by trusted oracles via OP_DATASIGVERIFY could provide the data used to determine the tokens BCH value.

1 Like

He had explicitly prohibited token quantity:

If the GroupId HOLDS_BCH flag is set, Quantity MUST be 0. Copy the BCH amount field in every non-authority input and output (grouped) UTXO into the respective Quantity field (REQ3.2.3.1). (This enables grouped BCH, rather than grouped tokens)

and:

Subgroups do not have their own flags; they have the same flags at the same location as their parent group.

Therefore even subgroups of fenced BCH would be 1:1 due to the rule applying to the parent group so we’re really discussing something new here, which is fine by me, let’s continue. :slight_smile:

Say we enable the quantity field. Doing that, the authority could do both:

  • lock or free BCH under that tokenID
  • freely adjust the quantity of tokens with that tokenID

independently of each other, so how would you enforce the multiplier when both coloredBCH and token supplies could be freely adjusted by whomever holds the authority at their discretion?

Also, any user could freely adjust the amounts across the UTXOs he owns: put all the coloredBCH into 1 UTXO with 1 unit of the token, and all token units to an UTXO with dust amount of coloredBCH. He can’t free or lock new BCH or mint/melt tokens so he could produce any number of outputs with any multiplier, quantity limited by what he owns, and having to hold whatever the remainder in one last output.

How to solve this without introducing complexity to the consensus layer? Can we solve it on another layer? Could we do it with Group introspection and PMv3 detached witness?

Yes i think we are talking about two different things. The quantity numbers in the fenced group BCH are a 1:1 ratio with BCH because it is still BCH. The group is only used to bind the outputs in that group to a covenant applied to the entire group.
I was saying that the tokens in the parent group have a varying BCH converted value.

Putting both the fenced BCH and tokens in the same group complicates things. The most immediate complication is movement. The tokens should be able to move freely to anyone without also sending fenced BCH. if they are combined, you then have to make sure you have enough fenced BCH being sent so that the receiver can move their tokens again or they get into a situation where they need to buy more fenced bch and tokens to move their initial purchased tokens. For my usecase it is also more desirable if the fenced BCH mostly stays with the holder of the authority baton. moving the fenced BCH around to people gets awkward.

This also increases complexity a bit with validation. Instead of the fenced BCH being a single check to make sure token quantity is 0, you have to balance it with token movement. You would have to make an additional validation path for tokens that are also fenced vs tokens that are not fenced.

I think the code and behaviour is a lot simpler if the fenced bch and tokens are not in the same group.

Agreed, so how would that work? Two groups with their baton/authority outputs locked in entangled Script covenants?

So all the BCH could just stay inside the authority/baton output? Then why would we need the fence feature for this? Because even if it is fenced, when the BCH is inside the authority/baton output it is as if it’s not fenced, it can move in&out unless so limited by the Script covenant placed on the baton.

Isn’t an ordinary group enough for this? The baton can hold all the ‘backing’ BCH and control token supply at the same time. Script covenant placed on it should ensure that BCH can leave the authority/baton output only if some token amounts are destroyed. If the baton is of finite mint then isn’t it enough to be able to introspect the baton “change” output in order to enforce this? With infinite mint baton you’d also need to introspect all grouped outputs so the contract can verify the token balance.

Depends on the covenant solution I can use.

With group covenants I can use the authority baton to set a script that will apply to the entire groups and either destroy the rescript permission so that covenant can never change, or keep it to change it later if needed. For clarity, I do not need an authority baton for the subgroup (creating one is optional and this helps simplify the covenant script). The parent group authority can execute permissions on a subgroup.

I have not explored a covenant solution with PMv3 yet but if the capabilities are the same or similar, some solution equivalent to the one above would do.

Why is the fenced BCH not allowed to move at all now? It still needs movement. My only issue before was that the movement of the fenced BCH was 1:1 with the tokens.

Talking with Andrew the other day had me realize that one use of subgroup was to easily evolve token state. Parent authority redeems the old token and issues the new one. Proof of ancestry is in the first 32 bytes of the ID.

If we update the spec to include the full prevout of the genesis TX in the genData that gets hashed for newly created tokenID, then such tokenID (still only 32 bytes) itself becomes a compressed proof of ancestry with the caveat that anyone wanting to prove ancestry down the line must present the genData to whatever contract requiring such proof.

Re. group covenant, don’t they make moving such tokens awkward? When the Script is locked so that it always must be equal across the TX, with some freedom to choose among contracts one owns, it means we can’t have P2PKH outputs because covenant would lock them so that you could only send it back to the same address. With Group covenant you can’t have non-covenanted and covenanted outputs share the same tokenID. Group templates were intended to work around this limitation by providing slots that could be changed without breaking the covenant. With that we could have a typical covenant contract that would allow changing the address, some pay-to-address-template.

It allows you to carry a proof of ancestry compressed into the detached witness hash, allowing descendant transactions to “introspect” entire so witnessed history. If we had a backed token, the witness should carry proof that whatever ratio calculation was respected for all minting and melting in the past.

With a backed token, you need to have 2 pools: the backing asset (1:1 fencedBCH), and the backed token (normal group token, supply somehow tied to the supply of fencedBCH), right? Who needs to hold the backing asset i.e. the fencedBCH? If it’s only supposed to sit in issuer’s vault, then for what would he need to move fencedBCH around inside the vault? He can, but doesn’t need to. Because, to free them from the fence/vault you need to put them in the same TX with the fencedBCH authority which opens the vault. So isn’t it more practical to just keep all the fencedBCH “inside” the authority and have the whole BCH pool exist in a single such UTXO?

I think ‘fence’ feature enables one function that could be the selling point: it prohibits people from paying into this super-contract. With TX introspection support, a Script contract could be written that locks BCH and pays them out only if some token X was burned in the TX but a Script can never prohibit anyone to lock his BCH with the exact same bytecode.

PS even the current proposal supports a special case of locking some BCH, a single UTXO “fence”: the BCH amount stored in the authority/baton UTXO. Nobody can pay BCH into it or out of it without spending the previous instance of the baton. So I think even the “base” enables backed tokens (depending on introspection support). The baton becomes the backing asset vault, and the tokens it fans out are the backed tokens.

I suppose in my scenario this is true, you could have the fenced BCH stay with the issuer.

In general though fenced BCH should be able to move. Why add that arbitrary restriction?

I am a bit surprised this is a point of contention. Adding fenced BCH to the base proposal using the original OP_GROUP implementation is only an additional enum field and 2 if statements. A grand total of 10 lines of code including brackets.

Am I really getting pushback on wanting a feature that is 10 lines of code when there is no security issue?

There’s no restriction. Fence feature allows movement within the fence, I’m not talking about disabling it. I’m talking about your particular use of it, where there seems no need for it to be moved because the key operation you’d need is to bring BCH in and out of the fence and don’t care what happens inside the fence.

What I meant is that if there’s no need for fenced BCH to be moved for your particular use of it, then for your particular use you don’t need the fenced feature at all because ordinary token baton (from the “base”, no-fence proposal) can serve as a BCH vault for the backing.

I’ve been asked to make ironman arguments about the “base” proposal and the features that are left in are those which can be defended with strong arguments. If we were to add “fence” back in, how would we defend having it if more people started asking the “why have it?”

As you say, it’s cheap to add and doesn’t introduce some new risk, so the “con” side is not that heavy. I know that, I was on the other side - defending the feature :slight_smile: And if I have to do it again I need more then I had last time so I’m really looking for more “pro” arguments here, and you had a good use-case which could be it. But then we see that you don’t really need the “fence” feature for that, so what now? Is there enough in the “pro” basket to make the case for it?

Even without “fence” any NFT is a “fence” of 1 UTXO in that others can’t pay into it but the owner can take out BCH.

So here’s another case for the fence: to make loaded NFTs. For token NFTs there are only 2 UTXOs in existence, the baton and the token. The baton can fill the token with BCH, and the NFT holder could move it around but never take out the BCH without issuer’s (baton holder) permission. Or, issuer could burn the baton to imbue whatever art with permanent amount of BCH.