Skip to content
Merged

Dev #127

Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d79d293
feat: standardize EIP-712 type hashes and signing process in EngineBl…
JaCoderX Mar 13, 2026
7cf6a66
chore: update package versions to 1.0.0-alpha.18 across all modules
JaCoderX Mar 13, 2026
c617c59
feat: enhance typed-data signing validation in MetaTransactionSigner
JaCoderX Mar 13, 2026
e8d9dcb
Merge pull request #126 from PracticalParticle/work
JaCoderX Mar 13, 2026
97faa65
chore: consolidate versioning approach in EngineBlox library and rela…
JaCoderX Mar 14, 2026
7578702
chore: update package-lock.json to version 1.0.0-alpha.18 and upgrade…
JaCoderX Mar 14, 2026
0be5e8b
chore: update package-lock.json to include conventional-commits-filte…
JaCoderX Mar 14, 2026
4a7b5d3
Merge pull request #129 from PracticalParticle/work
JaCoderX Mar 14, 2026
ac0345b
chore: standardize OpenZeppelin contract versions in package.json and…
JaCoderX Mar 14, 2026
fe3bb37
fix: correct chainId assignment in MetaTransactionSigner class
JaCoderX Mar 14, 2026
f04bebe
chore: enhance version file checks in sync workflow
JaCoderX Mar 16, 2026
e80cebb
chore: improve timeout handling and logging in remote Ganache health …
JaCoderX Mar 16, 2026
b657894
Merge pull request #130 from PracticalParticle/work
JaCoderX Mar 16, 2026
9caf9d5
chore: enhance dependabot configuration for improved package management
JaCoderX Mar 16, 2026
3e475ee
fix: improve gas limit handling in BaseStateMachine
JaCoderX Mar 16, 2026
124ec65
fix: add validation for non-negative gas limit in BaseStateMachine
JaCoderX Mar 16, 2026
8553caf
fix: enhance gas option type handling in TransactionOptions interface
JaCoderX Mar 16, 2026
54e9ded
Merge pull request #131 from PracticalParticle/work
JaCoderX Mar 16, 2026
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
12 changes: 6 additions & 6 deletions .github/workflows/sync-contract-versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ jobs:
DIFF_OUTPUT=$(git diff contracts/core/lib/EngineBlox.sol)

