Skip to content

Comments

Dev#78

Merged
JaCoderX merged 8 commits intomainfrom
dev
Feb 17, 2026
Merged

Dev#78
JaCoderX merged 8 commits intomainfrom
dev

Conversation

@JaCoderX
Copy link
Member

@JaCoderX JaCoderX commented Feb 16, 2026

Summary by CodeRabbit

  • New Features

    • Unified account contract usage (AccountBlox) across sanity tests and SDK tooling; added optional account address and optional wallet keys to test config.
  • Bug Fixes

    • Prevented double-initialization in core components and added non-zero target validation.
    • Improved test robustness with defensive error handling and resilient transaction-status checks.
  • Refactor

    • Modularized internal role/guard/ownership config handling and consolidated logging helpers.
  • Documentation

    • Added Contract Configuration guidance for AccountBlox (duplicated in some READMEs).
  • Chores

    • Bumped package versions to v1.0.0-alpha.12.

…dress pair logging

This commit refactors the SecureOwnable contract by replacing instances of _logComponentEvent with a new internal function _logAddressPairEvent. This change reduces contract size and improves clarity by standardizing the logging of address pairs. The BaseStateMachine contract also removes unnecessary logging calls, further streamlining the code.
This commit refactors the RuntimeRBAC and GuardController contracts by consolidating role management actions into dedicated internal functions. The changes include the introduction of _executeCreateRole, _executeRemoveRole, _executeAddWallet, _executeRevokeWallet, _executeAddFunctionToRole, and _executeRemoveFunctionFromRole methods, which enhance code clarity and maintainability. Additionally, the initialization logic in BaseStateMachine and SecureOwnable has been simplified to ensure consistent behavior across components.
This commit modifies the sanity test scripts and configuration files to standardize the use of the AccountBlox contract. The ACCOUNTBLOX_ADDRESS environment variable is now required for all sanity tests, replacing previous references to SecureBlox and RoleBlox. Additionally, the truffle-config has been updated to accept dynamic network IDs, enhancing compatibility with various development environments. Documentation has also been updated to reflect these changes.
This commit updates the version numbers in package.json and related files to 1.0.0-alpha.12, reflecting the latest changes in the project. The release scripts have also been adjusted to ensure proper version synchronization for publishing, enhancing the overall release process.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 16, 2026

Warning

Rate limit exceeded

@JaCoderX has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 14 minutes and 55 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

Unifies batch-action handling into internal executor functions and centralized logging across core contracts, makes base-state initialization unconditional in some initializers, consolidates sanity tests to use a single AccountBlox contract (ACCOUNTBLOX_ADDRESS), hardens tests and tx/status handling, and bumps package versions to 1.0.0-alpha.12.

Changes

Cohort / File(s) Summary
Runtime RBAC & GuardController
contracts/core/access/RuntimeRBAC.sol, contracts/core/execution/GuardController.sol
Extracted inline batch decoding into dedicated internal executors (e.g., _executeCreateRole, _executeAddWallet, _executeRegisterFunction, etc.), replaced encoder helpers with _logRoleConfigEvent/_logGuardConfigEvent that call _logComponentEvent, and updated batch loops to call the new executors. Public/external signatures unchanged.
BaseStateMachine & SecureOwnable
contracts/core/base/BaseStateMachine.sol, contracts/core/security/SecureOwnable.sol
Changed base-state initialization logic to avoid double-init by guarding _initializeBaseStateMachine and also added paths that call it unconditionally from some initializers; removed some hook logging side-effects and introduced _logAddressPairEvent helper used for address-pair logs.
Whitelist validation & minor contract fixes
contracts/core/lib/EngineBlox.sol
Added non-zero target validation in removeTargetFromFunctionWhitelist.
Test infra — AccountBlox consolidation
scripts/sanity-sdk/base/test-config.ts, scripts/sanity-sdk/guard-controller/base-test.ts, scripts/sanity-sdk/runtime-rbac/base-test.ts, scripts/sanity-sdk/secure-ownable/base-test.ts, scripts/sanity/guard-controller/base-test.cjs, scripts/sanity/runtime-rbac/base-test.cjs, scripts/sanity/secure-ownable/base-test.cjs
Replaced RoleBlox/SecureBlox/GuardController references with unified AccountBlox; wired env/config to ACCOUNTBLOX_ADDRESS; added accountBlox config field and made privateKeys optional.
Sanity test robustness & flows
scripts/sanity-sdk/guard-controller/erc20-mint-controller-tests.ts, scripts/sanity-sdk/runtime-rbac/rbac-tests.ts, scripts/sanity/secure-ownable/broadcaster-update-tests.cjs, scripts/sanity/secure-ownable/ownership-transfer-tests.cjs
Added try/catch around selector/role checks, improved handling of ResourceAlreadyExists and revert messages, best-effort verification paths, refactored broadcaster selection to accept multiple current broadcasters, and normalized tx.status numeric checks with richer logging and small delays.
Docs & env example
scripts/sanity-sdk/README.md, scripts/sanity/README.md, env.example
Inserted "Contract Configuration" sections documenting AccountBlox usage and added ACCOUNTBLOX_ADDRESS to env example (duplicate README insertions present).
Foundry & Truffle config
test/foundry/invariant/RoleInvariants.t.sol, truffle-config.cjs, foundry.toml
Added fuzz-selector exclusions to invariants, set Truffle network_id to "*", increased solc optimizer runs 1→200, and suppressed specific compiler warnings; disabled lint on build.
Version bumps
package.json, package/package.json, sdk/typescript/package.json
Bumped versions from 1.0.0-alpha.111.0.0-alpha.12, updated publish tags and peer dependency references accordingly.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Work #77: Mirrors this PR’s refactor pattern—adds _execute* handlers and _log* helpers across RuntimeRBAC, GuardController, BaseStateMachine, and SecureOwnable.
  • Work2 #61: Overlaps changes to RuntimeRBAC role-config batch handling and internal logging/encoding logic.
  • Stable version #35: Related refactor introducing internal executors and centralized logging paths in RBAC and companion contracts.

