Skip to content
Merged

Dev #230

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.5.0] - 2026-02-18

### Added

#### khodpay-signing (v0.2.0)

- ✨ **EIP-712 typed data signing** (`eip712` module) — generic, protocol-agnostic implementation
- `Eip712Type` trait: implement for any struct to get `type_hash()` and `hash_struct()` for free
- `Eip712Domain` + `Eip712DomainBuilder`: flexible domain with all 5 optional EIP-712 fields (`name`, `version`, `chainId`, `verifyingContract`, `salt`); `type_string()` auto-generates from only the fields set
- `hash_typed_data(domain, message)`: produces the `\x19\x01 || domainSep || structHash` envelope
- `sign_typed_data(signer, domain, message)`: signs with any `Bip44Signer`
- `verify_typed_data(domain, message, sig, expected)`: recovers and compares signer address
- ABI encoding helpers exported for use in `encode_data()` implementations: `encode_address`, `encode_uint64`, `encode_u256_bytes`, `encode_bool`, `encode_bytes32`, `encode_bytes_dynamic`

- ✨ **ERC-4337 v0.7 Account Abstraction** (`erc4337` module) — generic, protocol-agnostic implementation
- `PackedUserOperation` struct with all v0.7 fields including packed `bytes32` gas fields
- `PackedUserOperationBuilder`: fluent builder with validation for all required fields
- `pack_gas_limits(verificationGas, callGas)` / `pack_gas_fees(maxPriorityFee, maxFee)`: v0.7 packing helpers with matching unpack accessors
- `hash_user_operation(op, entry_point, chain_id)`: correct v0.7 hash formula
- `sign_user_operation(signer, op, entry_point, chain_id)`: returns a `Signature`
- `verify_user_operation(op, entry_point, chain_id, sig, expected)`: recover and compare
- `ENTRY_POINT_V07` constant: canonical `0x0000000071727De22E5E9d8BAf0edAc6f37da032`

- ✨ **Integration tests** (`tests/eip712_erc4337_integration_tests.rs`) — 21 tests covering:
- Full WPGP smart wallet flow: business signs `PaymentIntent` (EIP-712) → user signs `PackedUserOperation` (ERC-4337)
- Full WPGP EOA wallet flow: business signs `PaymentIntent` → user submits EIP-1559 transaction
- Replay protection: cross-chain, cross-entry-point, and cross-nonce hash uniqueness
- Forgery resistance: attacker cannot forge business or user signatures
- Tamper resistance: modified intent invalidates original signature
- Domain flexibility: optional `verifyingContract`, multi-version domains

### Changed

#### khodpay-signing
- Updated `description` and `keywords` in `Cargo.toml` to reflect new EIP-712 and ERC-4337 capabilities
- Expanded crate-level documentation with module overview table and quick-start examples for all three signing paths

## [0.4.0] - 2024-12-01

### Changed
Expand Down
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 3 additions & 9 deletions crates/bip32/src/public_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -788,17 +788,11 @@ mod tests {
let result = PublicKey::from_bytes(&bytes);
// This may or may not be on the curve - secp256k1 library handles validation
// We're testing that invalid points are rejected
if result.is_ok() {
// If this pattern happens to be valid, that's fine - secp256k1 accepted it
// The important thing is we don't crash or behave incorrectly
// Test passes - no assertion needed
} else {
if let Err(e) = result {
// If it's invalid, verify we get the right error
assert!(matches!(
result.unwrap_err(),
Error::InvalidPublicKey { .. }
));
assert!(matches!(e, Error::InvalidPublicKey { .. }));
}
// If this pattern happens to be valid, that's fine - secp256k1 accepted it
}

#[test]
Expand Down
31 changes: 31 additions & 0 deletions crates/bip44/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,37 @@ impl CoinType {
matches!(self, CoinType::BitcoinTestnet)
}

/// Returns `true` if this coin type uses EVM-compatible address derivation.
///
/// EVM-compatible chains derive addresses from the public key using Keccak-256
/// hashing. This includes:
/// - Ethereum and all Ethereum-based chains (Polygon, Arbitrum, Optimism, etc.)
/// - Ethereum Classic
/// - Binance Smart Chain (BSC)
/// - Tron (uses modified EVM)
///
/// Note: Most EVM chains (Polygon, Avalanche C-Chain, Arbitrum, etc.) use
/// Ethereum's coin type (60), so they're covered by `CoinType::Ethereum`.
///
/// # Examples
///
/// ```rust
/// use khodpay_bip44::CoinType;
///
/// assert!(CoinType::Ethereum.is_evm_compatible());
/// assert!(CoinType::EthereumClassic.is_evm_compatible());
/// assert!(CoinType::BinanceCoin.is_evm_compatible());
/// assert!(CoinType::Tron.is_evm_compatible());
/// assert!(!CoinType::Bitcoin.is_evm_compatible());
/// assert!(!CoinType::Solana.is_evm_compatible());
/// ```
pub const fn is_evm_compatible(&self) -> bool {
matches!(
self,
CoinType::Ethereum | CoinType::EthereumClassic | CoinType::BinanceCoin | CoinType::Tron
)
}

/// Returns the default purpose for this coin type.
///
/// Different cryptocurrencies may have different default address formats:
Expand Down
9 changes: 6 additions & 3 deletions crates/khodpay-signing/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[package]
name = "khodpay-signing"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
authors = ["Khodpay"]
description = "EVM transaction signing for BSC and other EVM chains"
description = "EVM signing: EIP-1559 transactions, EIP-712 typed data, and ERC-4337 UserOperation"
license = "MIT OR Apache-2.0"
repository = "https://github.com/khodpay/khodpay-wallet"
keywords = ["bsc", "ethereum", "evm", "signing", "transaction"]
keywords = ["eip712", "erc4337", "ethereum", "signing", "account-abstraction"]
categories = ["cryptography", "no-std"]

[dependencies]
Expand Down Expand Up @@ -35,10 +35,13 @@ zeroize = { version = "1.7", features = ["derive"] }

# Optional serialization
serde = { version = "1.0", optional = true, features = ["derive"] }
serde_json = { version = "1.0", optional = true }

[features]
default = []
serde = ["dep:serde"]
eip712 = ["serde", "dep:serde_json"]
erc4337 = ["eip712"]

[dev-dependencies]
khodpay-bip39 = { version = "0.4.0", path = "../bip39" }
Loading