feat: implement signer domain separation v2#643
feat: implement signer domain separation v2#643charliechinedu19-netizen wants to merge 3 commits into
Conversation
|
@charliechinedu19-netizen Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
b458f7a to
edb46a7
Compare
edb46a7 to
492b0fb
Compare
|
@charliechinedu19-netizen please fix workflow |
|
@Cedarich Sorry I'm just seeing this. I'll fix asap |
|
@Cedarich I fixed it boss. Please check now, it should pass. |
|
@Cedarich I've seen the issue. What's failing right now is clippy and no longer formatting. I will just run everything on my end to check for failures and fix any. |
|
@Cedarich I've pushed the fix. Formatting passes now, but there are pre-existing test errors that were not from my changes. Please rerun the job so we can confirm it worked. |
Summary
Closes #571
Hardens signature verification by introducing a canonical signed payload envelope that includes contract ID, network passphrase, and action type, preventing replay across methods, contracts, and networks.
What Changed
1. Canonical Signed Payload Envelope (
nonce.rs)Off-chain signers now construct payloads as:
New exports:
build_canonical_payload()— builds the full envelopehash_canonical_payload()— returns the SHA256 to signdomain_prefix_v1()— legacy helper retained for migration2. ActionType Enum (
nonce.rs)14 variants covering every contract entry point that requires authorization:
Withdraw,Refund,Dispute,ResolveDispute,VoteForDispute,ResolveDisputeMultiSig,Deposit,DepositWithCommitment,DepositPartial,PartialPayment,StealthDeposit,StealthWithdraw,SetPrivacy,UpgradeEach variant maps to a unique byte tag used in the canonical envelope.
3. Nonce Verification Wired into Contract Methods
Every signature-based action now accepts
nonce: u64, valid_until: u64and callsnonce::verify_and_consume()with the appropriateActionType:depositDepositdeposit_with_commitmentDepositWithCommitmentdeposit_partialDepositPartialwithdrawWithdrawrefundRefundpartial_paymentPartialPaymentresolve_disputeResolveDisputevote_for_disputeVoteForDisputeregister_ephemeral_keyStealthDepositstealth_withdrawStealthWithdraw4. Nonce Storage Layout
NonceKey::Used(Address, u64, ActionType)— nonce tracking now includes action type for defense-in-depth.NonceKey::UsedV1(Address, u64)— legacy layout retained for backward-compatible reads during transition.5. Escrow ID Domain Tag Bumped to v2
ESCROW_ID_DOMAIN_TAGchanged fromQUICKEX::ESCROW_ID::v1→QUICKEX::ESCROW_ID::v2to ensure deterministic escrow IDs computed by new code are distinct from v1 IDs.Files Modified
app/contract/contracts/quickex/src/nonce.rsapp/contract/contracts/quickex/src/nonce_test.rsapp/contract/contracts/quickex/src/escrow.rsapp/contract/contracts/quickex/src/stealth.rsapp/contract/contracts/quickex/src/escrow_id.rsapp/contract/contracts/quickex/src/lib.rsapp/contract/contracts/quickex/src/fuzz_test.rsapp/contract/contracts/quickex/src/stealth_test.rsapp/contract/contracts/quickex/src/test_context.rsAcceptance Criteria
ActionTypein both the canonical payload and the nonce storage key prevents cross-method reusecontract_idin the canonical envelope binds to the specific deploymentnetwork_passphrasein the envelope binds to the networknonce_test.rsverifies determinism, structure, and differentiationdomain_prefix_v1()retained,NonceKey::UsedV1retained, all existing test calls updated with nonce/valid_until defaultsMigration Compatibility
domain_prefix_v1()still exported for test fixtures containing v1-style signaturesNonceKey::UsedV1(Address, u64)retains the old storage discriminant so pre-existing consumed nonces remain recognisedEscrowIDv1 IDs remain readable in storage; v2 IDs are computed under a different domain tag and cannot collide0nonce andu64::MAXvalid_until, preserving their existing behaviour while satisfying the new interfaceVerification