Poem

🐰 I hopped through executors with glee,
AccountBlox now reigning free,
Logs trimmed neat, tests made stout,
Wallets checked, no panics out,
A rabbit winks—code's light and spry!

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The pull request title 'Dev' is vague and generic, providing no meaningful information about the changeset's actual content or purpose. Replace 'Dev' with a descriptive title that summarizes the main change, such as 'Refactor contract initialization and event logging to centralize state management' or 'Consolidate contract initialization guards and replace inline event logging'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
contracts/core/base/BaseStateMachine.sol (1)

298-310: ⚠️ Potential issue | 🔴 Critical

Add event emissions for hook configuration changes.

Hook additions and removals in _setHook / _clearHook (lines 298-310) do not emit events, making these critical state changes invisible to off-chain indexers and monitoring systems. Per the coding guidelines requiring events for all critical state changes, the functions should emit HookSet and HookCleared events (or similar). This aligns with the event-logging pattern used elsewhere in the codebase for state modifications (e.g., _logComponentEvent in GuardController, RuntimeRBAC, and SecureOwnable) and ensures hook configuration changes are observable off-chain.

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

In `@contracts/core/base/BaseStateMachine.sol` around lines 298 - 310, The
_setHook and _clearHook functions call EngineBlox.addTargetToFunctionHooks and
EngineBlox.removeTargetFromFunctionHooks but do not emit events, so add event
declarations (e.g., event HookSet(bytes4 indexed functionSelector, address
indexed hook, address indexed setter) and event HookCleared(bytes4 indexed
functionSelector, address indexed hook, address indexed clearer)) to the
contract and emit HookSet(functionSelector, hook, msg.sender) at the end of
_setHook and emit HookCleared(functionSelector, hook, msg.sender) at the end of
_clearHook so off-chain indexers can observe hook configuration changes.
🤖 Fix all issues with AI agents
Verify each finding against the current code and only fix it if needed.


In `@contracts/core/access/RuntimeRBAC.sol`:
- Around line 158-174: The ADD_WALLET/REVOKE_WALLET handlers (_executeAddWallet
and _executeRevokeWallet) currently call _logRoleConfigEvent with bytes4(0),
omitting the wallet address; update logging so the wallet is emitted: either
extend _logRoleConfigEvent to accept an extra address parameter and pass the
decoded wallet, or add a new helper (e.g., _logRoleConfigWalletEvent) that emits
(actionType, roleHash, wallet) and call it from
_executeAddWallet/_executeRevokeWallet for
IRuntimeRBAC.RoleConfigActionType.ADD_WALLET and REVOKE_WALLET respectively, and
update any event signatures/NatSpec accordingly.

In `@contracts/core/base/BaseStateMachine.sol`:
- Around line 298-310: The _setHook and _clearHook functions call
EngineBlox.addTargetToFunctionHooks and EngineBlox.removeTargetFromFunctionHooks
but do not emit events, so add event declarations (e.g., event HookSet(bytes4
indexed functionSelector, address indexed hook, address indexed setter) and
event HookCleared(bytes4 indexed functionSelector, address indexed hook, address
indexed clearer)) to the contract and emit HookSet(functionSelector, hook,
msg.sender) at the end of _setHook and emit HookCleared(functionSelector, hook,
msg.sender) at the end of _clearHook so off-chain indexers can observe hook
configuration changes.

In `@contracts/core/execution/GuardController.sol`:
- Around line 358-362: The _executeRemoveTargetFromWhitelist function currently
omits zero-address validation; update it to assert target != address(0) before
calling _removeTargetFromFunctionWhitelist by invoking the shared validation
helper (e.g., SharedValidation.validateNotZeroAddress(target)) or adding an
equivalent require, then proceed to call
_removeTargetFromFunctionWhitelist(functionSelector, target) and
_logGuardConfigEvent as before; this mirrors the protection used in
_executeAddTargetToWhitelist and prevents removing the zero address.

In `@package.json`:
- Around line 47-48: The two publish scripts (publish:contracts and publish:sdk)
hardcode "--tag alpha.12"; replace that with a tag derived from package.json's
prerelease identifier so it automatically follows version bumps. Update each
script to compute the tag from require('./package.json').version (e.g., extract
the part after the "-" or fallback to "latest") and use that value for npm
publish --tag; you can perform this inline in the script or delegate the value
from existing tasks like release:sync-versions or release:prepare so the publish
commands use the computed tag instead of the hardcoded "alpha.12".

