This was an early demo of the ideas behind the CashTokens CHIP.
For an introduction to the latest iteration of CashTokens, see:
CashTokens (v2): Token Primitives for Bitcoin Cash →
CashToken (v0) Corporations
Read the blog post: CashTokens: Contract-Validated Tokens for Bitcoin Cash.
Review the authentication template in Bitauth IDE:
If you have questions, feedback, or you're interested in contributing to future CashTokens or TxInt Opcodes specifications, please join CashToken Devs on Telegram or message me on Twitter.
Below are some notes which may make it into a future CashTokens and/or TxInt specification.
Current draft implementation of the TxInt upgrade ➔
The current target date for a TxInt opcode upgrade is May 2022. Some TxInt opcodes could be enabled earlier, but many should only be enabled with larger integer support (see below).
520-Byte Stack Item Size Limit
While CashToken can work within the 520-byte stack item size limit, because CashToken inductive proofs require inspecting the parent and grandparent transactions' contents, stack items can easily reach 520 bytes. Flexibility in signing schemes also increases the amount of bytecode required to validate each allowed configuration, contributing to overhead which must fit within the 520 bytes for P2SH outputs. For these reasons, the token covenant in this implementation is limited to multisig security schemes with a maximum of 3 signers (m-of-n where m <= 3, n <= 3). Increasing the stack item size limit to 1000 bytes would provide space for token covenants which use additional locktime-based security features or the largest allowed multisig schemes (up to 20 keys). A stack item size limit of 2,000 to 5,000 bytes would likely provide space for validation of transactions with multiple complex covenant inputs.
OP_OUTPOINTTXHASH operation pushes the outpoint transaction hash in big-endian byte order. While the serialized transaction format itself specifies this value in each input in little-endian order (reversing the double-sha256 hash of the parent transaction serializations), most VM bytecode use-cases will require the value in big-endian byte order (non-reversed). As an added benefit, big-endian byte order is also used by most external systems (explorers, indexers, etc.).
OP_UTXOBYTECODE operation pushes the bytecode currently being evaluated to the stack. For standard scripts, this is the locking bytecode of the Unspent Transaction Output (UTXO) spent by the input. For P2SH scripts, the UTXO's redeem script is pushed (rather than
OP_HASH160 <redeem_script_hash> OP_EQUAL). This behavior matches the existing behavior of the current VM during P2SH evaluation – once the P2SH pattern is matched, the remaining stack is copied, and the VM begins evaluation again with the new array of instructions.
OP_UTXOBYTECODE provides access to the serialization of this instruction list (in derivatives of the Satoshi implementation, the
script parameter provided to
Risk: Transaction Competition
With CashTokens, it's possible to create covenants for which multiple entities compete to create the next covenant transaction. These entities may be willing to pay higher-than-normal fees to have their version of the covenants next state mined. A non-negligible volume of these transactions may incentivize miners to develop backchannel Replace-By-Fee (RBF) infrastructure and weakening zero-confirmation reliability.
For example, when a second user attempts to outbid a previously broadcast covenant transaction, nodes which heard the first transaction may refuse to broadcast the second. If those nodes broadcast some form of Double-Spend Proof (DSP) for the new transaction, miners may be incentivized to request the "warned-against" double spend (over other channels) to maximize fees.
To avoid incentivizing the creation of double-spend backchannels, DSP strategies should account for the possibility of significant markets for fee-replacement. (Even without CashTokens, this is already true for other types of anyone-can-spend locking scripts.) Well-designed CashToken covenants should also avoid creating such scenarios, since "bidding wars" may also degrade the user experience of covenants.
Area for Research: Heterogeneous Tokens
It's possible to differentiate token types within a single CashToken corporation contract by using the tokens' satoshi values. For example, a corporation covenant can be designed to issue tokens with a base value above the current dust limit (546 satoshis) where each additional satoshi represents another unit of the token. E.g. for a base of 1000 satoshis, a 1001 satoshi CashToken is worth 1 UNIT (1001-1000), but a 2000 satoshi CashToken is worth 1000 UNITs (2000-1000).
Because the CashToken covenant places strict limitations on transfers, higher-level covenants can rely on CashTokens to only change their satoshi values in allowed ways from transfer-to-transfer. This same strategy can be used to differentiate other types of tokens like classes of stock (preferred, common, class B, etc.) or various privilege levels in a CashToken sidechain.
Complication: Big Integer Values
Because Script Numbers are currently limited to 4 bytes for mathematical operations, numbers pushed to the stack by
OP_OUTPUTVALUE are practically limited to positive int32 numbers. This limits the total operational value to 2,147,483,647 satoshis, or about 21 BCH. While this proposal doesn't yet recommend a solution for working with larger numbers in the VM, it would be valuable to adopt a big integer solution before or at the same time as the TxInt opcodes.
Complication: Fractional Satoshis
It should also be noted that future upgrades which enable fractional satoshi will complicate
OP_OUTPUTVALUE. It may be valuable to plan upgrade strategies which allow these opcodes to be used with the higher specificity values.
OP_OUTPUTVALUE could be modified to accept the index
-1 as an indicator that a higher specificity operation should be used (future subdivisions could be specified with
-3, etc). To allow for future upgrades, it may be valuable to require that
OP_UTXOVALUE consumes the value
0 from the stack to indicate the unit "satoshis".
(Update 2020-12-16: I'm also considering a design where each
OP_UTXO* opcode consumes a number to select a particular input such that
OP_INPUTINDEX OP_UTXOVALUE would do what
OP_UTXOVALUE does in the initial draft implementation.)
Contracts inspecting transactions are made simpler and safer with operations to convert between Script Numbers and Bitcoin VarInts. Without safe means of reading/writing VarInts, contracts must be carefully specified to either manually convert between formats or limit allowable input/output counts in proofs. Additionally, ease of use of VarInts in contracts might help to minimize wasted space caused by fixed-width contract values (e.g. nonces, indexes, payment amounts, rates, etc.).
Area for Research: OP_VARINT2NUM
Currently, only an implementation for OP_NUM2VARINT is proposed. This is sufficient for many types of covenants, but other covenants may be made possible or more efficient with an implementation of the reverse operation.
Area for Research: Unify Integers
Many covenant contracts utilizing transaction introspection will need to convert between Script Numbers (a.k.a.
CScriptNum, usually inclusive range from -2^31 + 1 to 2^31 - 1), transaction output satoshi values (little-endian, unsigned 64-bit integers), and variable-length integers (positive integers from 0 to 2^64−1, used in transaction and signing serializations). Beyond these existing formats, some strategy is needed to perform mathematical operations on output satoshi values (and on fractional satoshi values, which may no longer fit inside a uint64).
It may be valuable to solve all these number encoding problems at one time (perhaps in a v3 transaction format). Some goals and requirements for a variable-length integer solution:
- A single, variable-length, unsigned integer format for transaction serializations – to be used by the version, input/output count, input indexes, bytecode length, and satoshi value fields. (Version 1 and 2 transactions tend to waste bytes in fixed-width version and satoshi value integer fields, while also preventing these fields from interoperating with the VM's Script Number format in contracts. A unified integer type could solve both issues.)
- Math support for variable-length integers – all math operations currently operate on Script Numbers, a 32-bit signed integer format used by the VM. It must be possible for math operations to either operate on the variable-length integer type or convert between Script Numbers and the variable-length integer type. This is particularly important for math operations involving satoshi values larger than the current limit of 2,147,483,647 satoshis (about 21 BCH).
- A clear upgrade path to "fractional satoshis" – increasing the precision of value fields should be possible without breaking changes to VM operations.
Note, if a new variable-length integer format were phased in with v3 transactions, OP_NUM2VARINT could be modified to use this format when used in a v3 transaction. However, because this difference would need to be tracked along with every UTXO for proper enforcement, it would be advantageous to deploy this "upgraded OP_NUM2VARINT" such that it is only valid in v3 transactions. If OP_NUM2VARINT were to also be deployed for v1 and v2 transactions, it may be valuable to define a separate opcode for a v3-only OP_NUM2BIGINT.
Area for Research: Serialized Transaction Introspection
One or more serialized transaction introspection operations could simplify CashToken inductive proofs and other types of looping contracts. Rather than operating on the current transaction (as is the case for this proposal's set of operations), serialized transaction introspection opcodes would instead operate on the top stack item, interpreting the stack item as a serialized transaction and extracting requested data. This strategy would result in shorter contracts when validation of parent transactions is required, though it would likely require an expansion of the 520 byte stack item size limit. Notably, while the transaction serialization format is already consensus-critical for transaction identification in outpoints, "serialized TxInt" operations would further ossify the serialization format. It may be wise to only enable these types of transactions after widespread use is demonstrated, and only for the latest transaction version deployed at that time.
I don't understand this. Read literally, the value of OP_UTXOBYTECODE is pushed to the stack since that is what is being evaluated.
You mentioned the P2SH "trick". Do you mean something like an OP_EXEC that executes the top stack item AS bytecode?