Skip to content

Commit 73eb0ce

Browse files
committed
Document dual-domain sponsorship signatures
1 parent 775ce82 commit 73eb0ce

1 file changed

Lines changed: 28 additions & 18 deletions

File tree

docs/adr/ADR-0003-typed-transactions-sponsorship.md

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,15 @@ optional sponsor authorization, enabling a sponsor account to pay fees while
4444
preserving normal EVM execution semantics for the user call. It is not a
4545
"sponsorship-only" transaction; it is an additional EvNode transaction format
4646
and sponsorship is an optional capability. Other transaction types remain
47-
supported and this type is not the sole or primary format. The transaction itself
48-
uses the standard secp256k1 signature wrapper (`Signed<T>`), so we do not introduce
49-
a custom signed wrapper type.
47+
supported and this type is not the sole or primary format. The transaction uses
48+
separate executor and sponsor signature domains, so it requires a custom signed
49+
wrapper and signature hashing logic.
5050

5151
## Implementation Plan
5252

5353
1. Define the consensus transaction envelope and type.
5454
- Define the `EvNodeTransaction` struct and `EvRethTxEnvelope` enum in
55-
`crates/primitives`, using `Signed<T>` for the executor signature.
55+
`crates/primitives`, using a custom signed wrapper.
5656
- Register the new typed transaction with `#[envelope(ty = 0x76)]` and keep
5757
the consensus field ordering explicit in the struct.
5858

@@ -76,7 +76,7 @@ pub enum EvRethTxEnvelope {
7676
#[envelope(ty = 3)]
7777
Eip4844(Signed<TxEip4844>),
7878
#[envelope(ty = 0x76]
79-
EvNode(Signed<EvNodeTransaction>),
79+
EvNode(EvNodeSignedTx),
8080
}
8181

8282
#[derive(
@@ -115,19 +115,29 @@ pub struct EvNodeTransaction {
115115
order, the struct must match this ordering exactly.
116116
- Encode optional fields deterministically:
117117
- `fee_payer_signature`: always encoded; if `None`, encode `0x80`.
118-
- Executor signature preimage (EIP-2718):
119-
- `0x76 || rlp(fields...)` with `fee_payer_signature` encoded as `0x80`
118+
- Executor signature preimage (domain: `0x76`):
119+
- `0x76 || rlp(fields...)` with `fee_payer_signature = 0x80`
120120
regardless of whether a sponsor will sign later.
121-
- Sponsor signature preimage (separate domain):
122-
- `SPONSOR_DOMAIN_BYTE || rlp(fields...)` where `fee_payer_signature` is
123-
replaced by the executor address.
121+
- Sponsor signature preimage (domain: `0x78`):
122+
- `0x78 || rlp(fields...)` where `fee_payer_signature` is replaced by the
123+
executor address.
124124
- `tx_hash` uses standard EIP-2718 hashing:
125125
- `keccak256(0x76 || rlp(fields...))` with the *final* `fee_payer_signature`.
126-
- Ensure the signed type implements the `SignedTransaction` requirements
127-
(`Encodable`, `Decodable`, `Encodable2718`, `Decodable2718`, `Transaction`,
128-
`SignerRecoverable`, `TxHashRef`, `InMemorySize`, `IsTyped2718`/`Typed2718`).
129-
130-
3. Add the tx type identifier and compact encoding.
126+
- Ensure the custom signed type exposes:
127+
- `executor_signature_hash()` (placeholder sponsor signature)
128+
- `sponsor_signature_hash()` (executor address in sponsor slot)
129+
- `recover_executor()` and `recover_sponsor()` as applicable
130+
- trait implementations required by Reth for pool/consensus encoding
131+
(`Encodable`, `Decodable`, `Encodable2718`, `Decodable2718`, `Transaction`,
132+
`TxHashRef`, `InMemorySize`, `IsTyped2718`/`Typed2718`).
133+
134+
3. Optional sponsorship behavior.
135+
- If `fee_payer_signature` is `None`, the payer is the executor and validation
136+
follows the standard EIP-1559 path.
137+
- If `fee_payer_signature` is `Some`, the payer is the sponsor and the sponsor
138+
signature must be valid for the sponsor domain and bound to the executor.
139+
140+
4. Add the tx type identifier and compact encoding.
131141
- Register the new type id in the custom `TxType` enum and compact codec
132142
(extended identifier if needed), so storage/network encoding works.
133143
- Ensure `TransactionEnvelope` derives cover both the canonical and pooled
@@ -178,7 +188,7 @@ impl Compact for EvRethTxType {
178188
}
179189
```
180190

181-
4. Map the new tx to EVM execution.
191+
5. Map the new tx to EVM execution.
182192
- Define `TxEnv` mapping for executor vs sponsor, including gas price and
183193
fee fields when a sponsor is present.
184194
- Add execution logic for the new variant in the block executor and
@@ -218,7 +228,7 @@ match tx.tx() {
218228
}
219229
```
220230

221-
5. Decode in Engine API payloads and validate.
231+
6. Decode in Engine API payloads and validate.
222232
- Update the payload transaction iterator to decode the custom type using
223233
2718 decoding, recover signer, and preserve the encoded bytes.
224234
- Add fast, stateless validation for sponsorship fields during payload
@@ -242,7 +252,7 @@ Note: in this repo, the Engine API decode/validation currently happens in
242252
`crates/node/src/attributes.rs` within
243253
`PayloadBuilderAttributes::try_new` (the `attributes.transactions` decoding).
244254

245-
6. Define sponsorship validation and failure modes.
255+
7. Define sponsorship validation and failure modes.
246256
- Specify the sponsor authorization format, signature verification, and
247257
constraints (e.g. max fee caps).
248258
- Define stateful validation and exact behavior when sponsor auth is

0 commit comments

Comments
 (0)