In `@scripts/sanity-sdk/guard-controller/erc20-mint-controller-tests.ts`:
- Around line 344-372: The catch block for requestAndApproveExecution currently
masks real failures by always calling this.assertTest(true); change it to record
soft-failures (e.g., set a boolean/array like this.softFailures or
this.testResults.softFailures and push execError/details) and still allow the
individual test to continue, then at the end of the test run (or test file)
check that collection and fail the suite or call process.exit(1) /
this.assertTest(false, ...) if any soft-failures occurred; update the catch to
include execError metadata (execError?.message) in the recorded entry so CI can
surface actionable failures while keeping the local best-effort behavior during
the test body.

In `@scripts/sanity-sdk/runtime-rbac/base-test.ts`:
- Around line 122-123: The ABI override currently mutates (this.runtimeRBAC as
any).abi which bypasses typing and is not applied in
createRuntimeRBACWithWallet; update the code to consistently supply the
AccountBlox ABI to all RuntimeRBAC instances by either (A) passing
AccountBloxABIJson into the RuntimeRBAC constructor/factory (RuntimeRBAC(...))
if the class supports an abi parameter, or (B) centralizing the override inside
createRuntimeRBACWithWallet so it sets the instance ABI immediately after
creation (avoid using `as any` by using the proper typed property or a setter on
RuntimeRBAC); ensure both the existing this.runtimeRBAC initialization and
createRuntimeRBACWithWallet use the same mechanism so no RuntimeRBAC is left
with the incomplete default ABI.

In `@scripts/sanity-sdk/runtime-rbac/rbac-tests.ts`:
- Around line 217-228: The current error-handling in the create block uses
overly broad substring checks on msg (checking for 'revert' and 'Missing or
invalid') which can mask real failures; update the conditional around msg (and
the surrounding create flow that calls ensureRoleHasRequiredPermissions and uses
registryAdminRoleHash) to match only specific known error signatures (e.g.,
exact "ResourceAlreadyExists" or a more specific revert reason/regex returned by
your contract/library), prefer inspecting structured fields like error.code or
error.name if available, and when falling back to any broader match still emit a
distinct warning-level log that includes the full error and stack before
attempting ensureRoleHasRequiredPermissions so genuine issues aren’t silently
treated as "role exists."

