@@ -32,9 +32,7 @@ import "./interfaces/IEventForwarder.sol";
3232library EngineBlox {
3333 // ============ VERSION INFORMATION ============
3434 bytes32 public constant PROTOCOL_NAME_HASH = keccak256 ("Bloxchain " );
35- uint8 public constant VERSION_MAJOR = 1 ;
36- uint8 public constant VERSION_MINOR = 0 ;
37- uint8 public constant VERSION_PATCH = 0 ;
35+ string public constant VERSION = "1.0.0 " ;
3836
3937 // ============ SYSTEM SAFETY LIMITS ============
4038 // These constants define the safety range limits for system operations
@@ -206,8 +204,25 @@ library EngineBlox {
206204 bytes32 public constant NATIVE_TRANSFER_OPERATION = keccak256 ("NATIVE_TRANSFER " );
207205
208206 // EIP-712 Type Hashes (selective meta-tx payload: MetaTxRecord = txId + params + payment only)
209- bytes32 private constant META_TX_TYPE_HASH = keccak256 ("MetaTransaction(MetaTxRecord txRecord,MetaTxParams params,bytes data)MetaTxRecord(uint256 txId,TxParams params,PaymentDetails payment)TxParams(address requester,address target,uint256 value,uint256 gasLimit,bytes32 operationType,bytes4 executionSelector,bytes executionParams)MetaTxParams(uint256 chainId,uint256 nonce,address handlerContract,bytes4 handlerSelector,uint8 action,uint256 deadline,uint256 maxGasPrice,address signer)PaymentDetails(address recipient,uint256 nativeTokenAmount,address erc20TokenAddress,uint256 erc20TokenAmount) " );
210- bytes32 private constant META_TX_RECORD_TYPE_HASH = keccak256 ("MetaTxRecord(uint256 txId,TxParams params,PaymentDetails payment)TxParams(address requester,address target,uint256 value,uint256 gasLimit,bytes32 operationType,bytes4 executionSelector,bytes executionParams)PaymentDetails(address recipient,uint256 nativeTokenAmount,address erc20TokenAddress,uint256 erc20TokenAmount) " );
207+ // These follow the canonical EIP-712 convention so that eth_signTypedData_v4 and equivalent
208+ // wallet typed-data signers can reproduce the same hashes when given matching type definitions.
209+ //
210+ // Canonical primary type string for MetaTransaction (primary type + all referenced types,
211+ // appended in alphabetical order by type name
212+ bytes32 private constant META_TX_TYPE_HASH = keccak256 (
213+ "MetaTransaction(MetaTxRecord txRecord,MetaTxParams params,bytes data) "
214+ "MetaTxParams(uint256 chainId,uint256 nonce,address handlerContract,bytes4 handlerSelector,uint8 action,uint256 deadline,uint256 maxGasPrice,address signer) "
215+ "MetaTxRecord(uint256 txId,TxParams params,PaymentDetails payment) "
216+ "PaymentDetails(address recipient,uint256 nativeTokenAmount,address erc20TokenAddress,uint256 erc20TokenAmount) "
217+ "TxParams(address requester,address target,uint256 value,uint256 gasLimit,bytes32 operationType,bytes4 executionSelector,bytes executionParams) "
218+ );
219+
220+ // Canonical primary type string for MetaTxRecord (primary type + its referenced types).
221+ bytes32 private constant META_TX_RECORD_TYPE_HASH = keccak256 (
222+ "MetaTxRecord(uint256 txId,TxParams params,PaymentDetails payment) "
223+ "PaymentDetails(address recipient,uint256 nativeTokenAmount,address erc20TokenAddress,uint256 erc20TokenAmount) "
224+ "TxParams(address requester,address target,uint256 value,uint256 gasLimit,bytes32 operationType,bytes4 executionSelector,bytes executionParams) "
225+ );
211226 bytes32 private constant TX_PARAMS_TYPE_HASH = keccak256 ("TxParams(address requester,address target,uint256 value,uint256 gasLimit,bytes32 operationType,bytes4 executionSelector,bytes executionParams) " );
212227 bytes32 private constant META_TX_PARAMS_TYPE_HASH = keccak256 ("MetaTxParams(uint256 chainId,uint256 nonce,address handlerContract,bytes4 handlerSelector,uint8 action,uint256 deadline,uint256 maxGasPrice,address signer) " );
213228 bytes32 private constant PAYMENT_DETAILS_TYPE_HASH = keccak256 ("PaymentDetails(address recipient,uint256 nativeTokenAmount,address erc20TokenAddress,uint256 erc20TokenAmount) " );
@@ -1690,27 +1705,36 @@ library EngineBlox {
16901705
16911706 /**
16921707 * @dev Generates the EIP-712 message hash for the meta-transaction.
1693- * Uses selective MetaTxRecord (txId, params, payment only).
1694- * Integrators must sign this digest as a raw hash with no EIP-191 or personal_sign prefix—
1695- * e.g. account.sign({ hash: contractDigest }) or equivalent raw-hash signing API—so that
1696- * signatures match the raw ecrecover(messageHash, v, r, s) verification in recoverSigner.
1697- * Do NOT use personal_sign or generic eth_signTypedData_v4; the contract uses
1698- * abi.encodePacked for the version string and a custom META_TX_TYPE_HASH, so those produce
1699- * incompatible hashes.
1700- * The resulting digest is also written into the `message` field of the helper-built
1701- * `MetaTransaction` structs (see `createMetaTransactionForSigning`) so integrators can use
1702- * it directly without recomputing the hash client-side.
1708+ * Uses selective MetaTxRecord (txId, params, payment only) with standard EIP-712 type hashes
1709+ * so that eth_signTypedData_v4 (and equivalent) can reproduce the same digest when given
1710+ * matching domain + types:
1711+ *
1712+ * - primaryType: MetaTransaction
1713+ * - domain: { name: "Bloxchain", version: "1.0.0", chainId, verifyingContract }
1714+ * - types: MetaTransaction, MetaTxRecord, TxParams, MetaTxParams, PaymentDetails
1715+ *
1716+ * Integrators MAY:
1717+ * - use typed-data signing (eth_signTypedData_v4 / signTypedData) with the above domain/types, or
1718+ * - sign the resulting digest as a raw hash (e.g. account.sign({ hash: contractDigest })).
1719+ *
1720+ * In all cases, on-chain verification uses recoverSigner(messageHash, signature) which applies
1721+ * ecrecover(messageHash, v, r, s) with no personal_sign / EIP-191 prefix.
1722+ *
1723+ * The resulting digest is also written into the `message` field of helper-built `MetaTransaction`
1724+ * structs so integrators can use it directly without recomputing the hash client-side.
17031725 * @param metaTx The meta-transaction to generate the hash for
17041726 * @return The EIP-712 digest (no prefix; use standard recovery)
17051727 */
17061728 function generateMessageHash (MetaTransaction memory metaTx ) private view returns (bytes32 ) {
1707- bytes32 domainSeparator = keccak256 (abi.encode (
1708- DOMAIN_SEPARATOR_TYPE_HASH,
1709- PROTOCOL_NAME_HASH,
1710- keccak256 (abi.encodePacked (VERSION_MAJOR, ". " , VERSION_MINOR, ". " , VERSION_PATCH)),
1711- block .chainid ,
1712- address (this )
1713- ));
1729+ bytes32 domainSeparator = keccak256 (
1730+ abi.encode (
1731+ DOMAIN_SEPARATOR_TYPE_HASH,
1732+ PROTOCOL_NAME_HASH,
1733+ keccak256 (bytes (VERSION)),
1734+ block .chainid ,
1735+ address (this )
1736+ )
1737+ );
17141738
17151739 TxParams memory tp = metaTx.txRecord.params;
17161740 bytes32 txParamsStructHash = keccak256 (abi.encode (
@@ -1769,11 +1793,20 @@ library EngineBlox {
17691793
17701794 /**
17711795 * @dev Recovers the signer from the EIP-712 digest and signature. Uses standard EIP-712 recovery (no message prefix).
1772- * Integrators must sign the digest returned by generateMessageHash as a raw hash—e.g.
1773- * account.sign({ hash: contractDigest }) or equivalent raw-hash signing API—with no
1774- * EIP-191/personal prefix, so signatures match this ecrecover(messageHash, v, r, s) verification.
1775- * Do NOT use personal_sign or generic eth_signTypedData_v4; the contract uses abi.encodePacked
1776- * for the domain version and a custom META_TX_TYPE_HASH, so those produce incompatible hashes.
1796+ *
1797+ * Integrators have two equivalent options:
1798+ * - Use typed-data signing (eth_signTypedData_v4 / signTypedData) with:
1799+ * - primaryType: MetaTransaction
1800+ * - domain: { name: "Bloxchain", version: "1.0.0", chainId, verifyingContract }
1801+ * - types: MetaTransaction, MetaTxRecord, TxParams, MetaTxParams, PaymentDetails
1802+ * In this case the wallet computes the same digest as generateMessageHash and signs it.
1803+ * - Sign the digest returned by generateMessageHash as a raw hash—e.g.
1804+ * account.sign({ hash: contractDigest }) or equivalent raw-hash signing API—with no
1805+ * EIP-191/personal prefix.
1806+ *
1807+ * In all cases, this function applies ecrecover(messageHash, v, r, s) over the raw EIP-712 digest.
1808+ * personal_sign / EIP-191-prefixed signatures remain incompatible.
1809+ *
17771810 * @param messageHash The EIP-712 digest (keccak256("\x19\x01" || domainSeparator || structHash))
17781811 * @param signature The signature (r, s, v)
17791812 * @return The address of the signer
0 commit comments