# Check if diff contains only version constant changes
# Version constants are: VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH
if echo "$DIFF_OUTPUT" | grep -qE "^[-+].*VERSION_(MAJOR|MINOR|PATCH)" && \
! echo "$DIFF_OUTPUT" | grep -vE "^[-+].*VERSION_(MAJOR|MINOR|PATCH)|^@|^index|^---|^\+\+\+" | grep -qE "^[-+]"; then
echo "✓ Only version constants changed, safe to commit"
# Version constant is: string public constant VERSION = "..."
if echo "$DIFF_OUTPUT" | grep -qE "^[-+].*constant\s+VERSION\s*=" && \
! echo "$DIFF_OUTPUT" | grep -vE "^[-+].*constant\s+VERSION\s*=|^@|^index|^---|^\+\+\+" | grep -qE "^[-+]"; then
echo "✓ Only version constant changed, safe to commit"
echo "safe=true" >> $GITHUB_OUTPUT
else
echo "❌ ERROR: Changes detected in EngineBlox.sol are not limited to version constants!"
echo "❌ ERROR: Changes detected in EngineBlox.sol are not limited to version constant!"
echo ""
echo "The workflow detected changes beyond VERSION_MAJOR, VERSION_MINOR, or VERSION_PATCH."
echo "The workflow detected changes beyond the VERSION constant."
echo "This could indicate uncommitted changes were accidentally included."
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
echo ""
echo "Full diff:"
Expand Down
32 changes: 3 additions & 29 deletions abi/EngineBlox.abi.json
Original file line number Diff line number Diff line change
Expand Up @@ -689,38 +689,12 @@
},
{
"inputs": [],
"name": "VERSION_MAJOR",
"name": "VERSION",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "VERSION_MINOR",
"outputs": [
{
"internalType": "uint8",
"internalType": "string",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "VERSION_PATCH",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
"type": "string"
}
],
"stateMutability": "view",
Expand Down
87 changes: 60 additions & 27 deletions contracts/core/lib/EngineBlox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ import "./interfaces/IEventForwarder.sol";
library EngineBlox {
// ============ VERSION INFORMATION ============
bytes32 public constant PROTOCOL_NAME_HASH = keccak256("Bloxchain");
uint8 public constant VERSION_MAJOR = 1;
uint8 public constant VERSION_MINOR = 0;
uint8 public constant VERSION_PATCH = 0;
string public constant VERSION = "1.0.0";

// ============ SYSTEM SAFETY LIMITS ============
// These constants define the safety range limits for system operations
Expand Down Expand Up @@ -206,8 +204,25 @@ library EngineBlox {
bytes32 public constant NATIVE_TRANSFER_OPERATION = keccak256("NATIVE_TRANSFER");

// EIP-712 Type Hashes (selective meta-tx payload: MetaTxRecord = txId + params + payment only)
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)");
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)");
// These follow the canonical EIP-712 convention so that eth_signTypedData_v4 and equivalent
// wallet typed-data signers can reproduce the same hashes when given matching type definitions.
//
// Canonical primary type string for MetaTransaction (primary type + all referenced types,
// appended in alphabetical order by type name
bytes32 private constant META_TX_TYPE_HASH = keccak256(
"MetaTransaction(MetaTxRecord txRecord,MetaTxParams params,bytes data)"
"MetaTxParams(uint256 chainId,uint256 nonce,address handlerContract,bytes4 handlerSelector,uint8 action,uint256 deadline,uint256 maxGasPrice,address signer)"
"MetaTxRecord(uint256 txId,TxParams params,PaymentDetails payment)"
"PaymentDetails(address recipient,uint256 nativeTokenAmount,address erc20TokenAddress,uint256 erc20TokenAmount)"
"TxParams(address requester,address target,uint256 value,uint256 gasLimit,bytes32 operationType,bytes4 executionSelector,bytes executionParams)"
);

// Canonical primary type string for MetaTxRecord (primary type + its referenced types).
bytes32 private constant META_TX_RECORD_TYPE_HASH = keccak256(
"MetaTxRecord(uint256 txId,TxParams params,PaymentDetails payment)"
"PaymentDetails(address recipient,uint256 nativeTokenAmount,address erc20TokenAddress,uint256 erc20TokenAmount)"
"TxParams(address requester,address target,uint256 value,uint256 gasLimit,bytes32 operationType,bytes4 executionSelector,bytes executionParams)"
);
bytes32 private constant TX_PARAMS_TYPE_HASH = keccak256("TxParams(address requester,address target,uint256 value,uint256 gasLimit,bytes32 operationType,bytes4 executionSelector,bytes executionParams)");
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)");
bytes32 private constant PAYMENT_DETAILS_TYPE_HASH = keccak256("PaymentDetails(address recipient,uint256 nativeTokenAmount,address erc20TokenAddress,uint256 erc20TokenAmount)");
Expand Down Expand Up @@ -1690,27 +1705,36 @@ library EngineBlox {

/**
* @dev Generates the EIP-712 message hash for the meta-transaction.
* Uses selective MetaTxRecord (txId, params, payment only).
* Integrators must sign this digest as a raw hash with no EIP-191 or personal_sign prefix—
* e.g. account.sign({ hash: contractDigest }) or equivalent raw-hash signing API—so that
* signatures match the raw ecrecover(messageHash, v, r, s) verification in recoverSigner.
* Do NOT use personal_sign or generic eth_signTypedData_v4; the contract uses
* abi.encodePacked for the version string and a custom META_TX_TYPE_HASH, so those produce
* incompatible hashes.
* The resulting digest is also written into the `message` field of the helper-built
* `MetaTransaction` structs (see `createMetaTransactionForSigning`) so integrators can use
* it directly without recomputing the hash client-side.
* Uses selective MetaTxRecord (txId, params, payment only) with standard EIP-712 type hashes
* so that eth_signTypedData_v4 (and equivalent) can reproduce the same digest when given
* matching domain + types:
*
* - primaryType: MetaTransaction
* - domain: { name: "Bloxchain", version: "1.0.0", chainId, verifyingContract }
* - types: MetaTransaction, MetaTxRecord, TxParams, MetaTxParams, PaymentDetails
*
* Integrators MAY:
* - use typed-data signing (eth_signTypedData_v4 / signTypedData) with the above domain/types, or
* - sign the resulting digest as a raw hash (e.g. account.sign({ hash: contractDigest })).
*
* In all cases, on-chain verification uses recoverSigner(messageHash, signature) which applies
* ecrecover(messageHash, v, r, s) with no personal_sign / EIP-191 prefix.
*
* The resulting digest is also written into the `message` field of helper-built `MetaTransaction`
* structs so integrators can use it directly without recomputing the hash client-side.
* @param metaTx The meta-transaction to generate the hash for
* @return The EIP-712 digest (no prefix; use standard recovery)
*/
function generateMessageHash(MetaTransaction memory metaTx) private view returns (bytes32) {
bytes32 domainSeparator = keccak256(abi.encode(
DOMAIN_SEPARATOR_TYPE_HASH,
PROTOCOL_NAME_HASH,
keccak256(abi.encodePacked(VERSION_MAJOR, ".", VERSION_MINOR, ".", VERSION_PATCH)),
block.chainid,
address(this)
));
bytes32 domainSeparator = keccak256(
abi.encode(
DOMAIN_SEPARATOR_TYPE_HASH,
PROTOCOL_NAME_HASH,
keccak256(bytes(VERSION)),
block.chainid,
address(this)
)
);

TxParams memory tp = metaTx.txRecord.params;
bytes32 txParamsStructHash = keccak256(abi.encode(
Expand Down Expand Up @@ -1769,11 +1793,20 @@ library EngineBlox {

/**
* @dev Recovers the signer from the EIP-712 digest and signature. Uses standard EIP-712 recovery (no message prefix).
* Integrators must sign the digest returned by generateMessageHash as a raw hash—e.g.
* account.sign({ hash: contractDigest }) or equivalent raw-hash signing API—with no
* EIP-191/personal prefix, so signatures match this ecrecover(messageHash, v, r, s) verification.
* Do NOT use personal_sign or generic eth_signTypedData_v4; the contract uses abi.encodePacked
* for the domain version and a custom META_TX_TYPE_HASH, so those produce incompatible hashes.
*
* Integrators have two equivalent options:
* - Use typed-data signing (eth_signTypedData_v4 / signTypedData) with:
* - primaryType: MetaTransaction
* - domain: { name: "Bloxchain", version: "1.0.0", chainId, verifyingContract }
* - types: MetaTransaction, MetaTxRecord, TxParams, MetaTxParams, PaymentDetails
* In this case the wallet computes the same digest as generateMessageHash and signs it.
* - Sign the digest returned by generateMessageHash as a raw hash—e.g.
* account.sign({ hash: contractDigest }) or equivalent raw-hash signing API—with no
* EIP-191/personal prefix.
*
* In all cases, this function applies ecrecover(messageHash, v, r, s) over the raw EIP-712 digest.
* personal_sign / EIP-191-prefixed signatures remain incompatible.
*
* @param messageHash The EIP-712 digest (keccak256("\x19\x01" || domainSeparator || structHash))
* @param signature The signature (r, s, v)
* @return The address of the signer
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Bloxchain",
"version": "1.0.0-alpha.17",
"version": "1.0.0-alpha.18",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n package.json | head -60

Repository: PracticalParticle/Bloxchain-Protocol

Length of output: 3961


Sync the npm dist-tags with this version bump.

The manifest is now 1.0.0-alpha.18, but publish:contracts and publish:sdk still publish under --tag alpha.17. That will push the new artifacts onto the old dist-tag and leave the release metadata inconsistent.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` at line 3, The npm dist-tags used in the publish scripts are
out of sync with the package version 1.0.0-alpha.18; update the publish commands
so the dist-tag passed to npm (references: the "publish:contracts" and
"publish:sdk" script entries in package.json) uses "alpha.18" (or derive from
the package.json version) instead of "alpha.17"; locate the "publish:contracts"
and "publish:sdk" script values and replace the "--tag alpha.17" token with
"--tag alpha.18" (or refactor to compute the tag from the version string) so
published artifacts and release metadata remain consistent.

"description": "Library engine for building enterprise grade decentralized permissioned applications",
"type": "module",
"main": "truffle-config.cjs",
Expand Down
2 changes: 1 addition & 1 deletion package/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bloxchain/contracts",
"version": "1.0.0-alpha.17",
"version": "1.0.0-alpha.18",
"description": "Library engine for building enterprise grade decentralized permissioned applications",
"files": [
"core",
Expand Down
71 changes: 29 additions & 42 deletions scripts/sync-versions.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const rootPackageJsonPath = path.join(rootDir, 'package.json');
const contractsPackageJsonPath = path.join(rootDir, 'package', 'package.json');
const sdkPackageJsonPath = path.join(rootDir, 'sdk', 'typescript', 'package.json');
const engineBloxPath = path.join(rootDir, 'contracts', 'core', 'lib', 'EngineBlox.sol');
const sdkEngineBloxPath = path.join(rootDir, 'sdk', 'typescript', 'lib', 'EngineBlox.tsx');

// Parse command line arguments for tag
let preReleaseTag = null;
Expand Down Expand Up @@ -140,52 +141,20 @@ if (fs.existsSync(engineBloxPath)) {
let engineBloxContent = fs.readFileSync(engineBloxPath, 'utf8');
let updated = false;

// Update VERSION_MAJOR (uses base version, no pre-release tag)
const majorRegex = /(uint8\s+public\s+constant\s+VERSION_MAJOR\s*=\s*)(\d+)/;
const majorMatch = engineBloxContent.match(majorRegex);
if (majorMatch) {
const oldMajor = parseInt(majorMatch[2], 10);
if (oldMajor !== versionMajor) {
engineBloxContent = engineBloxContent.replace(majorRegex, `$1${versionMajor}`);
// Update VERSION string (uses base version, no pre-release tag)
const versionRegex = /(string\s+public\s+constant\s+VERSION\s*=\s*)"([^"]*)"/;
const versionMatch = engineBloxContent.match(versionRegex);
if (versionMatch) {
const oldVersion = versionMatch[2];
if (oldVersion !== baseVersion) {
engineBloxContent = engineBloxContent.replace(versionRegex, `$1"${baseVersion}"`);
updated = true;
console.log(`✅ EngineBlox.sol VERSION_MAJOR: ${oldMajor}${versionMajor} (base version, no pre-release tag)`);
console.log(`✅ EngineBlox.sol VERSION: "${oldVersion}""${baseVersion}" (base version, no pre-release tag)`);
} else {
console.log(`✓ EngineBlox.sol VERSION_MAJOR: ${versionMajor} (already synced)`);
console.log(`✓ EngineBlox.sol VERSION: "${baseVersion}" (already synced)`);
}
} else {
console.warn('⚠️ Could not find VERSION_MAJOR constant in EngineBlox.sol');
}

// Update VERSION_MINOR (uses base version, no pre-release tag)
const minorRegex = /(uint8\s+public\s+constant\s+VERSION_MINOR\s*=\s*)(\d+)/;
const minorMatch = engineBloxContent.match(minorRegex);
if (minorMatch) {
const oldMinor = parseInt(minorMatch[2], 10);
if (oldMinor !== versionMinor) {
engineBloxContent = engineBloxContent.replace(minorRegex, `$1${versionMinor}`);
updated = true;
console.log(`✅ EngineBlox.sol VERSION_MINOR: ${oldMinor} → ${versionMinor} (base version, no pre-release tag)`);
} else {
console.log(`✓ EngineBlox.sol VERSION_MINOR: ${versionMinor} (already synced)`);
}
} else {
console.warn('⚠️ Could not find VERSION_MINOR constant in EngineBlox.sol');
}

// Update VERSION_PATCH (uses base version, no pre-release tag)
const patchRegex = /(uint8\s+public\s+constant\s+VERSION_PATCH\s*=\s*)(\d+)/;
const patchMatch = engineBloxContent.match(patchRegex);
if (patchMatch) {
const oldPatch = parseInt(patchMatch[2], 10);
if (oldPatch !== versionPatch) {
engineBloxContent = engineBloxContent.replace(patchRegex, `$1${versionPatch}`);
updated = true;
console.log(`✅ EngineBlox.sol VERSION_PATCH: ${oldPatch} → ${versionPatch} (base version, no pre-release tag)`);
} else {
console.log(`✓ EngineBlox.sol VERSION_PATCH: ${versionPatch} (already synced)`);
}
} else {
console.warn('⚠️ Could not find VERSION_PATCH constant in EngineBlox.sol');
console.warn('⚠️ Could not find VERSION constant in EngineBlox.sol');
}

if (updated) {
Expand All @@ -199,4 +168,22 @@ if (fs.existsSync(engineBloxPath)) {
console.warn('⚠️ EngineBlox.sol not found');
}

// Update SDK EngineBlox.tsx VERSION string (same as contract, base version only)
if (fs.existsSync(sdkEngineBloxPath)) {
let sdkContent = fs.readFileSync(sdkEngineBloxPath, 'utf8');
const sdkVersionRegex = /(static readonly VERSION: string = )"([^"]*)"/;
const sdkMatch = sdkContent.match(sdkVersionRegex);
if (sdkMatch && sdkMatch[2] !== baseVersion) {
sdkContent = sdkContent.replace(sdkVersionRegex, `$1"${baseVersion}"`);
fs.writeFileSync(sdkEngineBloxPath, sdkContent, 'utf8');
console.log(`✅ SDK EngineBlox.tsx VERSION: "${sdkMatch[2]}" → "${baseVersion}"`);
} else if (sdkMatch) {
console.log(`✓ SDK EngineBlox.tsx VERSION: "${baseVersion}" (already synced)`);
} else {
console.warn('⚠️ Could not find VERSION in SDK EngineBlox.tsx');
}
} else {
console.warn('⚠️ SDK EngineBlox.tsx not found');
}

console.log('\n✅ Version sync complete!');
32 changes: 3 additions & 29 deletions sdk/typescript/abi/EngineBlox.abi.json
Original file line number Diff line number Diff line change
Expand Up @@ -689,38 +689,12 @@
},
{
"inputs": [],
"name": "VERSION_MAJOR",
"name": "VERSION",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "VERSION_MINOR",
"outputs": [
{
"internalType": "uint8",
"internalType": "string",
"name": "",
"type": "uint8"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "VERSION_PATCH",
"outputs": [
{
"internalType": "uint8",
"name": "",
"type": "uint8"
"type": "string"
}
],
"stateMutability": "view",
Expand Down
16 changes: 3 additions & 13 deletions sdk/typescript/lib/EngineBlox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const keccak256 = (str: string): Hex => {
*
* // Access constants
* const protocolName = EngineBlox.PROTOCOL_NAME_HASH;
* const version = `${EngineBlox.VERSION_MAJOR}.${EngineBlox.VERSION_MINOR}.${EngineBlox.VERSION_PATCH}`;
* const version = EngineBlox.VERSION;
*
* // Use pure functions
* const signer = EngineBlox.recoverSigner(messageHash, signature);
Expand All @@ -41,19 +41,9 @@ export class EngineBlox {
static readonly PROTOCOL_NAME_HASH: Hex = keccak256("Bloxchain");

/**
* Major version number
* Protocol version string (semver, e.g. "1.0.0"). Matches EngineBlox.sol VERSION and EIP-712 domain version.
*/
static readonly VERSION_MAJOR: number = 1;

/**
* Minor version number
*/
static readonly VERSION_MINOR: number = 0;

/**
* Patch version number
*/
static readonly VERSION_PATCH: number = 0;
static readonly VERSION: string = "1.0.0";

// ============ FUNCTION SELECTORS ============

Expand Down
2 changes: 1 addition & 1 deletion sdk/typescript/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@bloxchain/sdk",
"version": "1.0.0-alpha.17",
"version": "1.0.0-alpha.18",
"description": "Library engine for building enterprise grade decentralized permissioned applications",
"type": "module",
"main": "./dist/index.js",
Expand Down
Loading