Then we should relax the limitation on data carrier to be per-output rather than total per-transaction, else people who need more than 223 bytes in a transaction would just use multiple P2S outputs to get around not being able to use multiple data carrier outputs.
People can already do exactly that without P2S (bare multisig and/or input data). The primary difference is whether or not the dust limit is enforced: data carrier outputs can have a value of 0, while P2S outputs are required to “pay rent” via dust just like P2PKH, P2SH, BMS, etc. No change from the status quo.
Note that I wouldn’t be against a different CHIP simply removing the data carrier limit – again, the most relevant limit is currently ~100KB. The surface-level 223 byte limit was based on a misunderstanding, and it’s simply a mechanical inconvenience to protocols requiring larger data commitments. (Regardless, bandwidth is already paid by transaction fees, and transaction fees from all sources contribute equally to long-term network security and monetary soundness.)
If you’re interested, I’d love to see another CHIP focus specifically on that topic. The P2S CHIP requires no change either way.
I want to document that most libraries like CashScript, mainnet-js and bch-js would have to be upgraded to support fetching UTXOs for arbitrary scripts as P2S won’t use an address format.
I don’t think it is bad that there’s a need to upgrade ecosystem tooling to support the new functionality but I just want to note it won’t be automatically supported in most libraries by default. This is because most tooling wasn’t designed with this in front-of-mind.
Luckily most APIs for blockchain-data like Electrum, ChainGraph and Chronik already allow for lockingbytecode / script / scripthash encoding. I think most blockexplorers would also be fine.
I would be interested if anyone else has more insights into the ‘ecosystem costs’ for properly supporting P2S functionality 
I think this CHIP could really benefit from fleshing out a couple of real world examples. Ok so I understand that P2S isn’t summarized into an easily payable address string that anyone could paste into their wallet & just send off funds to - but then how DO people pay to these addresses (given they have a supporting wallet and a need to do so)?? or is it that these contracts get funded & then just run autonomously? Surely there would be some kind of user interaction in many cases?
Is it supposed to always just be automated contracts sending to other automated contracts? How do they know where to send the funds if there is no address (do they copy the template and then hash it themselves for the locking bytecode)?
A couple of small examples would really help clarify this a lot I think.
There is no “where.” There is only UTXO.
Inputs → Script → Outputs
“Where” is “inside the UTXO set.”
Your wallet needs to know about all of the UTXOs it can control. It’s easy to index and find them by address because p2p cash just uses p2pkh outputs.
But what if I wanted to interact with a cauldron LP, which is Anyone-Can-Spend? The transaction gets built the same way: Input → Script → Output. In our case, we’d learn that there’s a cauldron utxo at some transaction b411a9d3… and outpoint 0, and we can reference that utxo in the script we use to build the transaction.
This is the same way p2pkh works, we know we have some utxo on some transaction:outpoint, and it gets processed by a script that says “if the data from this input matches the hash on this output (your address), allow this spend”
So the address isn’t really a locator. It’s not your house address, it’s the shape of the inside of your deadbolt lock.
When we download some UTXOs and inspect their locking bytecode, you just get a blob of hex digits.
What we mentally think of as opcodes are just hex digits to the VM, being parsed sequentially.
So what P2S does is give us the raw hex blob - we know exactly what opcodes are in the locking bytecode. We transparently know every spend path for that output.
With P2SH, the hex blob is hashed, so the only way to know what the script does, you just have to hope you pass the correct data in your input to spend it. (or have some external knowledge of the contract)
My question is though, how would your wallet know which of those Anyone-Can-Spend UTXOs it could possibly be interested in / able to interact with? Obviously you can’t find them by address. I guess that’s where wallet templates maybe come into it?
Do you have to query Fulcrum for the full UTXO set? I assume not, I assume there will be some kind of endpoint for just checking hanging P2S outputs, but do I need to grab all of those to sift through for the one I want? How do I know what I want?
Do wallet authors need to individually code wallets to recognise each type of script? Is there going to be a “BCMR” type registry for common script patterns?
With wallet templates, then you could scan the blockchain for UTXOs that match a template. Or you could use an indexer like chaingraph to look for outputs with certain fingerprints. Or you could have some other system… I think Cauldron in particular uses an OP_RETURN 'SUMMON' or something like that to identify cauldrons and make them indexable.
We don’t have to query Fulcrum for the full UTXO set, we index UTXOs by address because it’s easy to do that for P2PKH and P2SH. But as you noted, we need some other way to identify other utxos that I can spend.
I believe we can also use the existing BCMR spec to identify and authenticate wallet templates/contract metadata like we can with token metadata.
With P2S outputs we could theoretically scan the whole UTXO set and find out about every public contract that exists on-chain, since they wouldn’t be obscured by hash.
Thanks for the comments everyone! Just a bump to note that the CHIP now links the BCHN implementation and directly commits the updated test vectors (now covering a few thousand more cases and benchmarks
)
So, the “address” is on chain just a 20 bytes hash. Which, again on chain, is actually identical between the p2pkh and the p2sh usecases. Which could be an issue, obviously.
This is an old problem, and the solution is actually quite interesting.
What the difference is between the p2pkh and p2sh addresses, again on chain, is the opcodes that surround them. So, the original designers of the indexers (fulcrum, electrumx etc) considered that problem and came with the solution to have a output-script-hash. A sha256 hash of the opcodes plus the 20-byte address. Which obviously nicely makes the p2sh and p2pkh addresses have a different hash.
The cool thing is, you can put in any outputscript and hash it and ask fulcrum to treat it as “an address” which you show in your wallet and get balance from etc.
The only requirement is that you get the full output-script somehow.
To enable payments between two wallets, you would not show a QR with an cash-address (q* or somesuch), instead you’d need to set up a bit more complex communication between the payer and payee. BIP70 is actually already capable of this. It allows embedding the actual output script instead of the address.
Fulcrum calls this ‘scripthash’. Example: Protocol Methods — Electrum Cash Protocol Fulcrum Protocol Reference 1.5.1 documentation
Here’s a data point on what happens when the market for out-of-band transactions gets developed: https://x.com/ercwl/status/1919834472549118413
IMO we should entirely close the gap between relay and consensus rules. This CHIP is a good step in that direction, but it doesn’t yet do it fully. Maybe do it fully?
same as you now pay to contract addresses through dapp frontends: the dapp generates the outputs for you, and you sign with WalletConnect
how do you discover them? well, instead of indexing on address, new indexers could index on data pushes and create an index of all utxos with 20-byte pushes, then you could look up your key hash and get a list of potential utxos you can spend, then check the contract fingerprint to know what you’re looking at
From Selection of Maximum Token Commitment Length
The
128byte limit is selected to remain below the existing data-carrier limit (220bytes), while extending the usefulness of the commitment field (without added waste or complexity from a hash-unwrapping step) for notable use cases: bilinear pairing-based accumulators (e.g.BLS12-381KZG commitments require ~48 bytes compressed or ~96 bytes uncompressed), two 64-byte Schnorr signatures, four 32-byte (OP_HASH256, birthday-collision resistant) hashes, or six 20-byte (OP_HASH160) hashes.
What is the reason not to set the Token Commitment limit also at 220 bytes so it matches the data-carrier-limit? I understand 128 is a “nice” number in base 2, but I feel like the trend is to unifying limits (removing edge cases & gaps, especially regarding miner or data storage incentives). Why wouldn’t that be the approach here?
Note, this is something I have proposed before. Perhaps we can develop the discussion in that thread.
Thanks! Added new sections on this:
- Status Quo: 40-Byte Token Commitments
- Alternative: 201-Byte Token Commitments
- Alternative: 220-Byte Token Commitments,
- Alternative: 10,000-Byte Token Commitments
- Alternative 100,000-Byte Token Commitments
RE unifying standardness and consensus: I’d support a future CHIP simplifying even further by setting commitment and bytecode length limits based on today’s most relevant ~100KB per-TX cumulative limit (minus some overhead, follows from MAX_STANDARD_TX_SIZE), but for the P2S CHIP I’ve avoided any new “plausible risks” to simplify review. See:
- Alternative: 100,000-Byte Locking Bytecode Limit
- Alternative 100,000-Byte Token Commitments, and
- Alternative: 100,000-Byte Unlocking Bytecode Limit.
Given the updated VM limits approach, I think there’s also little remaining justification for limiting standard TX sizes below the consensus limit, so 1MB (MAX_TX_SIZE) may be just as reasonable for all of the above. (Again, cans-of-worms I’m not interested in building consensus on for 2026.)
On the BLISS Technical Panel, discussion of P2S started out with everyone very positive on the idea but then refocussed on the risks (basically if not directly researched) of changes to relay-vs-consensus and shrinking that gap.
BCH is not the first place in the world people are looking to store lots of arbitrary data (being either more BTC or BSV inclined in general), but at some point we’re going to have those guys show up to ““spam”” our chain & we want to be well prepared for that.
I’ve been reviewing this further and it seems to all make sense to me. The changes around standardness regarding the unlocking byte code and token commitments seem very sensible and conservative, just like VM Limits they respect the existing worst case, and as noted in the CHIP it will be a separate project to investigate deeply the additional limits and incentives for data carrying.
But for P2S CHIP I’m feeling more confident.
Non-Impact on Data-Carrier Outputs (A.K.A. OP_RETURN Outputs)
This proposal carefully avoids impact to the costs and incentives of “on-chain data storage” use cases. Because the existing 220-byte content limit on
OP_RETURNData Carrier Outputs was originally selected due to a miscalculation, there is insufficient consensus among stakeholders as to whether or not the limit should exist, and future proposals can separately increase or remove this limit, this proposal considers changes impacting the status quo to be out of scope.Non-Reliance on Miscalculated 220-Byte Limit
The 220-byte limit was originally established to, “disincentivize the use of other methods to embed data into the chain” (commit
cbf44109). However, this rationale was based on earlier analysis which omitted more efficient strategies for recording arbitrary data in standard transactions. As such, this proposal avoids modifying or establishing any new limits based on the incorrect220byte constant; future proposals can separately address this topic.
In another thread it was brought up by @jimtendo that current standardness rules introduce a DoS vector for contracts: “Potential Lockscript Standardness DoS vector in Contract Dev”
The P2S CHIP would resolve this issue in an elegant way. With P2S, it would no longer be possible for user-provided lockingbytecode to be used to grief covenants into becoming non-standard to spend from
Thank you to all contributors and reviewers so far – I’ve frozen the P2S CHIP for lock-in at v1.0.3 (c144f03f), and stakeholder statements will be periodically updated through November 1. Final approval requests will go out in early October.
Please feel free to open issues in the repo for further comments, clarifications, or feedback, and please continue to publish and/or send pull requests with stakeholder statements.
This CHIP is integrated and live on the Sept. 15 public test network (tempnet) – please see that topic for details on how to setup a tempnet node and experiment with the upgrade 
Regarding the ecosystem integration of P2S outputs, I don’t know if any explorers actually support looking up balances/tx history by just a hexadecimal lockingbytecode. So while explorers probably won’t have problems with it as an input or output in transactions, i don’t think any of them support lookup.
So hopefully we’ll see explorers which support searching by hex locking bytecode in addition to by address?
No, but 3xpl supports looking up by hash of locking bytecode, e.g. the Script 0x51 can be found under Bitcoin Cash address script-031b4af5197ec30a926f48cf40e11a7d — 3xpl
The method is: take the hex string representation of locking bytecode (NOT the raw bytes) and hash it with sha256, prepend with “script-”.
Code: https://github.com/3xplcom/Core/blob/7b1997ab6ccfc823bc02fcb8c6f718cef9c03927/Modules/Common/UTXOMainModule.php#L156
Bash one-liner:
hex=0xAC; echo "https://3xpl.com/bitcoin-cash/address/script-"$(echo -n $hex | sed -s 's/^0x//' | tr 'A-F' 'a-f' | sha256sum | cut -b 1-32)`
Some example scripts:
- “” (empty, anyonecanspend): Bitcoin Cash address script-e3b0c44298fc1c149afbf4c8996fb924 — 3xpl
- 0x51 (OP_1, anyoncanspend): Bitcoin Cash address script-031b4af5197ec30a926f48cf40e11a7d — 3xpl
- 0xac (OP_CHECKSIG, anyonecanspend): Bitcoin Cash address script-f45de51cdef30991551e41e882dd7b54 — 3xpl
- 0xff (OP_UNKNOWN, unspendable): Bitcoin Cash address script-05a9bf223fedf80a9d0da5f73f5c191a — 3xpl
- 0xae91 (OP_CHECKMULTISIG OP_NOT, anyonecanspend): Bitcoin Cash address script-db6dbf144242a58ba3be00f4fc5deaa9 — 3xpl
I hope to see some explorers index on bytecode fingerprints, too:
- Node RPC extension: RPC: add patterns flag for `getblock` and `getrawtransaction` verbose RPCs which adds script "byteCodePattern" information (!1958) · Merge requests · Bitcoin Cash Node / Bitcoin Cash Node · GitLab
- Method: ac-0353f40e / Smart Contract Fingerprinting · GitLab
- Known fingerprints: bytecode-fingerprints · king · ac-0353f40e / Script Bytecode Fingerprints · GitLab