In `@scripts/sanity/secure-ownable/broadcaster-update-tests.cjs`:
- Around line 271-272: Replace the brittle fixed 1500ms sleep with a
retry/polling loop that calls getTransaction until the returned transaction
status is no longer EXECUTING or PROCESSING_PAYMENT (use the same pattern as
createBroadcasterRequestAndDeriveTxId's retry logic), retrying with a short
delay and a max timeout; update the code around the await new
Promise(setTimeout...) to perform repeated getTransaction calls, break when the
status is terminal, and throw or fail if the max wait is exceeded to avoid
hanging tests.
- Around line 277-295: Extract the duplicated status parsing and revert-data
logging into a shared helper named extractAndValidateStatus(tx, txId) that
accepts the transaction object and an identifier string; inside it perform the
flexible status extraction (use tx.status or tx[2]), normalize to a Number
(handling BigNumber-like objects with toNumber), if statusNum === 6 extract
rawResult from tx.result or tx[5], format resultHex (handle string vs
Buffer/array via Buffer.from), log the first 200 chars and the 4-byte selector,
then return statusNum (or throw/assert if you prefer); replace the duplicated
blocks in both places (the block around statusVal/statusNum and the similar
block in testTimeDelayApproval) with calls to extractAndValidateStatus(tx, txId)
and use the returned statusNum in the existing this.assertTest checks so
on-chain failures are consistently logged.

In `@scripts/sanity/secure-ownable/ownership-transfer-tests.cjs`:
- Line 443: The transaction status comparisons are inconsistent: some checks use
string equality (e.g., tx.status === '1' or '4') while others use
Number(tx.status) === 5; convert all status checks to numeric coercion for
consistency by wrapping tx.status with Number() and comparing against numeric
literals (e.g., Number(tx.status) === 1, 4, 5) wherever tx.status is tested
(look for assertions using this.assertTest and any direct tx.status
comparisons), and update the fallback history scan logic that reads tx.status
(the scan around the fallback on line ~728) to use Number(tx.status) as well so
all branches use the same numeric comparison pattern.
- Around line 403-410: The metaTxParams assignment is misindented relative to
its surrounding try block; locate the call to
this.callContractMethod(this.contract.methods.createMetaTxParams(...)) that
assigns to metaTxParams in the test and realign its indentation to match the
rest of the block (same nesting as adjacent statements) so the assignment line
and its wrapped arguments (including createMetaTxParams,
getTxAction('SIGN_META_APPROVE'), and getRoleWalletObject('owner').address) have
consistent indentation with the surrounding try block.
🧹 Nitpick comments (6)
🤖 Fix all nitpicks with AI agents
Verify each finding against the current code and only fix it if needed.


In `@package.json`:
- Around line 47-48: The two publish scripts (publish:contracts and publish:sdk)
hardcode "--tag alpha.12"; replace that with a tag derived from package.json's
prerelease identifier so it automatically follows version bumps. Update each
script to compute the tag from require('./package.json').version (e.g., extract
the part after the "-" or fallback to "latest") and use that value for npm
publish --tag; you can perform this inline in the script or delegate the value
from existing tasks like release:sync-versions or release:prepare so the publish
commands use the computed tag instead of the hardcoded "alpha.12".

In `@scripts/sanity-sdk/guard-controller/erc20-mint-controller-tests.ts`:
- Around line 344-372: The catch block for requestAndApproveExecution currently
masks real failures by always calling this.assertTest(true); change it to record
soft-failures (e.g., set a boolean/array like this.softFailures or
this.testResults.softFailures and push execError/details) and still allow the
individual test to continue, then at the end of the test run (or test file)
check that collection and fail the suite or call process.exit(1) /
this.assertTest(false, ...) if any soft-failures occurred; update the catch to
include execError metadata (execError?.message) in the recorded entry so CI can
surface actionable failures while keeping the local best-effort behavior during
the test body.

In `@scripts/sanity-sdk/runtime-rbac/rbac-tests.ts`:
- Around line 217-228: The current error-handling in the create block uses
overly broad substring checks on msg (checking for 'revert' and 'Missing or
invalid') which can mask real failures; update the conditional around msg (and
the surrounding create flow that calls ensureRoleHasRequiredPermissions and uses
registryAdminRoleHash) to match only specific known error signatures (e.g.,
exact "ResourceAlreadyExists" or a more specific revert reason/regex returned by
your contract/library), prefer inspecting structured fields like error.code or
error.name if available, and when falling back to any broader match still emit a
distinct warning-level log that includes the full error and stack before
attempting ensureRoleHasRequiredPermissions so genuine issues aren’t silently
treated as "role exists."

In `@scripts/sanity/secure-ownable/broadcaster-update-tests.cjs`:
- Around line 271-272: Replace the brittle fixed 1500ms sleep with a
retry/polling loop that calls getTransaction until the returned transaction
status is no longer EXECUTING or PROCESSING_PAYMENT (use the same pattern as
createBroadcasterRequestAndDeriveTxId's retry logic), retrying with a short
delay and a max timeout; update the code around the await new
Promise(setTimeout...) to perform repeated getTransaction calls, break when the
status is terminal, and throw or fail if the max wait is exceeded to avoid
hanging tests.
- Around line 277-295: Extract the duplicated status parsing and revert-data
logging into a shared helper named extractAndValidateStatus(tx, txId) that
accepts the transaction object and an identifier string; inside it perform the
flexible status extraction (use tx.status or tx[2]), normalize to a Number
(handling BigNumber-like objects with toNumber), if statusNum === 6 extract
rawResult from tx.result or tx[5], format resultHex (handle string vs
Buffer/array via Buffer.from), log the first 200 chars and the 4-byte selector,
then return statusNum (or throw/assert if you prefer); replace the duplicated
blocks in both places (the block around statusVal/statusNum and the similar
block in testTimeDelayApproval) with calls to extractAndValidateStatus(tx, txId)
and use the returned statusNum in the existing this.assertTest checks so
on-chain failures are consistently logged.

In `@scripts/sanity/secure-ownable/ownership-transfer-tests.cjs`:
- Around line 403-410: The metaTxParams assignment is misindented relative to
its surrounding try block; locate the call to
this.callContractMethod(this.contract.methods.createMetaTxParams(...)) that
assigns to metaTxParams in the test and realign its indentation to match the
rest of the block (same nesting as adjacent statements) so the assignment line
and its wrapped arguments (including createMetaTxParams,
getTxAction('SIGN_META_APPROVE'), and getRoleWalletObject('owner').address) have
consistent indentation with the surrounding try block.
package.json (1)

47-48: Consider deriving the publish tag from the version field to avoid manual updates.

The --tag alpha.12 strings are hardcoded and must be manually bumped alongside the version on every release. A small helper (or inline shell expansion) that extracts the prerelease identifier from version would eliminate this synchronization chore and prevent accidental mismatches.

For example:

-    "publish:contracts": "npm run release:prepare && cd package && npm publish --tag alpha.12",
-    "publish:sdk": "npm run release:sync-versions && npm run extract-abi && npm run build:sdk && cd sdk/typescript && npm publish --tag alpha.12",
+    "publish:contracts": "npm run release:prepare && cd package && npm publish --tag $(node -p \"require('./package.json').version.split('-')[1]?.split('.')[0] || 'latest'\")",
+    "publish:sdk": "npm run release:sync-versions && npm run extract-abi && npm run build:sdk && cd sdk/typescript && npm publish --tag $(node -p \"require('../../package.json').version.split('-')[1]?.split('.')[0] || 'latest'\")",

Or delegate to release:sync-versions / release:prepare to also patch publish tags.

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

In `@package.json` around lines 47 - 48, The two publish scripts
(publish:contracts and publish:sdk) hardcode "--tag alpha.12"; replace that with
a tag derived from package.json's prerelease identifier so it automatically
follows version bumps. Update each script to compute the tag from
require('./package.json').version (e.g., extract the part after the "-" or
fallback to "latest") and use that value for npm publish --tag; you can perform
this inline in the script or delegate the value from existing tasks like
release:sync-versions or release:prepare so the publish commands use the
computed tag instead of the hardcoded "alpha.12".
scripts/sanity/secure-ownable/ownership-transfer-tests.cjs (1)

403-410: Indentation is misaligned with the surrounding block.

The metaTxParams assignment (lines 403-410) drops to a shallower indent compared to the rest of the try block. Likely a copy-paste artifact.

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

In `@scripts/sanity/secure-ownable/ownership-transfer-tests.cjs` around lines 403
- 410, The metaTxParams assignment is misindented relative to its surrounding
try block; locate the call to
this.callContractMethod(this.contract.methods.createMetaTxParams(...)) that
assigns to metaTxParams in the test and realign its indentation to match the
rest of the block (same nesting as adjacent statements) so the assignment line
and its wrapped arguments (including createMetaTxParams,
getTxAction('SIGN_META_APPROVE'), and getRoleWalletObject('owner').address) have
consistent indentation with the surrounding try block.
scripts/sanity/secure-ownable/broadcaster-update-tests.cjs (2)

271-272: Arbitrary setTimeout delay is fragile.

A fixed 1500ms sleep to "allow state to settle" is unreliable — it may be too short on slow nodes or unnecessarily slow elsewhere. Consider polling getTransaction in a retry loop (similar to the pattern already used in createBroadcasterRequestAndDeriveTxId at lines 398–405) until the status transitions from EXECUTING/PROCESSING_PAYMENT to a terminal state.

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

In `@scripts/sanity/secure-ownable/broadcaster-update-tests.cjs` around lines 271
- 272, Replace the brittle fixed 1500ms sleep with a retry/polling loop that
calls getTransaction until the returned transaction status is no longer
EXECUTING or PROCESSING_PAYMENT (use the same pattern as
createBroadcasterRequestAndDeriveTxId's retry logic), retrying with a short
delay and a max timeout; update the code around the await new
Promise(setTimeout...) to perform repeated getTransaction calls, break when the
status is terminal, and throw or fail if the max wait is exceeded to avoid
hanging tests.

277-295: Duplicated status-extraction logic — extract a helper.

The status parsing (lines 277–279) is repeated almost identically at lines 357–359, but the revert-data logging (lines 281–289) is only present here. This inconsistency means testTimeDelayApproval silently swallows on-chain failures without any diagnostic output. Extract a shared method (e.g., extractAndValidateStatus(tx, txId)) that encapsulates both the flexible status extraction and the revert-data logging.

♻️ Sketch of a shared helper
+    /**
+     * Extract numeric status from a transaction record and log revert data if FAILED.
+     */
+    parseTransactionStatus(tx) {
+        const statusVal = tx.status !== undefined ? tx.status : tx[2];
+        const statusNum = typeof statusVal === 'object' && statusVal != null && typeof statusVal.toNumber === 'function'
+            ? statusVal.toNumber() : Number(statusVal);
+        if (statusNum === 6) {
+            const rawResult = tx.result !== undefined ? tx.result : tx[5];
+            if (rawResult) {
+                const resultHex = typeof rawResult === 'string' ? rawResult : (rawResult.length && typeof rawResult.slice === 'function') ? '0x' + Buffer.from(rawResult).toString('hex') : '0x';
+                const errorSelector = resultHex.length >= 10 ? resultHex.slice(0, 10) : resultHex;
+                console.log(`  📋 Revert data (first 200 chars): ${resultHex.slice(0, 200)}`);
+                console.log(`  📋 Error selector: ${errorSelector}`);
+            }
+        }
+        return statusNum;
+    }

Then in both test methods:

-            const statusVal = tx.status !== undefined ? tx.status : tx[2];
-            const statusNum = typeof statusVal === 'object' ...
+            const statusNum = this.parseTransactionStatus(tx);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/sanity/secure-ownable/broadcaster-update-tests.cjs` around lines 277
- 295, Extract the duplicated status parsing and revert-data logging into a
shared helper named extractAndValidateStatus(tx, txId) that accepts the
transaction object and an identifier string; inside it perform the flexible
status extraction (use tx.status or tx[2]), normalize to a Number (handling
BigNumber-like objects with toNumber), if statusNum === 6 extract rawResult from
tx.result or tx[5], format resultHex (handle string vs Buffer/array via
Buffer.from), log the first 200 chars and the 4-byte selector, then return
statusNum (or throw/assert if you prefer); replace the duplicated blocks in both
places (the block around statusVal/statusNum and the similar block in
testTimeDelayApproval) with calls to extractAndValidateStatus(tx, txId) and use
the returned statusNum in the existing this.assertTest checks so on-chain
failures are consistently logged.
scripts/sanity-sdk/runtime-rbac/rbac-tests.ts (1)

217-228: Broad error matching may mask genuine failures.

The check on line 219 matches 'revert' and 'Missing or invalid', which are very generic substrings. Any unrelated revert error would be swallowed and treated as "role already exists," potentially hiding real issues during test development. Consider tightening to more specific patterns, or at minimum logging a warning when falling through the broader matchers.

That said, since this is test-harness recovery code and subsequent steps will fail if assumptions are wrong, the risk is limited.

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

In `@scripts/sanity-sdk/runtime-rbac/rbac-tests.ts` around lines 217 - 228, The
current error-handling in the create block uses overly broad substring checks on
msg (checking for 'revert' and 'Missing or invalid') which can mask real
failures; update the conditional around msg (and the surrounding create flow
that calls ensureRoleHasRequiredPermissions and uses registryAdminRoleHash) to
match only specific known error signatures (e.g., exact "ResourceAlreadyExists"
or a more specific revert reason/regex returned by your contract/library),
prefer inspecting structured fields like error.code or error.name if available,
and when falling back to any broader match still emit a distinct warning-level
log that includes the full error and stack before attempting
ensureRoleHasRequiredPermissions so genuine issues aren’t silently treated as
"role exists."
scripts/sanity-sdk/guard-controller/erc20-mint-controller-tests.ts (1)

344-372: Soft-failure on mint execution undermines test signal.

When requestAndApproveExecution reverts, the test logs a warning but calls this.assertTest(true, ...), effectively masking a real failure. If the SDK wrapper itself has a bug, this test will never catch it. Consider at minimum tracking soft-failures in a summary or emitting a non-zero exit code when they occur, so CI doesn't silently pass broken flows.

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

In `@scripts/sanity-sdk/guard-controller/erc20-mint-controller-tests.ts` around
lines 344 - 372, The catch block for requestAndApproveExecution currently masks
real failures by always calling this.assertTest(true); change it to record
soft-failures (e.g., set a boolean/array like this.softFailures or
this.testResults.softFailures and push execError/details) and still allow the
individual test to continue, then at the end of the test run (or test file)
check that collection and fail the suite or call process.exit(1) /
this.assertTest(false, ...) if any soft-failures occurred; update the catch to
include execError metadata (execError?.message) in the recorded entry so CI can
surface actionable failures while keeping the local best-effort behavior during
the test body.

Comment on lines +122 to +123
// Override the ABI to use AccountBlox ABI which includes all RuntimeRBAC + GuardController + SecureOwnable functions
(this.runtimeRBAC as any).abi = AccountBloxABIJson;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

ABI override via as any is fragile and incomplete.

(this.runtimeRBAC as any).abi bypasses type safety and relies on the SDK class's internal property name. More importantly, createRuntimeRBACWithWallet (line 188-200) does not apply this same override, so any RuntimeRBAC instance created through that helper will use the default (incomplete) ABI, potentially causing silent failures when calling AccountBlox-specific functions.

Consider either:

  • Applying the override in createRuntimeRBACWithWallet as well, or
  • Passing a custom ABI through the RuntimeRBAC constructor if the SDK supports it.
#!/bin/bash
# Check if RuntimeRBAC class constructor or factory supports an ABI parameter
ast-grep --pattern 'class RuntimeRBAC {
  $$$
  constructor($$$) {
    $$$
  }
  $$$
}'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/sanity-sdk/runtime-rbac/base-test.ts` around lines 122 - 123, The ABI
override currently mutates (this.runtimeRBAC as any).abi which bypasses typing
and is not applied in createRuntimeRBACWithWallet; update the code to
consistently supply the AccountBlox ABI to all RuntimeRBAC instances by either
(A) passing AccountBloxABIJson into the RuntimeRBAC constructor/factory
(RuntimeRBAC(...)) if the class supports an abi parameter, or (B) centralizing
the override inside createRuntimeRBACWithWallet so it sets the instance ABI
immediately after creation (avoid using `as any` by using the proper typed
property or a setter on RuntimeRBAC); ensure both the existing this.runtimeRBAC
initialization and createRuntimeRBACWithWallet use the same mechanism so no
RuntimeRBAC is left with the incomplete default ABI.

// TxStatus enum: 0=UNDEFINED, 1=PENDING, 2=EXECUTING, 3=PROCESSING_PAYMENT, 4=CANCELLED, 5=COMPLETED, 6=FAILED, 7=REJECTED
const tx = await this.callContractMethod(this.contract.methods.getTransaction(txRecord.txId), this.getRoleWalletObject('recovery'));
this.assertTest(tx.status === '5', 'Transaction completed successfully');
this.assertTest(Number(tx.status) === 5, 'Transaction completed successfully');
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent status comparison pattern — apply Number() coercion uniformly or not at all.

Lines 443 and 661 now use Number(tx.status) === 5, but every other status check in this file still uses string comparison (e.g., tx.status === '1' on lines 98, 225, 343, 573 and tx.status === '4' on lines 196, 314). If the return type of getTransaction().status can vary (string vs. number/BigInt), the string comparisons elsewhere will silently pass or fail incorrectly under the same conditions that motivated this change.

Pick one approach and apply it consistently. Using Number() everywhere is the safer option:

Proposed fix (representative — apply to all similar lines)
-            this.assertTest(tx.status === '1', 'Transaction is pending');
+            this.assertTest(Number(tx.status) === 1, 'Transaction is pending');
-            this.assertTest(tx.status === '4', 'Transaction cancelled successfully');
+            this.assertTest(Number(tx.status) === 4, 'Transaction cancelled successfully');

Also update the fallback history scan on line 728:

-                if (rec && rec.status === '1' && rec.params && rec.params.operationType &&
+                if (rec && Number(rec.status) === 1 && rec.params && rec.params.operationType &&

Also applies to: 661-661

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

In `@scripts/sanity/secure-ownable/ownership-transfer-tests.cjs` at line 443, The
transaction status comparisons are inconsistent: some checks use string equality
(e.g., tx.status === '1' or '4') while others use Number(tx.status) === 5;
convert all status checks to numeric coercion for consistency by wrapping
tx.status with Number() and comparing against numeric literals (e.g.,
Number(tx.status) === 1, 4, 5) wherever tx.status is tested (look for assertions
using this.assertTest and any direct tx.status comparisons), and update the
fallback history scan logic that reads tx.status (the scan around the fallback
on line ~728) to use Number(tx.status) as well so all branches use the same
numeric comparison pattern.

This commit updates the foundry.toml file to suppress common compiler warnings and disables linting during the build process for cleaner output. Additionally, it modifies the truffle-config to optimize the Solidity compiler settings by increasing the optimization runs to 200. In the RuntimeRBAC contract, the logging functions are updated to include the wallet address in role configuration events, improving traceability and clarity in role management actions.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@contracts/core/access/RuntimeRBAC.sol`:
- Around line 148-152: The _executeRemoveRole function is missing the protection
check that prevents removing protected roles; add a call to
_requireRoleNotProtected(roleHash) at the start of _executeRemoveRole (before
calling _removeRole and _logRoleConfigEvent) so removals of
OWNER/BROADCASTER/RECOVERY (and any other protected roles enforced by
_requireRoleNotProtected) are blocked in batch operations; locate
_executeRemoveRole, insert the same _requireRoleNotProtected(roleHash) guard
used in _executeAddWallet and _executeRevokeWallet.

In `@foundry.toml`:
- Around line 32-35: The ignored_error_codes entry currently masks Solidity
shadowing warnings (2519); remove 2519 from the ignored_error_codes array so the
compiler surfaces variable-shadowing issues (update the ignored_error_codes
symbol to exclude 2519), then run the build/tests and fix any shadowing
instances (rename locals, use explicit storage/visibility, or refactor) until no
2519 warnings remain. If you cannot immediately fix all cases, revert the change
but add a TODO comment next to ignored_error_codes referencing a tracking issue
(create an issue and include its ID) that lists all shadowing occurrences to be
resolved and a milestone to re-enable the 2519 check.

---

Duplicate comments:
In `@contracts/core/access/RuntimeRBAC.sol`:
- Around line 158-174: The event logging concern is resolved: both
_executeAddWallet and _executeRevokeWallet now pass the wallet into
_logRoleConfigEvent, so no code change is required here; just verify that the
_logRoleConfigEvent implementation accepts and records the wallet parameter
correctly and add/update unit/integration tests for _executeAddWallet and
_executeRevokeWallet to assert the emitted RoleConfig event contains the
expected wallet value.

Comment on lines +148 to +152
function _executeRemoveRole(bytes calldata data) internal {
(bytes32 roleHash) = abi.decode(data, (bytes32));
_removeRole(roleHash);
_logRoleConfigEvent(IRuntimeRBAC.RoleConfigActionType.REMOVE_ROLE, roleHash, bytes4(0), address(0));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -name "RuntimeRBAC.sol" -type f

Repository: PracticalParticle/Bloxchain-Protocol

Length of output: 119


🏁 Script executed:

cat -n contracts/core/access/RuntimeRBAC.sol | head -200

Repository: PracticalParticle/Bloxchain-Protocol

Length of output: 10157


🏁 Script executed:

rg -n "_requireRoleNotProtected" -A 5 --type sol -B 2

Repository: PracticalParticle/Bloxchain-Protocol

Length of output: 107


🏁 Script executed:

rg -n "_removeRole" -A 10 --type sol

Repository: PracticalParticle/Bloxchain-Protocol

Length of output: 107


🏁 Script executed:

rg -n "_removeRole" -g "*.sol" -A 10 -B 2

Repository: PracticalParticle/Bloxchain-Protocol

Length of output: 2397


🏁 Script executed:

rg -n "isProtected" -g "*.sol" -B 2 -A 2 | head -100

Repository: PracticalParticle/Bloxchain-Protocol

Length of output: 8584


🏁 Script executed:

rg -n "OWNER|BROADCASTER|RECOVERY" -g "*.sol" -B 1 -A 1 | head -80

Repository: PracticalParticle/Bloxchain-Protocol

Length of output: 5623


Add missing _requireRoleNotProtected check in _executeRemoveRole.

_executeAddWallet and _executeRevokeWallet both guard against modifying protected roles via _requireRoleNotProtected, but _executeRemoveRole is missing this check. This allows removing protected roles (OWNER, BROADCASTER, RECOVERY) through batch operations, bypassing the design intent stated in the function's docstring and creating a critical access-control vulnerability.

Proposed fix
     function _executeRemoveRole(bytes calldata data) internal {
         (bytes32 roleHash) = abi.decode(data, (bytes32));
+        _requireRoleNotProtected(roleHash);
         _removeRole(roleHash);
         _logRoleConfigEvent(IRuntimeRBAC.RoleConfigActionType.REMOVE_ROLE, roleHash, bytes4(0), address(0));
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function _executeRemoveRole(bytes calldata data) internal {
(bytes32 roleHash) = abi.decode(data, (bytes32));
_removeRole(roleHash);
_logRoleConfigEvent(IRuntimeRBAC.RoleConfigActionType.REMOVE_ROLE, roleHash, bytes4(0), address(0));
}
function _executeRemoveRole(bytes calldata data) internal {
(bytes32 roleHash) = abi.decode(data, (bytes32));
_requireRoleNotProtected(roleHash);
_removeRole(roleHash);
_logRoleConfigEvent(IRuntimeRBAC.RoleConfigActionType.REMOVE_ROLE, roleHash, bytes4(0), address(0));
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@contracts/core/access/RuntimeRBAC.sol` around lines 148 - 152, The
_executeRemoveRole function is missing the protection check that prevents
removing protected roles; add a call to _requireRoleNotProtected(roleHash) at
the start of _executeRemoveRole (before calling _removeRole and
_logRoleConfigEvent) so removals of OWNER/BROADCASTER/RECOVERY (and any other
protected roles enforced by _requireRoleNotProtected) are blocked in batch
operations; locate _executeRemoveRole, insert the same
_requireRoleNotProtected(roleHash) guard used in _executeAddWallet and
_executeRevokeWallet.

This commit modifies the foundry.toml file to clarify the handling of compiler warnings by explicitly stating that shadowing (code 2519) is not suppressed, ensuring that variable-shadowing issues are surfaced. The list of ignored error codes has been updated accordingly for better clarity in the build process.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@foundry.toml`:
- Around line 32-36: The ignored_error_codes array (ignored_error_codes) and
remappings setting are placed under the [invariant] section and therefore won’t
be applied; move both ignored_error_codes and remappings into the
[profile.default] section (i.e., cut the ignored_error_codes block and the
remappings entry from under [invariant] and paste them under [profile.default]
above the [fuzz] section), and then remove their originals from [invariant] so
the TOML parser applies these profile-level settings correctly.

foundry.toml Outdated
Comment on lines 32 to 36

# Suppress common compiler warnings (lint-style) so build output is clean
# Shadowing (2519) is NOT suppressed so the compiler surfaces variable-shadowing issues.
# Codes: 2072=unused-var, 5667=unused-param, 2018=func-mutability, 1878=license, 2462=constructor-visibility, 3628=missing-receive-ether, 6321=unnamed-return
ignored_error_codes = [2072, 5667, 2018, 1878, 2462, 3628, 6321]
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, check if foundry.toml exists and read it
if [ -f foundry.toml ]; then
    echo "=== Full foundry.toml content ==="
    cat -n foundry.toml
    echo ""
    echo "=== Parsing TOML structure ==="
    pip install toml -q 2>/dev/null
    python3 << 'EOF'
import toml
import json

with open('foundry.toml') as f:
    data = toml.load(f)

print("Full parsed structure:")
print(json.dumps(data, indent=2))

print("\n=== Section Analysis ===")
if 'invariant' in data:
    print(f"Keys in [invariant]: {list(data['invariant'].keys())}")
    
if 'profile' in data and 'default' in data['profile']:
    profile_default = data['profile']['default']
    print(f"Keys in [profile.default]: {list(profile_default.keys())}")
    
    if 'invariant' in profile_default:
        print(f"  Keys in [profile.default.invariant]: {list(profile_default['invariant'].keys())}")
    if 'fuzz' in profile_default:
        print(f"  Keys in [profile.default.fuzz]: {list(profile_default['fuzz'].keys())}")

if 'lint' in data:
    print(f"Keys in [lint]: {list(data['lint'].keys())}")
if 'profile' in data and 'default' in data['profile'] and 'lint' in data['profile']['default']:
    print(f"Keys in [profile.default.lint]: {list(data['profile']['default']['lint'].keys())}")

print("\n=== Checking for ignored_error_codes location ===")
for section, content in data.items():
    if isinstance(content, dict) and 'ignored_error_codes' in content:
        print(f"Found 'ignored_error_codes' in section: [{section}]")
        print(f"  Value: {content['ignored_error_codes']}")
EOF
else
    echo "foundry.toml not found"
fi

Repository: PracticalParticle/Bloxchain-Protocol

Length of output: 2846


ignored_error_codes is under the wrong section and will not take effect.

The TOML structure shows ignored_error_codes (line 36) is parsed as part of the [invariant] section, not [profile.default]. Compiler error code suppression is a profile-level setting and must appear under [profile.default] to work correctly. In its current position, it will be ignored.

Move ignored_error_codes and its comments above the [fuzz] section:

Suggested fix
 evm_version = "osaka"
 
+# Suppress common compiler warnings (lint-style) so build output is clean
+# Shadowing (2519) is NOT suppressed so the compiler surfaces variable-shadowing issues.
+# Codes: 2072=unused-var, 5667=unused-param, 2018=func-mutability, 1878=license, 2462=constructor-visibility, 3628=missing-receive-ether, 6321=unnamed-return
+ignored_error_codes = [2072, 5667, 2018, 1878, 2462, 3628, 6321]
+
 # Remappings for OpenZeppelin dependencies
 remappings = [
     "@openzeppelin/=node_modules/@openzeppelin/",
     "forge-std/=lib/forge-std/src/",
 ]
 
 # Fuzzing configuration
 [fuzz]

Then remove lines 33–36 from their current location under [invariant].

Note: remappings (line 28) has the same placement issue—it is also under [invariant] instead of [profile.default]. Consider relocating it as well.

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

In `@foundry.toml` around lines 32 - 36, The ignored_error_codes array
(ignored_error_codes) and remappings setting are placed under the [invariant]
section and therefore won’t be applied; move both ignored_error_codes and
remappings into the [profile.default] section (i.e., cut the ignored_error_codes
block and the remappings entry from under [invariant] and paste them under
[profile.default] above the [fuzz] section), and then remove their originals
from [invariant] so the TOML parser applies these profile-level settings
correctly.

… suppression

This commit modifies the foundry.toml file to reintroduce remappings for OpenZeppelin dependencies and suppress common compiler warnings for a cleaner build output. The list of ignored error codes has been clarified, ensuring that variable-shadowing issues are still surfaced while improving overall build clarity.
@JaCoderX JaCoderX merged commit 49cf8d3 into main Feb 17, 2026
3 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Feb 22, 2026
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant