Repository navigation
Conversation
A counterparty signs over a different hash prefix than an ordinary transaction signature, and the specification does not say so. Document both prefixes, since section 3.8.1.1 allows a single-key signature and a Signers list, and each uses a different one.
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Clarify that CPM applies to each nested signer’s TxnSignature and update the document metadata.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
This pull request documents the hash prefixes used for single- and multi-signature counterparty signatures in XLS-66.
Changes:
- Adds CPT and CPM prefix values.
- Contrasts them with ordinary transaction prefixes.
- References the corresponding rippled implementation.
File summaries
| File | Description |
|---|---|
XLS-0066-lending-protocol/README.md |
Specifies counterparty signing prefixes. |
Review details
Suppressed comments (1)
XLS-0066-lending-protocol/README.md:1017
CounterpartySignature.Signersis the array, not a signature-bearing field. TheCPMprefix applies to each nested signer’sTxnSignature; labeling the array itself leaves implementers unsure whether to hash the array once or which bytes to sign, and can produce invalid signatures. Identify the per-entry field and state that the prefix applies to every signer entry.
| `CounterpartySignature.Signers` | `CPM` | `0x43504D00` |
- Files reviewed: 1/1 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| 1. The `SigningPubKey` and `TxnSignature` fields, or | ||
| 2. The `Signers` field and, optionally, an empty `SigningPubKey`. | ||
|
|
||
| The counterparty signature is computed over the same signing fields as the primary signature, but with a different hash prefix: |
Collaborator
There was a problem hiding this comment.
Hey @hliosone this is a nice PR! Could you address the Copilot comment please.
Tapanito
reviewed
Sep 16, 2026
|
|
||
| These differ from the prefixes used for an ordinary transaction signature, `STX` (`0x53545800`) and `SMT` (`0x534D5400`). A counterparty signature computed with an ordinary prefix does not verify. | ||
|
|
||
| The values are defined in `HashPrefix.h` as `CounterpartyTxSign` and `CounterpartyTxMultiSign`, and are selected in `Sign.cpp` by `SignatureRole::Counterparty`. |
Collaborator
There was a problem hiding this comment.
Could you please remove this sentence as well. It can cause the specs to go stale whenever we'll update the code.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
XLS-66 section 3.8.1.1 describes the fields of
CounterpartySignature, and section 3.8.3 describes the handoff between the two parties, but the specification never states what bytes a counterparty signs. A counterparty signature uses a different hash prefix from an ordinary transaction signature, and there are two of them, because 3.8.1.1 permits either a single-key signature inTxnSignatureor aSignerslist.This adds a short table giving both, alongside the ordinary prefixes for contrast.
Verification
From
HashPrefix.honXRPLF/rippled@develop:where
makeHashPrefix(a, b, c) = a << 24 | b << 16 | c << 8, giving0x53545800,0x534D5400,0x43505400and0x43504D00.Which of the two counterparty prefixes applies is decided in
Sign.cpp:Why it is worth documenting
We hit this building a two-party
LoanSetat the XRPL Lending Protocol Hackathon in Paris on 12 and 13 September 2026. It cost roughly 114 minutes across 27 submissions on public Devnet. The rejection we saw wasfails local checks: Counterparty: Invalid signature, which does not point at a prefix, and we eventually found the answer by reading the source of a wallet extension rather than the specification or the SDK.Two nearby signals sent us the wrong way. Omitting
CounterpartySignaturereturnstemBAD_SIGNERwith text about duplicate signers, which reads as a multisign problem. AndcombineLoanSetCounterpartySignerssits next tosignLoanSetByCounterparty, mirroring thesignMultiBatchandcombineBatchSignerspair, so sign then combine then submit looks like the intended flow, when it is multisign only.xrpl.js5.2.0-beta.0 omitted the prefix insignLoanSetByCounterparty, and 5.2.0-beta.1 fixed it with aroleargument tocomputeSignature. That library is correct now, but anyone implementing the signature outside that helper, in another language, in a wallet, or in a hardware signing path, still has nothing in the specification to work from.Relationship to #570
#570 introduces a two-step flow and makes
CounterpartySignatureconditional, but it keeps the single-transaction flow and documents it in a new section 3.8.3.1. The prefixes are therefore still needed after that PR lands, and #570 does not document them. Happy to rebase on top of it if you would prefer to take that first.