-
Notifications
You must be signed in to change notification settings - Fork 110
Description
Summary
The op-rbuilder crate contains a custom Signer struct that manually implements transaction and message signing using the secp256k1 crate. This functionality is already provided by alloy-signer-local's PrivateKeySigner, which the codebase already depends on and uses elsewhere.
Consolidating on alloy-signer-local would reduce maintenance burden, leverage well-tested upstream code, and provide additional features like EIP-712 typed data signing, HSM support, and mnemonic/keystore support.
Current Implementation
The custom Signer wraps secp256k1 directly:
pub struct Signer {
pub address: Address,
pub pubkey: PublicKey, // secp256k1::PublicKey
pub secret: SecretKey, // secp256k1::SecretKey
}Key methods:
sign_message(B256)— Signs raw hashes usingSECP256K1.sign_ecdsa_recoverable()sign_tx(OpTypedTransaction)— Signs transactions by computing signature hash per tx typetry_from_secret(B256)— Constructs from private key bytes
Alloy Provides Equivalent Functionality
Custom Signer Method |
Alloy Equivalent |
|---|---|
sign_message(B256) |
SignerSync::sign_hash_sync(&hash) |
sign_tx(OpTypedTransaction) |
TxSignerSync::sign_transaction_sync(&mut tx) |
try_from_secret(B256) |
PrivateKeySigner::from_bytes(&fixed_bytes) |
random() |
PrivateKeySigner::random() |
.address |
Signer::address(&self) |
Evidence: Codebase Already Uses Both
The codebase already has a hybrid approach where custom Signer is converted to PrivateKeySigner:
tx_manager.rs:71-73— Converts customSignertoPrivateKeySignerfor provider integration:
let wallet = PrivateKeySigner::from_bytes(&self.builder_signer.secret.secret_bytes().into())-
accounts.rs:58-64— UsesPrivateKeySignerdirectly for test accounts -
test_utils.rs— UsesTxSignerSync::sign_transaction_sync()from alloy
Files Using Custom Signer
tx_signer.rs— Definition (~100 lines)args/op.rs— CLI argument parsingbuilders/context.rs— Builder context storagebuilders/builder_tx.rs:280-302— Transaction signingflashtestations/builder_tx.rs— Permit signingflashtestations/tx_manager.rs— TEE registrationtests/framework/utils.rs— Test signer helpers
Benefits of Migration
- Reduced maintenance — ~100 lines of custom crypto code removed
- Well-tested upstream —
alloy-signer-localis battle-tested - Additional features available:
- EIP-712 typed data signing (useful for flashtestations permits)
- Async signing support (
Signertrait) - Chain ID management
- HSM support via
yubihsmfeature - Mnemonic support via
mnemonicfeature - Keystore support via
keystorefeature
secp256k1backend available — If exact parity with current implementation is needed,alloy-signer-localprovidesSecp256k1Signervia thesecp256k1feature flag
Migration Notes
The one unique aspect of the custom Signer is sign_tx() returning Recovered<OpTransactionSigned> directly. With alloy, this becomes:
// Current custom implementation (one call)
let recovered = signer.sign_tx(tx)?;
// With alloy (explicit steps, or wrap in helper)
let signature = signer.sign_hash_sync(&tx.signature_hash())?;
let signed = OpTransactionSigned::new_unhashed(tx, signature);
let recovered = Recovered::new_unchecked(signed, signer.address());A helper trait or function can preserve the ergonomic API if desired.
Proposed Changes
- Replace
Signerstruct withPrivateKeySigner(possibly with a type alias or newtype wrapper forFromStrCLI parsing) - Update
sign_message(B256)calls tosign_hash_sync(&hash) - Create a helper for
sign_tx()pattern if needed - Remove
tx_signer.rsor reduce to just the helper - Update all import sites