-
Notifications
You must be signed in to change notification settings - Fork 8
Solana triggers - DO NOT MERGE #190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…ployDment scripts
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (9)
Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughAdds Solana integration: new ForwarderSolana, Borsh encoder/decoder/utils, Solana payload types/constants, Solana-aware digest path in WritePrecompile, ERC20-based SUSDC credits and plugs, many interface/signature changes, extensive test suites and deployment/config updates across toolchains. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Forwarder as ForwarderSolana
participant Resolver as AddressResolver
participant AG as IAppGateway
participant Watcher
rect rgba(230,245,255,0.5)
note over User,Forwarder: ForwarderSolana synchronous enqueue flow
User->>Forwarder: callSolana(solanaPayload, target)
Forwarder->>Resolver: addressResolver__()
alt Resolver not set
Forwarder-->>User: revert AddressResolverNotSet()
else Resolver returns
Resolver-->>Forwarder: resolverAddr
Forwarder->>AG: check AsyncModifier / getOverrideParams()
alt AsyncModifier missing
Forwarder-->>User: revert AsyncModifierNotSet()
else
AG-->>Forwarder: overrideParams, switchboardType
Forwarder->>Watcher: watcher.queue(queueParams, msg.sender)
Watcher-->>Forwarder: queuedRequestId
Forwarder-->>User: return queuedRequestId
end
end
end
sequenceDiagram
autonumber
participant WP as WritePrecompile
participant BEnc as BorshEncoder
participant EVM as EvmDigestBuilder
rect rgba(240,255,240,0.5)
note right of WP: digest path selection by chainSlug
WP->>WP: _isSolanaChainSlug(chainSlug)
alt Solana chain
WP->>BEnc: encodeFunctionArgs(instruction)
BEnc-->>WP: borshEncodedArgs
WP->>WP: _createSolanaDigestParams(..., borshEncodedArgs)
else EVM-like chain
WP->>EVM: _createEvmDigestParams(...)
end
WP->>WP: compute keccak256(abi.encodePacked(...)) -> digest
WP-->>Caller: store digest / emit WriteProofRequested
end
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Suggested reviewers
Pre-merge checks (2 passed, 1 warning)❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Poem
Pre-merge checks (2 passed, 1 warning)❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Poem
Pre-merge checks (2 passed, 1 warning)❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Poem
Pre-merge checks (2 passed, 1 warning)❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 23
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (6)
hardhat.config.ts (1)
35-43
: Prevent invalid account key (“0xundefined”) and drop unsafe type-cast.Env is optional right now; the current cast to HardhatNetworkAccountUserConfig and blind "0x" prefixing can yield bad keys. This should sanitize and avoid accidental bad config.
-const privateKey: HardhatNetworkAccountUserConfig = process.env - .SOCKET_SIGNER_KEY as unknown as HardhatNetworkAccountUserConfig; +const rawSignerKey = process.env.SOCKET_SIGNER_KEY || ""; +const signerKey = rawSignerKey.startsWith("0x") ? rawSignerKey : (rawSignerKey ? `0x${rawSignerKey}` : ""); function getChainConfig(chainSlug: ChainSlug): NetworkUserConfig { return { - accounts: [`0x${privateKey}`], + accounts: signerKey ? [signerKey] : [], chainId: ChainSlugToId[chainSlug], url: getJsonRpcUrl(chainSlug), }; }Optionally re-enable the missing-key guard once setup scripts are fixed.
foundry.toml (2)
1-11
: Match Foundry IR pipeline with HardhatFoundry’s config (foundry.toml line 10) sets
via_ir = false
, while Hardhat’s config (hardhat.config.ts line 177) usesviaIR: true
. This mismatch causes divergent bytecode outputs. This should be aligned to guarantee identical runtime bytecode.– In foundry.toml (line 10):
-via_ir = false +via_ir = true– Reference in hardhat.config.ts (line 177):
viaIR: true,This should be validated by rebuilding with Foundry and Hardhat and diffing the ForwarderSolana/WritePrecompile bytecode for parity.
12-39
: Fix hardcoded ForwarderSolana address in deploy scriptThe forwarderSolanaAddress is still hardcoded in script/super-token-solana/DeployEVMSolanaApps.s.sol, which will drift if labels change. This should be replaced with the label lookup from foundry.toml to guarantee consistency.
• script/super-token-solana/DeployEVMSolanaApps.s.sol (line 26):
- address forwarderSolanaAddress = 0xC570206ACBa112fC8d438235BF8cE31b3548aa96; + address forwarderSolanaAddress = vm.label("ForwarderSolana");No other occurrences of APP_GATEWAY, WritePrecompile or Watcher remain hardcoded outside foundry.toml.
hardhat-scripts/deploy/3.configureChains.ts (1)
90-92
: Guard against missing FeesPlug; current code will throw when undefined.
toBytes32FormatHexString(chainAddresses[Contracts.FeesPlug]!)
will crash if FeesPlug is not deployed on a chain. ComputefeesPlug
only when present.Apply:
- const feesPlug = toBytes32FormatHexString( - chainAddresses[Contracts.FeesPlug]! - ); + const feesPlug = + chainAddresses[Contracts.FeesPlug] + ? toBytes32FormatHexString(chainAddresses[Contracts.FeesPlug] as string) + : undefined;hardhat-scripts/deploy/1.deploy.ts (1)
93-95
: Await getWatcherSigner here for consistency and correctness.Else
signer.address
will throw ifgetWatcherSigner
is async (it is awaited elsewhere in this file).Apply:
- const signer: Wallet = getWatcherSigner(); + const signer: Wallet = await getWatcherSigner();contracts/evmx/watcher/precompiles/WritePrecompile.sol (1)
372-379
: Docstring contradicts access control.Comment says “Only callable by the contract owner” but function is onlyWatcher. Fix comment or modifier.
- /// @dev Only callable by the contract owner + /// @dev Only callable by the watcher - function setExpiryTime(uint256 expiryTime_) external onlyWatcher { + function setExpiryTime(uint256 expiryTime_) external onlyWatcher {If the intent is owner control, switch to onlyOwner instead.
🧹 Nitpick comments (26)
contracts/evmx/watcher/borsh-serde/BorshUtils.sol (1)
98-124
: Require closing bracket when parsing array length.Currently, “[u8; 32 foo” would pass because only semicolon+digits are required. This should track ‘]’ to avoid false positives.
- function extractArrayLength(string memory typeName) internal pure returns (uint256) { + function extractArrayLength(string memory typeName) internal pure returns (uint256) { bytes memory typeBytes = bytes(typeName); uint256 length = 0; bool foundSemicolon = false; bool foundDigit = false; + bool foundClosingBracket = false; // Parse patterns like "[u8; 32]" for (uint256 i = 0; i < typeBytes.length; i++) { bytes1 char = typeBytes[i]; if (char == 0x3B) { // ';' foundSemicolon = true; } else if (foundSemicolon && char >= 0x30 && char <= 0x39) { // '0' to '9' foundDigit = true; length = length * 10 + uint256(uint8(char)) - 48; // Convert ASCII to number - } else if (foundSemicolon && foundDigit && char == 0x5D) { // ']' - break; // End of array type declaration + } else if (foundSemicolon && foundDigit && char == 0x5D) { // ']' + foundClosingBracket = true; + break; // End of array type declaration } else if (foundSemicolon && foundDigit && char != 0x20) { // Not a space // If we found digits but hit a non-digit non-space, invalid format revert("Invalid array length format"); } // Skip spaces and other characters before semicolon } - require(foundSemicolon && foundDigit && length > 0, "Could not extract array length"); + require(foundSemicolon && foundDigit && foundClosingBracket && length > 0, "Could not extract array length"); return length; }contracts/utils/common/Structs.sol (1)
239-249
: Document invariants for SolanaReadRequest.When schemaType=PREDEFINED, predefinedSchemaNameHash must be nonzero; when GENERIC, it should be zero. This should be documented and enforced at use-site to avoid ambiguous decoding.
test/DigestTest.t.sol (1)
84-86
: Add CI cross-check to lock test’s getDigest to the canonical implementationThe test in test/DigestTest.t.sol (lines 84–86) currently calls its own local getDigest and compares it against a hard-coded expectedDigest. This only verifies the test’s copy of the logic—not the canonical function in contracts/evmx/watcher/precompiles/WritePrecompile.sol. If the parameter packing or ordering ever drifts, the test will still pass even though production code would break.
This should be fixed by deriving the expected value at runtime from the canonical function and adding a constant-locking assertion:
- In test/DigestTest.t.sol import (or deploy via a fixture) the contract defining the canonical getDigest(DigestParams) in WritePrecompile.sol.
- Change the test to:
- Compute bytes32 constantExpected = /* existing constant */;
- Assert keccak256(abi.encodePacked(/* params */)) == constantExpected;
- Assert canonicalContract.getDigest(inputDigestParams) == constantExpected;
Alternatively, drop the local getDigest entirely and assert:
bytes32 runtimeExpected = canonicalContract.getDigest(inputDigestParams); assertEq(actualDigest, runtimeExpected);
This guarantees CI will catch any divergence between the test data and the on-chain logic.
contracts/evmx/base/AppGatewayBase.sol (2)
162-173
: Returning zero on missing forwarder masks misconfiguration (Solana path).This should not silently succeed for Solana; it leads to “valid plug” checks using zero address. Add an explicit Solana branch (resolver-based lookup) or revert with a clear error on Solana slugs to surface config issues early.
220-225
: Add Solana-specific valid plug setter
This should bypass the EVM-onlygetOnChainAddress
lookup for Solana by passing the programId directly to the watcher.• File: contracts/evmx/base/AppGatewayBase.sol (after line 225)
• No changes needed on the watcher side—IWatcher.setIsValidPlug(bool,uint32,bytes32)
accepts anybytes32
as the plug parameter.function _setValidPlug(bool isValid, uint32 chainSlug_, bytes32 contractId_) internal { bytes32 onchainAddress = getOnChainAddress(contractId_, chainSlug_); watcher__().setIsValidPlug(isValid, chainSlug_, onchainAddress); } + /// @notice Solana path: set validity using programId directly (no contractId lookup) + /// @dev Use only for Solana chainSlug values. + function _setValidPlugSolana(bool isValid, uint32 chainSlug_, bytes32 programId_) internal { + watcher__().setIsValidPlug(isValid, chainSlug_, programId_); + }contracts/evmx/watcher/Configurations.sol (1)
47-49
: Debug-only event extends ABI but is unused. Remove or emit, then drop before merge.Option A: remove now.
- // TODO:GW: remove after testing Solana - event VerifyConnectionsSB(bytes32 switchboard, bytes32 switchboardExpected);Option B: emit inside verifyConnections during bring-up:
function verifyConnections( @@ - ) external view { - (bytes32 appGatewayId, bytes32 switchboard) = getPlugConfigs(chainSlug_, target_); + ) external view { + (bytes32 appGatewayId, bytes32 switchboard) = getPlugConfigs(chainSlug_, target_); + // debug emission; remove before merge + emit VerifyConnectionsSB(switchboard, switchboards[chainSlug_][switchboardType_]); if (appGatewayId != toBytes32Format(appGateway_)) revert InvalidGateway(); if (switchboard != switchboards[chainSlug_][switchboardType_]) revert InvalidSwitchboard(); }hardhat-scripts/deploy/3.configureChains.ts (1)
107-115
: Remove noisy debug log and fix misleading “reversed” message.Keep logs actionable. The “reversed” note is incorrect and risks confusion about endianness.
Apply:
- console.log("XXX Setting solana switchboard"); - console.log("FAST_SWITCHBOARD_TYPE: ", FAST_SWITCHBOARD_TYPE); + console.log("Setting Solana switchboard for FAST_SWITCHBOARD_TYPE"); @@ - console.log( - "solanaSwitchboard as bytes32 reversed: ", - Buffer.from(toBytes32Format(solanaSwitchboard)).toString("hex") - ); + console.log( + "solanaSwitchboard bytes32:", + Buffer.from(toBytes32Format(solanaSwitchboard)).toString("hex") + );hardhat-scripts/deploy/1.deploy.ts (1)
40-44
: Validate constant size at definition time.Ensure the mocked Solana program id is exactly 32 bytes to prevent ABI encoding issues in initializer calls.
Optionally assert in code:
export const mockForwarderSolanaOnChainAddress32Bytes = Buffer.from( "0914e65e59622aeeefb7f007aef36df62d4c380895553b0643fcc4383c7c2448", "hex" ); +if (mockForwarderSolanaOnChainAddress32Bytes.length !== 32) { + throw new Error("mockForwarderSolanaOnChainAddress32Bytes must be 32 bytes"); +}hardhat-scripts/deploy/6.connect.ts (1)
178-184
: Remove commented alt payload with wrong shape.The commented object lacks
plugConfig
nesting and will mislead future edits.Delete lines 178–184.
test/ReturnValueSolanaTest.t.sol (3)
6-6
: Remove unused Constants import.Avoids compiler warnings and keeps the test lean.
Apply:
-import "../contracts/utils/common/Constants.sol";
24-31
: Assert parsedData arity to harden the test.This should fail fast if schema decoding returns unexpected lengths.
Apply:
bytes[] memory parsedData = BorshDecoder.decodeGenericSchema(returnDataSchema, returnData); +assertEq(parsedData.length, 2);
32-39
: Logs are fine for local debugging; consider dropping for CI speed.Not blocking; retain if helpful for flakiness triage.
script/super-token-solana/DeployEVMSolanaApps.s.sol (5)
6-7
: Don't import deploy targets from test paths.This script imports deployment targets from test directories. This should deploy real contracts or explicitly mark this script as dev-only and avoid cross-importing test artifacts to prevent accidental production usage.
Apply:
-import {EvmSolanaAppGateway} from "../../test/apps/app-gateways/super-token/EvmSolanaAppGateway.sol"; -import {SuperTokenAppGateway} from "../../test/apps/app-gateways/super-token/SuperTokenAppGateway.sol"; +// TODO(dev): point to production deploy targets or move script under a dev-only folder explicitly. +import {EvmSolanaAppGateway} from "../../apps/app-gateways/super-token/EvmSolanaAppGateway.sol"; +import {SuperTokenAppGateway} from "../../apps/app-gateways/super-token/SuperTokenAppGateway.sol";
8-8
: Unused import.ETH_ADDRESS is not used. Remove to keep the script lean.
-import {ETH_ADDRESS} from "../../contracts/utils/common/Constants.sol";
12-12
: Outdated invocation hint.The comment points to a different script path. Update to prevent confusion.
-// source .env && forge script script/counter/deployEVMxCounterApp.s.sol --broadcast --skip-simulation --legacy --gas-price 0 +// source .env && forge script script/super-token-solana/DeployEVMSolanaApps.s.sol --broadcast --skip-simulation --legacy --gas-price 0
53-59
: External reads may revert if the address is not a ForwarderSolana; guard with try/catch.Keep logs but don’t let the script die on introspection.
- console.log("Forwarder Solana address resolver:"); - console.log(address(ForwarderSolana(forwarderSolanaAddress).addressResolver__())); - console.log("ForwarderSolana chain slug:"); - console.log(ForwarderSolana(forwarderSolanaAddress).chainSlug()); - console.log("ForwarderSolana onChainAddress:"); - console.logBytes32(ForwarderSolana(forwarderSolanaAddress).onChainAddress()); + try ForwarderSolana(forwarderSolanaAddress).addressResolver__() returns (AddressResolver res) { + console.log("Forwarder Solana address resolver:"); + console.log(address(res)); + console.log("ForwarderSolana chain slug:"); + console.log(ForwarderSolana(forwarderSolanaAddress).chainSlug()); + console.log("ForwarderSolana onChainAddress:"); + console.logBytes32(ForwarderSolana(forwarderSolanaAddress).onChainAddress()); + } catch { + console.log("ForwarderSolana introspection failed (not deployed or wrong address)."); + }
28-30
: Gas limit comment is chain-specific; assert or move to config.Hard-coding “Arbitrum Sepolia” in script comments drifts. This should be passed via env or documented as example.
FunctionSignatures.md (1)
300-315
: ForwarderSolana selectors verified; table formatting tweakAll 4-byte selectors in FunctionSignatures.md match the compiled ABI.
This should ensure the table entries under “## ForwarderSolana” are correct.• Add a blank line immediately before the table (lines 300–315) so GitHub Markdown renders it as a standalone table.
contracts/evmx/watcher/borsh-serde/BorshDecoder.sol (2)
130-136
: EOI check message clarity.“unexpected EOI” is fine; keep consistent wording (“unexpected end of input”).
- require(data.ptr + length <= data.end, "Parse error: unexpected EOI"); + require(data.ptr + length <= data.end, "Parse error: unexpected end of input");
146-149
: done(): message clarity.- require(data.ptr == data.end, "Parse error: EOI expected"); + require(data.ptr == data.end, "Parse error: trailing bytes");contracts/evmx/watcher/precompiles/WritePrecompile.sol (1)
51-52
: Dead code.Commented using directive has no effect; remove.
- // using BorshEncoder for borsh;
contracts/evmx/watcher/borsh-serde/BorshEncoder.sol (2)
48-52
: Duplicate [u8;N] branch. Remove one to avoid divergence.The [u8;N] case appears twice; keep the later “fixed length” section with the rest.
- // Handle array types with fixed length - else if (BorshUtils.startsWith(typeName, "[u8;")) { - uint8[] memory abiDecodedArg = abi.decode(data, (uint8[])); - bytes memory borshEncodedArg = encodeUint8Array(abiDecodedArg); - functionArgsPacked = abi.encodePacked(functionArgsPacked, borshEncodedArg); - } else if (keccak256(bytes(typeName)) == keccak256(bytes("u16[]"))) { + } else if (keccak256(bytes(typeName)) == keccak256(bytes("u16[]"))) {Also applies to: 100-104
240-286
: Packing loops are O(n^2) due to bytes.concat in a loop.This should preallocate and write with assembly to avoid repeated allocations, especially for large arrays. Keep as-is if inputs stay small in practice.
script/super-token-solana/EvmSolanaOnchainCalls.s.sol (1)
23-24
: Remove misleading comment.Line 23 contains an outdated command with incorrect script path. The comment references "counter/EvmSolanaOnchainCalls.s.sol" but this file is in "super-token-solana" directory.
-// source .env && forge script script/counter/EvmSolanaOnchainCalls.s.sol --broadcast --skip-simulation --legacy --gas-price 0 +// source .env && forge script script/super-token-solana/EvmSolanaOnchainCalls.s.sol --broadcast --skip-simulation --legacy --gas-price 0contracts/evmx/helpers/ForwarderSolana.sol (2)
17-19
: Update contract documentation.The title and description don't reflect that this is specifically for Solana. Should be "Forwarder Contract for Solana".
-/// @title Forwarder Contract -/// @notice This contract acts as a forwarder for async calls to the on-chain contracts. +/// @title Forwarder Contract for Solana +/// @notice This contract acts as a forwarder for async calls to Solana programs.
29-30
: Fix typo in comment.Line 29 has duplicate forward slashes at the beginning.
- //// @param onChainAddress_ on-chain address associated with this forwarder + /// @param onChainAddress_ on-chain address associated with this forwarder
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (25)
Errors.md
(1 hunks)EventTopics.md
(1 hunks)FunctionSignatures.md
(1 hunks)contracts/evmx/base/AppGatewayBase.sol
(2 hunks)contracts/evmx/helpers/ForwarderSolana.sol
(1 hunks)contracts/evmx/watcher/Configurations.sol
(1 hunks)contracts/evmx/watcher/borsh-serde/BorshDecoder.sol
(1 hunks)contracts/evmx/watcher/borsh-serde/BorshEncoder.sol
(1 hunks)contracts/evmx/watcher/borsh-serde/BorshUtils.sol
(1 hunks)contracts/evmx/watcher/precompiles/WritePrecompile.sol
(6 hunks)contracts/utils/common/Constants.sol
(1 hunks)contracts/utils/common/Structs.sol
(2 hunks)foundry.toml
(1 hunks)hardhat-scripts/deploy/1.deploy.ts
(3 hunks)hardhat-scripts/deploy/3.configureChains.ts
(2 hunks)hardhat-scripts/deploy/6.connect.ts
(2 hunks)hardhat.config.ts
(1 hunks)script/super-token-solana/DeployEVMSolanaApps.s.sol
(1 hunks)script/super-token-solana/EvmSolanaOnchainCalls.s.sol
(1 hunks)src/enums.ts
(1 hunks)test/BorshDecoderTest.t.sol
(1 hunks)test/BorshEncoderTest.t.sol
(1 hunks)test/DigestTest.t.sol
(1 hunks)test/ReturnValueSolanaTest.t.sol
(1 hunks)test/apps/app-gateways/super-token/EvmSolanaAppGateway.sol
(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
hardhat-scripts/deploy/3.configureChains.ts (5)
hardhat-scripts/constants/constants.ts (1)
FAST_SWITCHBOARD_TYPE
(9-9)hardhat-scripts/utils/address.ts (1)
toBytes32Format
(54-61)hardhat-scripts/utils/deployUtils.ts (1)
updateContractSettings
(323-362)hardhat-scripts/config/config.ts (2)
EVMX_CHAIN_ID
(92-92)mode
(6-8)hardhat-scripts/constants/feeConstants.ts (1)
getFeeTokens
(27-29)
hardhat-scripts/deploy/6.connect.ts (1)
hardhat-scripts/deploy/1.deploy.ts (1)
mockForwarderSolanaOnChainAddress32Bytes
(41-44)
🪛 LanguageTool
Errors.md
[grammar] ~21-~21: There might be a mistake here.
Context: ...rwarderSolana.sol | Error | Signature | |-------|-----------| | `InvalidSolanaCh...
(QB_NEW_EN)
[grammar] ~22-~22: There might be a mistake here.
Context: ...rror | Signature | |-------|-----------| | InvalidSolanaChainSlug()
| `0xe37803...
(QB_NEW_EN)
[grammar] ~23-~23: There might be a mistake here.
Context: ...validSolanaChainSlug()|
0xe37803ab| |
AddressResolverNotSet()|
0x6d55276...
(QB_NEW_EN)
EventTopics.md
[grammar] ~117-~117: There might be a mistake here.
Context: ...ncPromise | Event | Arguments | Topic | | ----- | --------- | ----- | | `Initial...
(QB_NEW_EN)
[grammar] ~118-~118: There might be a mistake here.
Context: ... | Topic | | ----- | --------- | ----- | | Initialized
| (version: uint64)
| ...
(QB_NEW_EN)
[grammar] ~132-~132: There might be a mistake here.
Context: ...Forwarder | Event | Arguments | Topic | | ----- | --------- | ----- | | `Initial...
(QB_NEW_EN)
[grammar] ~133-~133: There might be a mistake here.
Context: ... | Topic | | ----- | --------- | ----- | | Initialized
| (version: uint64)
| ...
(QB_NEW_EN)
[grammar] ~138-~138: There might be a mistake here.
Context: ...derSolana | Event | Arguments | Topic | | ----- | --------- | ----- | | `Initial...
(QB_NEW_EN)
[grammar] ~139-~139: There might be a mistake here.
Context: ... | Topic | | ----- | --------- | ----- | | Initialized
| (version: uint64)
| ...
(QB_NEW_EN)
[grammar] ~152-~152: There might be a mistake here.
Context: ... TestUSDC | Event | Arguments | Topic | | ----- | --------- | ----- | | `Approva...
(QB_NEW_EN)
[grammar] ~153-~153: There might be a mistake here.
Context: ... | Topic | | ----- | --------- | ----- | | Approval
| `(owner: address, spender...
(QB_NEW_EN)
[grammar] ~154-~154: There might be a mistake here.
Context: ...e84f3dd0314c0f7b2291e5b200ac8c7c3b925| |
Transfer|
(from: address, to: addr...
(QB_NEW_EN)
FunctionSignatures.md
[grammar] ~302-~302: There might be a mistake here.
Context: ...orwarderSolana | Function | Signature | | -------- | --------- | | `addressResol...
(QB_NEW_EN)
[grammar] ~303-~303: There might be a mistake here.
Context: ...n | Signature | | -------- | --------- | | addressResolver__
| 0x6a750469
| |...
(QB_NEW_EN)
[grammar] ~304-~304: There might be a mistake here.
Context: ...| | addressResolver__
| 0x6a750469
| | asyncDeployer__
| 0x2a39e801
| | `...
(QB_NEW_EN)
[grammar] ~305-~305: There might be a mistake here.
Context: ...| |
asyncDeployer__|
0x2a39e801| |
callSolana|
0x4ef7957b| |
chain...
(QB_NEW_EN)
[grammar] ~306-~306: There might be a mistake here.
Context: ...9e801| |
callSolana|
0x4ef7957b| |
chainSlug|
0xb349ba65| |
deploy...
(QB_NEW_EN)
[grammar] ~307-~307: There might be a mistake here.
Context: ...f7957b| |
chainSlug|
0xb349ba65| |
deployForwarder__|
0xd4e3b034` | |...
(QB_NEW_EN)
[grammar] ~308-~308: There might be a mistake here.
Context: ...| | deployForwarder__
| 0xd4e3b034
| | feesManager__
| 0x70568b58
| | `ge...
(QB_NEW_EN)
[grammar] ~309-~309: There might be a mistake here.
Context: ...34| |
feesManager__|
0x70568b58| |
getChainSlug|
0x0b8c6568| |
get...
(QB_NEW_EN)
[grammar] ~310-~310: There might be a mistake here.
Context: ...b58| |
getChainSlug|
0x0b8c6568| |
getOnChainAddress|
0x9da48789` | |...
(QB_NEW_EN)
[grammar] ~311-~311: There might be a mistake here.
Context: ...| | getOnChainAddress
| 0x9da48789
| | initialize
| 0x148841cb
| | `onCha...
(QB_NEW_EN)
[grammar] ~312-~312: There might be a mistake here.
Context: ...48789| |
initialize|
0x148841cb| |
onChainAddress|
0x8bd0b363| |
w...
(QB_NEW_EN)
[grammar] ~313-~313: There might be a mistake here.
Context: ...b| |
onChainAddress|
0x8bd0b363| |
watcher__|
0x300bb063` | ## Proxy...
(QB_NEW_EN)
🪛 Gitleaks (8.27.2)
script/super-token-solana/EvmSolanaOnchainCalls.s.sol
72-72: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
134-134: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
148-148: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
160-160: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
202-202: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
326-326: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🔇 Additional comments (17)
hardhat.config.ts (1)
164-179
: Align Hardhat viaIR with Foundry to avoid divergent bytecode.Hardhat compiles with viaIR=true (Line 177) while foundry.toml has via_ir=false (Line 10). This should be consistent across toolchains or you will get different bytecode/sizes, breaking CREATE2 addresses, size-based assumptions, and verifications.
Run both pipelines and compare runtime bytecode for affected contracts (ForwarderSolana, WritePrecompile, etc.). If you standardize on viaIR, flip Foundry to via_ir=true (see suggested diff under foundry.toml comment).
contracts/utils/common/Constants.sol (1)
23-26
: LGTM: Stable identifiers for Solana schemas.The new TOKEN_ACCOUNT and MINT_ACCOUNT hashes are fine and scoped clearly for predefined schema selection.
contracts/evmx/watcher/borsh-serde/BorshUtils.sol (3)
8-18
: LGTM: Thin wrappers for mload/mstore.Simple and correct; no risk as long as callers pass valid pointers.
86-96
: LGTM: startsWith implementation is correct.Bounds check is in place and the loop is tight.
20-40
: Fix infinite loop and incorrect allocation in memoryToBytes.end is computed without the +32 header, so destPtr starts past end and the loop never terminates. Zero-length also returns an uninitialized pointer. This should allocate [32 + ceil32(length)] bytes, advance the free pointer, and loop until dest reaches end.
- function memoryToBytes(uint256 ptr, uint256 length) internal pure returns (bytes memory res) { - if (length != 0) { - assembly { - // 0x40 is the address of free memory pointer. - res := mload(0x40) - let end := - add(res, and(add(length, 63), 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0)) - // end = res + 32 + 32 * ceil(length / 32). - mstore(0x40, end) - mstore(res, length) - let destPtr := add(res, 32) - // prettier-ignore - for {} 1 {} { - mstore(destPtr, mload(ptr)) - destPtr := add(destPtr, 32) - if eq(destPtr, end) { break } - ptr := add(ptr, 32) - } - } - } - } + function memoryToBytes(uint256 ptr, uint256 length) internal pure returns (bytes memory res) { + assembly { + // Allocate: 32 (length slot) + ceil32(length) + let free := mload(0x40) + let size := and(add(length, 31), not(31)) // ceil32(length) + let newFree := add(add(free, 32), size) + mstore(0x40, newFree) + // Write length and copy payload + mstore(free, length) + let dest := add(free, 32) + let end := add(dest, size) + for { } lt(dest, end) { dest := add(dest, 32) ptr := add(ptr, 32) } { + mstore(dest, mload(ptr)) + } + res := free + } + }Likely an incorrect or invalid review comment.
contracts/utils/common/Structs.sol (1)
222-235
: Enforce accounts/accountFlags length parity at encode time.description.accountFlags should match data.accounts length one-to-one (bit 0 = isWritable). This should be validated where SolanaInstruction is consumed (e.g., in BorshEncoder/WritePrecompile) to prevent malformed payloads.
If absent, add a require/assert before encoding/transmission.
test/DigestTest.t.sol (1)
12-16
: Confirm logBytes4 support in your Forge-std version
I couldn’t locatelogBytes4
in the vendoredconsole.sol
. This should prevent test breakage on Forge-std variants that don’t implementlogBytes4
.• File test/DigestTest.t.sol, lines 12–16
Suggested change:
- console.logBytes4(READ); + console.logBytes(abi.encodePacked(READ)); ... - console.logBytes4(WRITE); + console.logBytes(abi.encodePacked(WRITE)); ... - console.logBytes4(SCHEDULE); + console.logBytes(abi.encodePacked(SCHEDULE));src/enums.ts (1)
74-75
: Confirmed consistent usage of Contracts.ForwarderSolanaFound exactly two references in the TypeScript deploy script, matching expectations:
- hardhat-scripts/deploy/1.deploy.ts – lines 262 and 273: uses Contracts.ForwarderSolana
No other TS files reference the new enum. No changes required.
Errors.md (1)
19-25
: Error signatures verified and correctComputed selectors via keccak256(first 4 bytes) for
•InvalidSolanaChainSlug()
→ 0xe37803ab
•AddressResolverNotSet()
→ 0x6d55276dmatch the entries in Errors.md (lines 19–25) and ForwarderSolana.sol exactly. No further changes needed.
hardhat-scripts/deploy/3.configureChains.ts (1)
63-76
: Remove unnecessary await on getWatcherSignergetWatcherSigner is defined as a synchronous function returning an ethers.Wallet (no
async
keyword or Promise in its signature), so it does not need to be awaited. Leaving the code as-is (const signer: Wallet = getWatcherSigner()
) is correct and safe—no change required.Likely an incorrect or invalid review comment.
hardhat-scripts/deploy/1.deploy.ts (1)
258-277
: ForwarderSolana initializer signature verified.This should confirm that the deployed args match the contract’s initialize signature:
- Contract signature:
function initialize(uint32 chainSlug_, bytes32 onChainAddress_, address addressResolver_)
- Passed args:
[ChainId.SOLANA_DEVNET, mockForwarderSolanaOnChainAddress32Bytes, addressResolver.address]
No changes needed.
EventTopics.md (2)
5-19
: Tables render fine; ignore grammar-tool noise.Automated grammar flags are false positives for Markdown tables. No action needed.
130-141
: Verify Initialized event documentation in EventTopics.mdEventTopics.md should list only the
Initialized
event because neither Forwarder nor ForwarderSolana declares any events nor inheritsOwnable
. AddressResolverUtil.sol and ForwarderStorage are event-free, so no ownership or custom events are emitted. This should reflect the actual compiled ABI:
- contracts/evmx/helpers/Forwarder.sol — no
event
declarations- contracts/evmx/helpers/ForwarderSolana.sol — no
event
declarations- Inherited
Initialized
event comes from solady/utils/Initializable.sol- docs/EventTopics.md (lines 130–141) — currently only shows
Initialized(version: uint64)
Manually confirm that the
Initialized(uint64)
signature and topic hash in EventTopics.md match the compiledInitialized
event from Solady’s Initializable (which may use a different integer size).hardhat-scripts/deploy/6.connect.ts (1)
101-109
: Incorrect assumption about getWatcherSignergetWatcherSigner is a synchronous function that returns an ethers.Wallet instance directly (see
hardhat-scripts/utils/sign.ts
), not a Promise. Addingawait
is unnecessary—awaiting a non-Promise simply wraps the value in a resolved Promise and has no functional effect, but it misrepresents the implementation and may confuse readers. Leave the code as:const signer = getWatcherSigner();Likely an incorrect or invalid review comment.
contracts/evmx/watcher/precompiles/WritePrecompile.sol (1)
181-205
: Digest param split by chain is a good direction.Branching to Solana/EVM helpers improves readability and reduces accidental coupling.
test/BorshEncoderTest.t.sol (1)
1-249
: LGTM! Comprehensive test coverage.The test suite thoroughly covers all Borsh encoding scenarios including primitives, arrays, vectors, and strings with appropriate assertions and edge cases.
test/BorshDecoderTest.t.sol (1)
1-836
: LGTM! Excellent test coverage.The test suite provides comprehensive coverage of Borsh decoding functionality including:
- All primitive types (u8 through u128)
- Vectors and arrays with various types
- Complex nested structures
- Edge cases and error conditions
- Real-world Solana account decoding scenarios
The tests are well-structured with clear assertions and appropriate use of vm.expectRevert for error cases.
} else if (keccak256(bytes(typeName)) == keccak256(bytes("String"))) { | ||
string memory value = data.decodeString(); | ||
decodedParams[i] = abi.encode(value); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
String type casing mismatch with encoder. Support both "String" and "string".
Encoder uses "string" while decoder matches "String". This will fail round-trips.
- } else if (keccak256(bytes(typeName)) == keccak256(bytes("String"))) {
+ } else if (
+ keccak256(bytes(typeName)) == keccak256(bytes("String")) ||
+ keccak256(bytes(typeName)) == keccak256(bytes("string"))
+ ) {
string memory value = data.decodeString();
decodedParams[i] = abi.encode(value);
📝 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.
} else if (keccak256(bytes(typeName)) == keccak256(bytes("String"))) { | |
string memory value = data.decodeString(); | |
decodedParams[i] = abi.encode(value); | |
} | |
} else if ( | |
keccak256(bytes(typeName)) == keccak256(bytes("String")) || | |
keccak256(bytes(typeName)) == keccak256(bytes("string")) | |
) { | |
string memory value = data.decodeString(); | |
decodedParams[i] = abi.encode(value); | |
} |
🤖 Prompt for AI Agents
In contracts/evmx/watcher/borsh-serde/BorshDecoder.sol around lines 39 to 42,
the decoder only matches keccak256(bytes("String")) while the encoder emits
"string", breaking round-trips; update the conditional to accept both casings
(e.g., compare keccak256(bytes(typeName)) against keccak256("String") OR
keccak256("string")) or normalize typeName to a single case (lowercase) and
compare to "string", then call data.decodeString() and abi.encode(value) as
before.
There was a problem hiding this 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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
contracts/protocol/SocketConfig.sol (1)
69-74
: Fix enableSwitchboard: this registers GOVERNANCE msg.sender, not the target switchboardconnect() checks isValidSwitchboard[switchboard_] on the passed address, but enableSwitchboard() marks the GOVERNANCE caller as REGISTERED. This should take an address parameter and update that entry.
Apply:
- function enableSwitchboard() external onlyRole(GOVERNANCE_ROLE) { - isValidSwitchboard[msg.sender] = SwitchboardStatus.REGISTERED; - emit SwitchboardEnabled(msg.sender); - } + function enableSwitchboard(address switchboard_) external onlyRole(GOVERNANCE_ROLE) { + // prevent duplicate enables; reuse existing error + if (isValidSwitchboard[switchboard_] == SwitchboardStatus.REGISTERED) revert SwitchboardExists(); + isValidSwitchboard[switchboard_] = SwitchboardStatus.REGISTERED; + emit SwitchboardEnabled(switchboard_); + }hardhat-scripts/deploy/3.configureChains.ts (2)
90-96
: Guard FeesPlug normalization; current non-null assertion can crash when missing.toBytes32FormatHexString(chainAddresses[Contracts.FeesPlug]!) will throw if FeesPlug isn’t deployed for a chain. Move normalization inside the guarded block that sets FeesPlug.
Apply:
- const feesPlug = toBytes32FormatHexString( - chainAddresses[Contracts.FeesPlug]! - ); + // Normalize only when present; set below in guarded updateAnd update the guarded block (see separate diff for lines 141-151).
--- `141-151`: **Normalize FeesPlug only when present and pass normalized bytes correctly.** This should prevent crashes and keep required/setter values consistent. Apply: ```diff - if (chainAddresses[Contracts.FeesPlug]) - await updateContractSettings( + if (chainAddresses[Contracts.FeesPlug]) { + const feesPlug = toBytes32FormatHexString( + chainAddresses[Contracts.FeesPlug] as string + ); + await updateContractSettings( EVMX_CHAIN_ID, Contracts.FeesManager, "feesPlugs", [chain], feesPlug, "setFeesPlug", [chain, toBytes32Format(feesPlug)], signer - ); + ); + }
♻️ Duplicate comments (2)
hardhat-scripts/deploy/3.configureChains.ts (2)
208-209
: Correct getFeeTokens signature now used.This fixes the previous runtime mismatch. Good.
107-128
: Normalize SWITCHBOARD_SOLANA and use the normalized value for compare + setter.updateContractSettings compares strings from the getter with requiredValue. Passing the raw env risks perpetual mismatches or invalid formatting. Normalize once to 0x-prefixed bytes32 and reuse for required and setter args. Also trim noisy debug logs.
Apply:
- console.log("XXX Setting solana switchboard"); - console.log("FAST_SWITCHBOARD_TYPE: ", FAST_SWITCHBOARD_TYPE); - const solanaSwitchboard = process.env.SWITCHBOARD_SOLANA; - if (!solanaSwitchboard) throw new Error("SWITCHBOARD_SOLANA is not set"); - console.log( - "solanaSwitchboard as bytes32 reversed: ", - Buffer.from(toBytes32Format(solanaSwitchboard)).toString("hex") - ); + console.log("Setting Solana switchboard"); + const solanaSwitchboardRaw = process.env.SWITCHBOARD_SOLANA; + if (!solanaSwitchboardRaw) throw new Error("SWITCHBOARD_SOLANA is not set"); + const solanaSwitchboardHex = toBytes32FormatHexString(solanaSwitchboardRaw); + console.log("FAST_SWITCHBOARD_TYPE:", FAST_SWITCHBOARD_TYPE, "SOLANA:", solanaSwitchboardHex); await updateContractSettings( EVMX_CHAIN_ID, Contracts.Configurations, "switchboards", [ChainSlug.SOLANA_DEVNET, FAST_SWITCHBOARD_TYPE], - solanaSwitchboard, + solanaSwitchboardHex, "setSwitchboard", [ ChainSlug.SOLANA_DEVNET, FAST_SWITCHBOARD_TYPE, - toBytes32Format(solanaSwitchboard), + toBytes32Format(solanaSwitchboardHex), ], signer );
🧹 Nitpick comments (6)
contracts/protocol/SocketConfig.sol (6)
62-67
: Resolve access-control model: register vs enable is inconsistentAs written: anyone can registerSwitchboard() to REGISTERED; disable needs SWITCHBOARD_DISABLER_ROLE; enable requires GOVERNANCE but currently affects msg.sender. This should define a clear state machine:
- registerSwitchboard() → PENDING (self-registration)
- enableSwitchboard(address) [GOVERNANCE_ROLE] → REGISTERED (only from DISABLED/PENDING)
- disableSwitchboard(address) [SWITCHBOARD_DISABLER_ROLE] → DISABLED
Alternatively, remove self-registration and make GOVERNANCE the sole registrar.
46-54
: Self-registration grants REGISTERED to any addressregisterSwitchboard() sets REGISTERED with no role or allowlist, which undermines governance gating. This should not directly elevate to REGISTERED. Either restrict to GOVERNANCE_ROLE or gate through a PENDING state and require enableSwitchboard() to finalize.
76-79
: Validate fee manager address and avoid no-op updatesThis should reject zero address and skip emitting when unchanged. Also set before emitting for conventional ordering.
- function setSocketFeeManager(address socketFeeManager_) external onlyRole(GOVERNANCE_ROLE) { - emit SocketFeeManagerUpdated(address(socketFeeManager), socketFeeManager_); - socketFeeManager = ISocketFeeManager(socketFeeManager_); - } + function setSocketFeeManager(address socketFeeManager_) external onlyRole(GOVERNANCE_ROLE) { + require(socketFeeManager_ != address(0), "socketFeeManager is zero"); + address old = address(socketFeeManager); + if (old == socketFeeManager_) return; + socketFeeManager = ISocketFeeManager(socketFeeManager_); + emit SocketFeeManagerUpdated(old, socketFeeManager_); + }
96-101
: Enforce MAX_COPY_BYTES ceiling; imported constant currently unusedWithout bounds, an unsafe value can be set and break downstream assumptions. This should validate range and use MAX_COPY_BYTES.
- function setMaxCopyBytes(uint16 maxCopyBytes_) external onlyRole(GOVERNANCE_ROLE) { - maxCopyBytes = maxCopyBytes_; - } + function setMaxCopyBytes(uint16 maxCopyBytes_) external onlyRole(GOVERNANCE_ROLE) { + require(maxCopyBytes_ > 0 && maxCopyBytes_ <= MAX_COPY_BYTES, "maxCopyBytes out of range"); + maxCopyBytes = maxCopyBytes_; + }
33-37
: Unused error: SwitchboardExistsCurrently unused in this file; use it in enableSwitchboard() (see above) or remove to keep the surface area lean.
56-61
: Consider idempotent disableRepeated disables emit duplicate events. This should no-op if already DISABLED (or revert with a specific error for a cleaner state machine).
- function disableSwitchboard(address switchboard_) external onlyRole(SWITCHBOARD_DISABLER_ROLE) { - isValidSwitchboard[switchboard_] = SwitchboardStatus.DISABLED; - emit SwitchboardDisabled(switchboard_); - } + function disableSwitchboard(address switchboard_) external onlyRole(SWITCHBOARD_DISABLER_ROLE) { + if (isValidSwitchboard[switchboard_] == SwitchboardStatus.DISABLED) return; + isValidSwitchboard[switchboard_] = SwitchboardStatus.DISABLED; + emit SwitchboardDisabled(switchboard_); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled
- Linear integration is disabled
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (7)
Errors.md
(1 hunks)EventTopics.md
(1 hunks)FunctionSignatures.md
(1 hunks)contracts/protocol/SocketConfig.sol
(1 hunks)foundry.toml
(1 hunks)hardhat-scripts/deploy/3.configureChains.ts
(1 hunks)script/super-token-solana/DeployEVMSolanaApps.s.sol
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- script/super-token-solana/DeployEVMSolanaApps.s.sol
🧰 Additional context used
🧬 Code graph analysis (1)
hardhat-scripts/deploy/3.configureChains.ts (4)
hardhat-scripts/constants/constants.ts (1)
FAST_SWITCHBOARD_TYPE
(9-9)hardhat-scripts/utils/address.ts (1)
toBytes32Format
(54-61)hardhat-scripts/utils/deployUtils.ts (1)
updateContractSettings
(323-362)hardhat-scripts/config/config.ts (1)
EVMX_CHAIN_ID
(92-92)
🪛 LanguageTool
FunctionSignatures.md
[grammar] ~89-~89: There might be a mistake here.
Context: ... SocketBatcher | Function | Signature | | -------- | --------- | | `attestAndExe...
(QB_NEW_EN)
[grammar] ~90-~90: There might be a mistake here.
Context: ...n | Signature | | -------- | --------- | | attestAndExecute
| 0x66c7748a
| | ...
(QB_NEW_EN)
[grammar] ~91-~91: There might be a mistake here.
Context: ... | | attestAndExecute
| 0x66c7748a
| | cancelOwnershipHandover
| `0x54d1f13...
(QB_NEW_EN)
[grammar] ~92-~92: There might be a mistake here.
Context: ...ancelOwnershipHandover|
0x54d1f13d| |
completeOwnershipHandover|
0xf04e2...
(QB_NEW_EN)
[grammar] ~93-~93: There might be a mistake here.
Context: ...pleteOwnershipHandover|
0xf04e283e| |
owner|
0x8da5cb5b| |
ownershipH...
(QB_NEW_EN)
[grammar] ~94-~94: There might be a mistake here.
Context: ...0xf04e283e| |
owner|
0x8da5cb5b| |
ownershipHandoverExpiresAt|
0xfee8...
(QB_NEW_EN)
[grammar] ~95-~95: There might be a mistake here.
Context: ...rshipHandoverExpiresAt|
0xfee81cf4| |
renounceOwnership|
0x715018a6` | |...
(QB_NEW_EN)
[grammar] ~96-~96: There might be a mistake here.
Context: ...| | renounceOwnership
| 0x715018a6
| | requestOwnershipHandover
| `0x256929...
(QB_NEW_EN)
[grammar] ~97-~97: There might be a mistake here.
Context: ...questOwnershipHandover|
0x25692962| |
rescueFunds|
0x6ccae054| |
sock...
(QB_NEW_EN)
[grammar] ~98-~98: There might be a mistake here.
Context: ...2962| |
rescueFunds|
0x6ccae054| |
socket__|
0xc6a261d2| |
transfe...
(QB_NEW_EN)
[grammar] ~99-~99: There might be a mistake here.
Context: ...ccae054| |
socket__|
0xc6a261d2| |
transferOwnership|
0xf2fde38b` | ...
(QB_NEW_EN)
[grammar] ~104-~104: There might be a mistake here.
Context: ...cketFeeManager | Function | Signature | | -------- | --------- | | `cancelOwners...
(QB_NEW_EN)
[grammar] ~105-~105: There might be a mistake here.
Context: ...n | Signature | | -------- | --------- | | cancelOwnershipHandover
| `0x54d1f13...
(QB_NEW_EN)
[grammar] ~106-~106: There might be a mistake here.
Context: ...ancelOwnershipHandover|
0x54d1f13d| |
completeOwnershipHandover|
0xf04e2...
(QB_NEW_EN)
[grammar] ~107-~107: There might be a mistake here.
Context: ...pleteOwnershipHandover|
0xf04e283e| |
getMinSocketFees|
0xd383b688` | | ...
(QB_NEW_EN)
[grammar] ~108-~108: There might be a mistake here.
Context: ... | | getMinSocketFees
| 0xd383b688
| | grantRole
| 0x2f2ff15d
| | `hasRol...
(QB_NEW_EN)
[grammar] ~109-~109: There might be a mistake here.
Context: ...83b688| |
grantRole|
0x2f2ff15d| |
hasRole|
0x91d14854| |
owner` |...
(QB_NEW_EN)
[grammar] ~110-~110: There might be a mistake here.
Context: ...2f2ff15d| |
hasRole|
0x91d14854| |
owner|
0x8da5cb5b| |
ownershipH...
(QB_NEW_EN)
[grammar] ~111-~111: There might be a mistake here.
Context: ...0x91d14854| |
owner|
0x8da5cb5b| |
ownershipHandoverExpiresAt|
0xfee8...
(QB_NEW_EN)
[grammar] ~112-~112: There might be a mistake here.
Context: ...rshipHandoverExpiresAt|
0xfee81cf4| |
payAndCheckFees|
0xd9d29ae3| |
...
(QB_NEW_EN)
[grammar] ~113-~113: There might be a mistake here.
Context: ...| |
payAndCheckFees|
0xd9d29ae3| |
renounceOwnership|
0x715018a6` | |...
(QB_NEW_EN)
[grammar] ~114-~114: There might be a mistake here.
Context: ...| | renounceOwnership
| 0x715018a6
| | requestOwnershipHandover
| `0x256929...
(QB_NEW_EN)
[grammar] ~115-~115: There might be a mistake here.
Context: ...questOwnershipHandover|
0x25692962| |
rescueFunds|
0x6ccae054| |
revo...
(QB_NEW_EN)
[grammar] ~116-~116: There might be a mistake here.
Context: ...2962| |
rescueFunds|
0x6ccae054| |
revokeRole|
0xd547741f| |
setSo...
(QB_NEW_EN)
[grammar] ~117-~117: There might be a mistake here.
Context: ...ae054| |
revokeRole|
0xd547741f| |
setSocketFees|
0x47a406f6| |
so...
(QB_NEW_EN)
[grammar] ~118-~118: There might be a mistake here.
Context: ...1f| |
setSocketFees|
0x47a406f6| |
socketFees|
0xab1b33a8| |
trans...
(QB_NEW_EN)
[grammar] ~119-~119: There might be a mistake here.
Context: ...406f6| |
socketFees|
0xab1b33a8| |
transferOwnership|
0xf2fde38b` | ## FeesManager | Fun...
(QB_NEW_EN)
[grammar] ~169-~169: There might be a mistake here.
Context: ...| ## FeesPool | Function | Signature | | -------- | --------- | | `cancelOwners...
(QB_NEW_EN)
[grammar] ~170-~170: There might be a mistake here.
Context: ...n | Signature | | -------- | --------- | | cancelOwnershipHandover
| `0x54d1f13...
(QB_NEW_EN)
[grammar] ~171-~171: There might be a mistake here.
Context: ...ancelOwnershipHandover|
0x54d1f13d| |
completeOwnershipHandover|
0xf04e2...
(QB_NEW_EN)
[grammar] ~172-~172: There might be a mistake here.
Context: ...pleteOwnershipHandover|
0xf04e283e| |
getBalance|
0x12065fe0| |
grant...
(QB_NEW_EN)
[grammar] ~173-~173: There might be a mistake here.
Context: ...e283e| |
getBalance|
0x12065fe0| |
grantRole|
0x2f2ff15d| |
hasRol...
(QB_NEW_EN)
[grammar] ~174-~174: There might be a mistake here.
Context: ...065fe0| |
grantRole|
0x2f2ff15d| |
hasRole|
0x91d14854| |
owner` |...
(QB_NEW_EN)
[grammar] ~175-~175: There might be a mistake here.
Context: ...2f2ff15d| |
hasRole|
0x91d14854| |
owner|
0x8da5cb5b| |
ownershipH...
(QB_NEW_EN)
[grammar] ~176-~176: There might be a mistake here.
Context: ...0x91d14854| |
owner|
0x8da5cb5b| |
ownershipHandoverExpiresAt|
0xfee8...
(QB_NEW_EN)
[grammar] ~177-~177: There might be a mistake here.
Context: ...rshipHandoverExpiresAt|
0xfee81cf4| |
renounceOwnership|
0x715018a6` | |...
(QB_NEW_EN)
[grammar] ~178-~178: There might be a mistake here.
Context: ...| | renounceOwnership
| 0x715018a6
| | requestOwnershipHandover
| `0x256929...
(QB_NEW_EN)
[grammar] ~179-~179: There might be a mistake here.
Context: ...questOwnershipHandover|
0x25692962| |
revokeRole|
0xd547741f| |
trans...
(QB_NEW_EN)
[grammar] ~180-~180: There might be a mistake here.
Context: ...92962| |
revokeRole|
0xd547741f| |
transferOwnership|
0xf2fde38b` | |...
(QB_NEW_EN)
[grammar] ~181-~181: There might be a mistake here.
Context: ...| | transferOwnership
| 0xf2fde38b
| | withdraw
| 0xf3fef3a3
| ## Addres...
(QB_NEW_EN)
[grammar] ~242-~242: There might be a mistake here.
Context: ...# AsyncPromise | Function | Signature | | -------- | --------- | | `addressResol...
(QB_NEW_EN)
[grammar] ~243-~243: There might be a mistake here.
Context: ...n | Signature | | -------- | --------- | | addressResolver__
| 0x6a750469
| |...
(QB_NEW_EN)
[grammar] ~244-~244: There might be a mistake here.
Context: ...| | addressResolver__
| 0x6a750469
| | asyncDeployer__
| 0x2a39e801
| | `...
(QB_NEW_EN)
[grammar] ~245-~245: There might be a mistake here.
Context: ...| |
asyncDeployer__|
0x2a39e801| |
callbackData|
0xef44c272| |
cal...
(QB_NEW_EN)
[grammar] ~246-~246: There might be a mistake here.
Context: ...801| |
callbackData|
0xef44c272| |
callbackSelector|
0x2764f92f` | | ...
(QB_NEW_EN)
[grammar] ~247-~247: There might be a mistake here.
Context: ... | | callbackSelector
| 0x2764f92f
| | deployForwarder__
| 0xd4e3b034
| |...
(QB_NEW_EN)
[grammar] ~248-~248: There might be a mistake here.
Context: ...| | deployForwarder__
| 0xd4e3b034
| | exceededMaxCopy
| 0xaf598c7c
| | `...
(QB_NEW_EN)
[grammar] ~249-~249: There might be a mistake here.
Context: ...| |
exceededMaxCopy|
0xaf598c7c| |
feesManager__|
0x70568b58| |
in...
(QB_NEW_EN)
[grammar] ~250-~250: There might be a mistake here.
Context: ...7c| |
feesManager__|
0x70568b58| |
initialize|
0x0ece6089| |
local...
(QB_NEW_EN)
[grammar] ~251-~251: There might be a mistake here.
Context: ...68b58| |
initialize|
0x0ece6089| |
localInvoker|
0x45eb87f4| |
mar...
(QB_NEW_EN)
[grammar] ~252-~252: There might be a mistake here.
Context: ...089| |
localInvoker|
0x45eb87f4| |
markOnchainRevert|
0xd0e7af1b` | |...
(QB_NEW_EN)
[grammar] ~253-~253: There might be a mistake here.
Context: ...| | markOnchainRevert
| 0xd0e7af1b
| | markResolved
| 0x822d5d1f
| | `req...
(QB_NEW_EN)
[grammar] ~254-~254: There might be a mistake here.
Context: ...f1b| |
markResolved|
0x822d5d1f| |
requestCount|
0x5badbe4c| |
res...
(QB_NEW_EN)
[grammar] ~255-~255: There might be a mistake here.
Context: ...d1f| |
requestCount|
0x5badbe4c| |
rescueFunds|
0x6ccae054| |
retu...
(QB_NEW_EN)
[grammar] ~256-~256: There might be a mistake here.
Context: ...be4c| |
rescueFunds|
0x6ccae054| |
returnData|
0xebddbaf6| |
state...
(QB_NEW_EN)
[grammar] ~257-~257: There might be a mistake here.
Context: ...ae054| |
returnData|
0xebddbaf6| |
state|
0xc19d93fb| |
then|
0...
(QB_NEW_EN)
[grammar] ~264-~264: There might be a mistake here.
Context: ...eployForwarder | Function | Signature | | -------- | --------- | | `addressResol...
(QB_NEW_EN)
[grammar] ~265-~265: There might be a mistake here.
Context: ...n | Signature | | -------- | --------- | | addressResolver__
| 0x6a750469
| |...
(QB_NEW_EN)
[grammar] ~266-~266: There might be a mistake here.
Context: ...| | addressResolver__
| 0x6a750469
| | asyncDeployer__
| 0x2a39e801
| | `...
(QB_NEW_EN)
[grammar] ~267-~267: There might be a mistake here.
Context: ...| |
asyncDeployer__|
0x2a39e801| |
cancelOwnershipHandover|
0x54d1f13...
(QB_NEW_EN)
[grammar] ~268-~268: There might be a mistake here.
Context: ...ancelOwnershipHandover|
0x54d1f13d| |
completeOwnershipHandover|
0xf04e2...
(QB_NEW_EN)
[grammar] ~269-~269: There might be a mistake here.
Context: ...pleteOwnershipHandover|
0xf04e283e| |
deploy|
0x940f11af| |
deployFor...
(QB_NEW_EN)
[grammar] ~270-~270: There might be a mistake here.
Context: ...xf04e283e| |
deploy|
0x940f11af| |
deployForwarder__|
0xd4e3b034` | |...
(QB_NEW_EN)
[grammar] ~271-~271: There might be a mistake here.
Context: ...| | deployForwarder__
| 0xd4e3b034
| | deployerSwitchboardType
| `0xaa381f9...
(QB_NEW_EN)
[grammar] ~272-~272: There might be a mistake here.
Context: ...eployerSwitchboardType|
0xaa381f9a| |
feesManager__|
0x70568b58| |
in...
(QB_NEW_EN)
[grammar] ~273-~273: There might be a mistake here.
Context: ...9a| |
feesManager__|
0x70568b58| |
initialize|
0x6133f985| |
owner...
(QB_NEW_EN)
[grammar] ~274-~274: There might be a mistake here.
Context: ...68b58| |
initialize|
0x6133f985| |
owner|
0x8da5cb5b| |
ownershipH...
(QB_NEW_EN)
[grammar] ~275-~275: There might be a mistake here.
Context: ...0x6133f985| |
owner|
0x8da5cb5b| |
ownershipHandoverExpiresAt|
0xfee8...
(QB_NEW_EN)
[grammar] ~276-~276: There might be a mistake here.
Context: ...rshipHandoverExpiresAt|
0xfee81cf4| |
renounceOwnership|
0x715018a6` | |...
(QB_NEW_EN)
[grammar] ~277-~277: There might be a mistake here.
Context: ...| | renounceOwnership
| 0x715018a6
| | requestOwnershipHandover
| `0x256929...
(QB_NEW_EN)
[grammar] ~278-~278: There might be a mistake here.
Context: ...questOwnershipHandover|
0x25692962| |
rescueFunds|
0x6ccae054| |
salt...
(QB_NEW_EN)
[grammar] ~286-~286: There might be a mistake here.
Context: ... ## Forwarder | Function | Signature | | -------- | --------- | | `addressResol...
(QB_NEW_EN)
[grammar] ~287-~287: There might be a mistake here.
Context: ...n | Signature | | -------- | --------- | | addressResolver__
| 0x6a750469
| |...
(QB_NEW_EN)
[grammar] ~288-~288: There might be a mistake here.
Context: ...| | addressResolver__
| 0x6a750469
| | asyncDeployer__
| 0x2a39e801
| | `...
(QB_NEW_EN)
[grammar] ~289-~289: There might be a mistake here.
Context: ...| |
asyncDeployer__|
0x2a39e801| |
chainSlug|
0xb349ba65| |
deploy...
(QB_NEW_EN)
[grammar] ~290-~290: There might be a mistake here.
Context: ...39e801| |
chainSlug|
0xb349ba65| |
deployForwarder__|
0xd4e3b034` | |...
(QB_NEW_EN)
[grammar] ~291-~291: There might be a mistake here.
Context: ...| | deployForwarder__
| 0xd4e3b034
| | feesManager__
| 0x70568b58
| | `ge...
(QB_NEW_EN)
[grammar] ~292-~292: There might be a mistake here.
Context: ...34| |
feesManager__|
0x70568b58| |
getChainSlug|
0x0b8c6568| |
get...
(QB_NEW_EN)
[grammar] ~293-~293: There might be a mistake here.
Context: ...b58| |
getChainSlug|
0x0b8c6568| |
getOnChainAddress|
0x9da48789` | |...
(QB_NEW_EN)
[grammar] ~294-~294: There might be a mistake here.
Context: ...| | getOnChainAddress
| 0x9da48789
| | initialize
| 0x148841cb
| | `onCha...
(QB_NEW_EN)
[grammar] ~295-~295: There might be a mistake here.
Context: ...48789| |
initialize|
0x148841cb| |
onChainAddress|
0x8bd0b363| |
r...
(QB_NEW_EN)
[grammar] ~296-~296: There might be a mistake here.
Context: ...b| |
onChainAddress|
0x8bd0b363| |
rescueFunds|
0x6ccae054| |
watc...
(QB_NEW_EN)
[grammar] ~297-~297: There might be a mistake here.
Context: ...b363| |
rescueFunds|
0x6ccae054| |
watcher__|
0x300bb063` | ## Forwa...
(QB_NEW_EN)
[grammar] ~302-~302: There might be a mistake here.
Context: ...orwarderSolana | Function | Signature | | -------- | --------- | | `addressResol...
(QB_NEW_EN)
[grammar] ~303-~303: There might be a mistake here.
Context: ...n | Signature | | -------- | --------- | | addressResolver__
| 0x6a750469
| |...
(QB_NEW_EN)
[grammar] ~304-~304: There might be a mistake here.
Context: ...| | addressResolver__
| 0x6a750469
| | asyncDeployer__
| 0x2a39e801
| | `...
(QB_NEW_EN)
[grammar] ~305-~305: There might be a mistake here.
Context: ...| |
asyncDeployer__|
0x2a39e801| |
callSolana|
0x4ef7957b| |
chain...
(QB_NEW_EN)
[grammar] ~306-~306: There might be a mistake here.
Context: ...9e801| |
callSolana|
0x4ef7957b| |
chainSlug|
0xb349ba65| |
deploy...
(QB_NEW_EN)
[grammar] ~307-~307: There might be a mistake here.
Context: ...f7957b| |
chainSlug|
0xb349ba65| |
deployForwarder__|
0xd4e3b034` | |...
(QB_NEW_EN)
[grammar] ~308-~308: There might be a mistake here.
Context: ...| | deployForwarder__
| 0xd4e3b034
| | feesManager__
| 0x70568b58
| | `ge...
(QB_NEW_EN)
[grammar] ~309-~309: There might be a mistake here.
Context: ...34| |
feesManager__|
0x70568b58| |
getChainSlug|
0x0b8c6568| |
get...
(QB_NEW_EN)
[grammar] ~310-~310: There might be a mistake here.
Context: ...b58| |
getChainSlug|
0x0b8c6568| |
getOnChainAddress|
0x9da48789` | |...
(QB_NEW_EN)
[grammar] ~311-~311: There might be a mistake here.
Context: ...| | getOnChainAddress
| 0x9da48789
| | initialize
| 0x148841cb
| | `onCha...
(QB_NEW_EN)
[grammar] ~312-~312: There might be a mistake here.
Context: ...48789| |
initialize|
0x148841cb| |
onChainAddress|
0x8bd0b363| |
w...
(QB_NEW_EN)
[grammar] ~313-~313: There might be a mistake here.
Context: ...b| |
onChainAddress|
0x8bd0b363| |
watcher__|
0x300bb063` | ## Proxy...
(QB_NEW_EN)
[grammar] ~318-~318: There might be a mistake here.
Context: ...# ProxyFactory | Function | Signature | | -------- | --------- | | adminOf
| `...
(QB_NEW_EN)
[grammar] ~319-~319: There might be a mistake here.
Context: ...n | Signature | | -------- | --------- | | adminOf
| 0x2abbef15
| | `changeAd...
(QB_NEW_EN)
[grammar] ~320-~320: There might be a mistake here.
Context: ...--------- | | adminOf
| 0x2abbef15
| | changeAdmin
| 0x1acfd02a
| | `depl...
(QB_NEW_EN)
[grammar] ~321-~321: There might be a mistake here.
Context: ...ef15| |
changeAdmin|
0x1acfd02a| |
deploy|
0x545e7c61| |
deployAnd...
(QB_NEW_EN)
[grammar] ~322-~322: There might be a mistake here.
Context: ...x1acfd02a| |
deploy|
0x545e7c61| |
deployAndCall|
0x4314f120| |
de...
(QB_NEW_EN)
[grammar] ~323-~323: There might be a mistake here.
Context: ...61| |
deployAndCall|
0x4314f120| |
deployDeterministic|
0x3729f922` |...
(QB_NEW_EN)
[grammar] ~324-~324: There might be a mistake here.
Context: ...| deployDeterministic
| 0x3729f922
| | deployDeterministicAndCall
| `0xa97b...
(QB_NEW_EN)
[grammar] ~325-~325: There might be a mistake here.
Context: ...oyDeterministicAndCall|
0xa97b90d5| |
initCodeHash|
0xdb4c545e| |
pre...
(QB_NEW_EN)
[grammar] ~326-~326: There might be a mistake here.
Context: ...0d5| |
initCodeHash|
0xdb4c545e| |
predictDeterministicAddress|
0x541...
(QB_NEW_EN)
[grammar] ~327-~327: There might be a mistake here.
Context: ...ctDeterministicAddress|
0x5414dff0| |
upgrade|
0x99a88ec4| |
upgradeA...
(QB_NEW_EN)
[grammar] ~328-~328: There might be a mistake here.
Context: ...5414dff0| |
upgrade|
0x99a88ec4| |
upgradeAndCall|
0x9623609d` | ## ...
(QB_NEW_EN)
[grammar] ~333-~333: There might be a mistake here.
Context: ...| ## TestUSDC | Function | Signature | | -------- | --------- | | `DOMAIN_SEPAR...
(QB_NEW_EN)
[grammar] ~334-~334: There might be a mistake here.
Context: ...n | Signature | | -------- | --------- | | DOMAIN_SEPARATOR
| 0x3644e515
| | ...
(QB_NEW_EN)
[grammar] ~335-~335: There might be a mistake here.
Context: ... | | DOMAIN_SEPARATOR
| 0x3644e515
| | allowance
| 0xdd62ed3e
| | `approv...
(QB_NEW_EN)
[grammar] ~336-~336: There might be a mistake here.
Context: ...44e515| |
allowance|
0xdd62ed3e| |
approve|
0x095ea7b3| |
balanceO...
(QB_NEW_EN)
[grammar] ~337-~337: There might be a mistake here.
Context: ...dd62ed3e| |
approve|
0x095ea7b3| |
balanceOf|
0x70a08231| |
decima...
(QB_NEW_EN)
[grammar] ~338-~338: There might be a mistake here.
Context: ...5ea7b3| |
balanceOf|
0x70a08231| |
decimals|
0x313ce567| |
mint` |...
(QB_NEW_EN)
[grammar] ~339-~339: There might be a mistake here.
Context: ...0a08231| |
decimals|
0x313ce567| |
mint|
0x40c10f19| |
name|
0x...
(QB_NEW_EN)
[grammar] ~340-~340: There might be a mistake here.
Context: ...0x313ce567
| | mint
| 0x40c10f19
| | name
| 0x06fdde03
| | nonces
| `...
(QB_NEW_EN)
[grammar] ~341-~341: There might be a mistake here.
Context: ...0x40c10f19
| | name
| 0x06fdde03
| | nonces
| 0x7ecebe00
| | owner
| ...
(QB_NEW_EN)
[grammar] ~342-~342: There might be a mistake here.
Context: ...x06fdde03| |
nonces|
0x7ecebe00| |
owner|
0x8da5cb5b| |
permit` | ...
(QB_NEW_EN)
[grammar] ~343-~343: There might be a mistake here.
Context: ...0x7ecebe00| |
owner|
0x8da5cb5b| |
permit|
0xd505accf| |
symbol` |...
(QB_NEW_EN)
[grammar] ~344-~344: There might be a mistake here.
Context: ...x8da5cb5b| |
permit|
0xd505accf| |
symbol|
0x95d89b41| |
totalSupp...
(QB_NEW_EN)
[grammar] ~345-~345: There might be a mistake here.
Context: ...xd505accf| |
symbol|
0x95d89b41| |
totalSupply|
0x18160ddd| |
tran...
(QB_NEW_EN)
[grammar] ~346-~346: There might be a mistake here.
Context: ...9b41| |
totalSupply|
0x18160ddd| |
transfer|
0xa9059cbb| |
transfe...
(QB_NEW_EN)
[grammar] ~347-~347: There might be a mistake here.
Context: ...8160ddd| |
transfer|
0xa9059cbb| |
transferFrom|
0x23b872dd` | ## Co...
(QB_NEW_EN)
[grammar] ~400-~400: There might be a mistake here.
Context: ...romiseResolver | Function | Signature | | -------- | --------- | | markRevert
...
(QB_NEW_EN)
[grammar] ~401-~401: There might be a mistake here.
Context: ...n | Signature | | -------- | --------- | | markRevert
| 0x56501015
| | `rescu...
(QB_NEW_EN)
[grammar] ~402-~402: There might be a mistake here.
Context: ...------ | | markRevert
| 0x56501015
| | rescueFunds
| 0x6ccae054
| | `reso...
(QB_NEW_EN)
[grammar] ~403-~403: There might be a mistake here.
Context: ...1015| |
rescueFunds|
0x6ccae054| |
resolvePromises|
0xbf8484b8| |
...
(QB_NEW_EN)
[grammar] ~404-~404: There might be a mistake here.
Context: ...| |
resolvePromises|
0xbf8484b8| |
watcher__|
0x300bb063` | ## Reque...
(QB_NEW_EN)
[grammar] ~493-~493: There might be a mistake here.
Context: ...astSwitchboard | Function | Signature | | -------- | --------- | | `allowPayload...
(QB_NEW_EN)
[grammar] ~494-~494: There might be a mistake here.
Context: ...n | Signature | | -------- | --------- | | allowPayload
| 0x31c23f66
| | `att...
(QB_NEW_EN)
[grammar] ~495-~495: There might be a mistake here.
Context: ...---- | | allowPayload
| 0x31c23f66
| | attest
| 0x63671b60
| | `cancelOwn...
(QB_NEW_EN)
[grammar] ~496-~496: There might be a mistake here.
Context: ...x31c23f66| |
attest|
0x63671b60| |
cancelOwnershipHandover|
0x54d1f13...
(QB_NEW_EN)
[grammar] ~497-~497: There might be a mistake here.
Context: ...ancelOwnershipHandover|
0x54d1f13d| |
chainSlug|
0xb349ba65| |
comple...
(QB_NEW_EN)
[grammar] ~498-~498: There might be a mistake here.
Context: ...d1f13d| |
chainSlug|
0xb349ba65| |
completeOwnershipHandover|
0xf04e2...
(QB_NEW_EN)
[grammar] ~499-~499: There might be a mistake here.
Context: ...pleteOwnershipHandover|
0xf04e283e| |
grantRole|
0x2f2ff15d| |
hasRol...
(QB_NEW_EN)
[grammar] ~500-~500: There might be a mistake here.
Context: ...4e283e| |
grantRole|
0x2f2ff15d| |
hasRole|
0x91d14854| |
isAttest...
(QB_NEW_EN)
[grammar] ~501-~501: There might be a mistake here.
Context: ...2f2ff15d| |
hasRole|
0x91d14854| |
isAttested|
0xc13c2396| |
owner...
(QB_NEW_EN)
[grammar] ~502-~502: There might be a mistake here.
Context: ...14854| |
isAttested|
0xc13c2396| |
owner|
0x8da5cb5b| |
ownershipH...
(QB_NEW_EN)
[grammar] ~503-~503: There might be a mistake here.
Context: ...0xc13c2396| |
owner|
0x8da5cb5b| |
ownershipHandoverExpiresAt|
0xfee8...
(QB_NEW_EN)
[grammar] ~504-~504: There might be a mistake here.
Context: ...rshipHandoverExpiresAt|
0xfee81cf4| |
registerSwitchboard|
0x74f5b1fc` |...
(QB_NEW_EN)
[grammar] ~505-~505: There might be a mistake here.
Context: ...| registerSwitchboard
| 0x74f5b1fc
| | renounceOwnership
| 0x715018a6
| |...
(QB_NEW_EN)
[grammar] ~506-~506: There might be a mistake here.
Context: ...| | renounceOwnership
| 0x715018a6
| | requestOwnershipHandover
| `0x256929...
(QB_NEW_EN)
[grammar] ~507-~507: There might be a mistake here.
Context: ...questOwnershipHandover|
0x25692962| |
rescueFunds|
0x6ccae054| |
revo...
(QB_NEW_EN)
[grammar] ~508-~508: There might be a mistake here.
Context: ...2962| |
rescueFunds|
0x6ccae054| |
revokeRole|
0xd547741f| |
socke...
(QB_NEW_EN)
[grammar] ~515-~515: There might be a mistake here.
Context: ...ReadPrecompile | Function | Signature | | -------- | --------- | | expiryTime
...
(QB_NEW_EN)
[grammar] ~516-~516: There might be a mistake here.
Context: ...n | Signature | | -------- | --------- | | expiryTime
| 0x99bc0aea
| | `getPr...
(QB_NEW_EN)
[grammar] ~517-~517: There might be a mistake here.
Context: ...------ | | expiryTime
| 0x99bc0aea
| | getPrecompileFees
| 0xb7a3d04c
| |...
(QB_NEW_EN)
[grammar] ~518-~518: There might be a mistake here.
Context: ...| | getPrecompileFees
| 0xb7a3d04c
| | handlePayload
| 0x1d5e1d98
| | `re...
(QB_NEW_EN)
[grammar] ~519-~519: There might be a mistake here.
Context: ...4c| |
handlePayload|
0x1d5e1d98| |
readFees|
0xe06357a2| |
rescueF...
(QB_NEW_EN)
[grammar] ~520-~520: There might be a mistake here.
Context: ...d5e1d98| |
readFees|
0xe06357a2| |
rescueFunds|
0x6ccae054| |
reso...
(QB_NEW_EN)
[grammar] ~521-~521: There might be a mistake here.
Context: ...57a2| |
rescueFunds|
0x6ccae054| |
resolvePayload|
0xea92e825| |
s...
(QB_NEW_EN)
[grammar] ~522-~522: There might be a mistake here.
Context: ...4| |
resolvePayload|
0xea92e825| |
setExpiryTime|
0x30fc4cff| |
se...
(QB_NEW_EN)
[grammar] ~523-~523: There might be a mistake here.
Context: ...25| |
setExpiryTime|
0x30fc4cff| |
setFees|
0x3d18678e| |
validate...
(QB_NEW_EN)
[grammar] ~524-~524: There might be a mistake here.
Context: ...30fc4cff| |
setFees|
0x3d18678e| |
validateAndGetPrecompileData|
0x99...
(QB_NEW_EN)
[grammar] ~525-~525: There might be a mistake here.
Context: ...teAndGetPrecompileData|
0x997f5bef| |
watcher__|
0x300bb063` | ## Sched...
(QB_NEW_EN)
[grammar] ~530-~530: There might be a mistake here.
Context: ...dulePrecompile | Function | Signature | | -------- | --------- | | expiryTime
...
(QB_NEW_EN)
[grammar] ~531-~531: There might be a mistake here.
Context: ...n | Signature | | -------- | --------- | | expiryTime
| 0x99bc0aea
| | `getPr...
(QB_NEW_EN)
[grammar] ~532-~532: There might be a mistake here.
Context: ...------ | | expiryTime
| 0x99bc0aea
| | getPrecompileFees
| 0xb7a3d04c
| |...
(QB_NEW_EN)
[grammar] ~533-~533: There might be a mistake here.
Context: ...| | getPrecompileFees
| 0xb7a3d04c
| | handlePayload
| 0x1d5e1d98
| | `ma...
(QB_NEW_EN)
[grammar] ~534-~534: There might be a mistake here.
Context: ...4c| |
handlePayload|
0x1d5e1d98| |
maxScheduleDelayInSeconds|
0x3ef01...
(QB_NEW_EN)
[grammar] ~535-~535: There might be a mistake here.
Context: ...ScheduleDelayInSeconds|
0x3ef01cdb| |
rescueFunds|
0x6ccae054| |
reso...
(QB_NEW_EN)
[grammar] ~536-~536: There might be a mistake here.
Context: ...1cdb| |
rescueFunds|
0x6ccae054| |
resolvePayload|
0xea92e825| |
s...
(QB_NEW_EN)
[grammar] ~537-~537: There might be a mistake here.
Context: ...4| |
resolvePayload|
0xea92e825| |
scheduleCallbackFees|
0x4c5b6007` ...
(QB_NEW_EN)
[grammar] ~538-~538: There might be a mistake here.
Context: ... scheduleCallbackFees
| 0x4c5b6007
| | scheduleFeesPerSecond
| 0x852a74c1
...
(QB_NEW_EN)
[grammar] ~539-~539: There might be a mistake here.
Context: ...scheduleFeesPerSecond
| 0x852a74c1
| | setExpiryTime
| 0x30fc4cff
| | `se...
(QB_NEW_EN)
[grammar] ~540-~540: There might be a mistake here.
Context: ...c1| |
setExpiryTime|
0x30fc4cff| |
setMaxScheduleDelayInSeconds|
0x12...
(QB_NEW_EN)
[grammar] ~541-~541: There might be a mistake here.
Context: ...ScheduleDelayInSeconds|
0x12953318| |
setScheduleCallbackFees|
0xec8fd71...
(QB_NEW_EN)
[grammar] ~542-~542: There might be a mistake here.
Context: ...etScheduleCallbackFees|
0xec8fd71e| |
setScheduleFeesPerSecond|
0x28e59e...
(QB_NEW_EN)
[grammar] ~543-~543: There might be a mistake here.
Context: ...tScheduleFeesPerSecond|
0x28e59e57| |
validateAndGetPrecompileData|
0x99...
(QB_NEW_EN)
[grammar] ~544-~544: There might be a mistake here.
Context: ...teAndGetPrecompileData|
0x997f5bef| |
watcher__|
0x300bb063` | ## Write...
(QB_NEW_EN)
EventTopics.md
[grammar] ~40-~40: There might be a mistake here.
Context: ...etBatcher | Event | Arguments | Topic | | ----- | --------- | ----- | | `Ownersh...
(QB_NEW_EN)
[grammar] ~41-~41: There might be a mistake here.
Context: ... | Topic | | ----- | --------- | ----- | | OwnershipHandoverCanceled
| `(pendin...
(QB_NEW_EN)
[grammar] ~42-~42: There might be a mistake here.
Context: ...464468f9bfbae89d1675917346ca6d8fe3c92| |
OwnershipHandoverRequested|
(pendi...
(QB_NEW_EN)
[grammar] ~43-~43: There might be a mistake here.
Context: ...abf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d| |
OwnershipTransferred|
(oldOwner: a...
(QB_NEW_EN)
[grammar] ~117-~117: There might be a mistake here.
Context: ...ncPromise | Event | Arguments | Topic | | ----- | --------- | ----- | | `Initial...
(QB_NEW_EN)
[grammar] ~118-~118: There might be a mistake here.
Context: ... | Topic | | ----- | --------- | ----- | | Initialized
| (version: uint64)
| ...
(QB_NEW_EN)
[grammar] ~123-~123: There might be a mistake here.
Context: ...Forwarder | Event | Arguments | Topic | | ----- | --------- | ----- | | `Initial...
(QB_NEW_EN)
[grammar] ~124-~124: There might be a mistake here.
Context: ... | Topic | | ----- | --------- | ----- | | Initialized
| (version: uint64)
| ...
(QB_NEW_EN)
[grammar] ~125-~125: There might be a mistake here.
Context: ...99e1f2633a7b5936321eed1cdaeb6115181d2| |
OwnershipHandoverCanceled|
(pendin...
(QB_NEW_EN)
[grammar] ~126-~126: There might be a mistake here.
Context: ...464468f9bfbae89d1675917346ca6d8fe3c92| |
OwnershipHandoverRequested|
(pendi...
(QB_NEW_EN)
[grammar] ~127-~127: There might be a mistake here.
Context: ...abf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d| |
OwnershipTransferred|
(oldOwner: a...
(QB_NEW_EN)
[grammar] ~132-~132: There might be a mistake here.
Context: ...Forwarder | Event | Arguments | Topic | | ----- | --------- | ----- | | `Initial...
(QB_NEW_EN)
[grammar] ~133-~133: There might be a mistake here.
Context: ... | Topic | | ----- | --------- | ----- | | Initialized
| (version: uint64)
| ...
(QB_NEW_EN)
[grammar] ~138-~138: There might be a mistake here.
Context: ...derSolana | Event | Arguments | Topic | | ----- | --------- | ----- | | `Initial...
(QB_NEW_EN)
[grammar] ~139-~139: There might be a mistake here.
Context: ... | Topic | | ----- | --------- | ----- | | Initialized
| (version: uint64)
| ...
(QB_NEW_EN)
[grammar] ~144-~144: There might be a mistake here.
Context: ...xyFactory | Event | Arguments | Topic | | ----- | --------- | ----- | | `AdminCh...
(QB_NEW_EN)
[grammar] ~145-~145: There might be a mistake here.
Context: ... | Topic | | ----- | --------- | ----- | | AdminChanged
| `(proxy: address, adm...
(QB_NEW_EN)
[grammar] ~146-~146: There might be a mistake here.
Context: ...588d331ebfa28653d42ae832dc59e38c9798f| |
Deployed|
(proxy: address, impleme...
(QB_NEW_EN)
[grammar] ~147-~147: There might be a mistake here.
Context: ...27ae891d20b2fb91cf3994b6a3bf2b8178082| |
Upgraded|
(proxy: address, impleme...
(QB_NEW_EN)
[grammar] ~152-~152: There might be a mistake here.
Context: ... TestUSDC | Event | Arguments | Topic | | ----- | --------- | ----- | | `Approva...
(QB_NEW_EN)
[grammar] ~153-~153: There might be a mistake here.
Context: ... | Topic | | ----- | --------- | ----- | | Approval
| `(owner: address, spender...
(QB_NEW_EN)
[grammar] ~154-~154: There might be a mistake here.
Context: ...e84f3dd0314c0f7b2291e5b200ac8c7c3b925| |
Transfer|
(from: address, to: addr...
(QB_NEW_EN)
[grammar] ~200-~200: There might be a mistake here.
Context: ...eResolver | Event | Arguments | Topic | | ----- | --------- | ----- | | `MarkedR...
(QB_NEW_EN)
[grammar] ~201-~201: There might be a mistake here.
Context: ... | Topic | | ----- | --------- | ----- | | MarkedRevert
| `(payloadId: bytes32,...
(QB_NEW_EN)
[grammar] ~202-~202: There might be a mistake here.
Context: ...c834fe98da3ddac44deb77fffd22ad933824c| |
PromiseNotResolved|
(payloadId: by...
(QB_NEW_EN)
[grammar] ~203-~203: There might be a mistake here.
Context: ...439395bd5fb5c39bca3547b126fe6ee467937| |
PromiseResolved|
(payloadId: bytes...
(QB_NEW_EN)
[grammar] ~247-~247: There might be a mistake here.
Context: ...recompile | Event | Arguments | Topic | | ----- | --------- | ----- | | `ExpiryT...
(QB_NEW_EN)
[grammar] ~248-~248: There might be a mistake here.
Context: ... | Topic | | ----- | --------- | ----- | | ExpiryTimeSet
| `(expiryTime: uint25...
(QB_NEW_EN)
[grammar] ~249-~249: There might be a mistake here.
Context: ...bbf12de19f06df79cb0be12b3a7d7f2397fa9| |
ReadFeesSet|
(readFees: uint256)` ...
(QB_NEW_EN)
[grammar] ~250-~250: There might be a mistake here.
Context: ...606ffc54ac8a169e1568fc834c7813010f926| |
ReadRequested|
(transaction: tuple...
(QB_NEW_EN)
Errors.md
[grammar] ~6-~6: There might be a mistake here.
Context: ...fees/FeesPool.sol | Error | Signature | |-------|-----------| | `TransferFailed(...
(QB_NEW_EN)
[grammar] ~7-~7: There might be a mistake here.
Context: ...rror | Signature | |-------|-----------| | TransferFailed()
| 0x90b8ec18
| #...
(QB_NEW_EN)
[grammar] ~12-~12: There might be a mistake here.
Context: .../AsyncPromise.sol | Error | Signature | |-------|-----------| | `PromiseAlreadyR...
(QB_NEW_EN)
[grammar] ~13-~13: There might be a mistake here.
Context: ...rror | Signature | |-------|-----------| | PromiseAlreadyResolved()
| `0x56b635...
(QB_NEW_EN)
[grammar] ~14-~14: There might be a mistake here.
Context: ...omiseAlreadyResolved()|
0x56b63537| |
OnlyInvoker()|
0x74ed21f5| |
Pr...
(QB_NEW_EN)
[grammar] ~15-~15: There might be a mistake here.
Context: ...37| |
OnlyInvoker()|
0x74ed21f5| |
PromiseAlreadySetUp()|
0x927c53d5`...
(QB_NEW_EN)
[grammar] ~16-~16: There might be a mistake here.
Context: ...PromiseAlreadySetUp()
| 0x927c53d5
| | PromiseRevertFailed()
| 0x0175b9de
...
(QB_NEW_EN)
[grammar] ~17-~17: There might be a mistake here.
Context: ...PromiseRevertFailed()
| 0x0175b9de
| | NotLatestPromise()
| 0x39ca95d3
| ...
(QB_NEW_EN)
[grammar] ~22-~22: There might be a mistake here.
Context: ...rwarderSolana.sol | Error | Signature | |-------|-----------| | `InvalidSolanaCh...
(QB_NEW_EN)
[grammar] ~23-~23: There might be a mistake here.
Context: ...rror | Signature | |-------|-----------| | InvalidSolanaChainSlug()
| `0xe37803...
(QB_NEW_EN)
[grammar] ~24-~24: There might be a mistake here.
Context: ...validSolanaChainSlug()|
0xe37803ab| |
AddressResolverNotSet()|
0x6d55276...
(QB_NEW_EN)
[grammar] ~29-~29: There might be a mistake here.
Context: ...ctFactoryPlug.sol | Error | Signature | |-------|-----------| | `DeploymentFaile...
(QB_NEW_EN)
[grammar] ~30-~30: There might be a mistake here.
Context: ...rror | Signature | |-------|-----------| | DeploymentFailed()
| 0x30116425
| ...
(QB_NEW_EN)
[grammar] ~31-~31: There might be a mistake here.
Context: ... | DeploymentFailed()
| 0x30116425
| | ExecutionFailed(bytes32,bytes)
| `0x...
(QB_NEW_EN)
[grammar] ~32-~32: There might be a mistake here.
Context: ...nFailed(bytes32,bytes)|
0xd255d8a3| |
information(bool,,bytes)|
0x3a82a1...
(QB_NEW_EN)
[grammar] ~37-~37: There might be a mistake here.
Context: ...lugs/FeesPlug.sol | Error | Signature | |-------|-----------| | `InsufficientTok...
(QB_NEW_EN)
[grammar] ~38-~38: There might be a mistake here.
Context: ...rror | Signature | |-------|-----------| | `InsufficientTokenBalance(address,uint...
(QB_NEW_EN)
[grammar] ~39-~39: There might be a mistake here.
Context: ...dress,uint256,uint256)|
0xebd6ced9| |
InvalidDepositAmount()|
0xfe9ba5cd...
(QB_NEW_EN)
[grammar] ~40-~40: There might be a mistake here.
Context: ...InvalidDepositAmount()|
0xfe9ba5cd| |
TokenNotWhitelisted(address)|
0xea...
(QB_NEW_EN)
[grammar] ~45-~45: There might be a mistake here.
Context: ...equestHandler.sol | Error | Signature | |-------|-----------| | `InsufficientMax...
(QB_NEW_EN)
[grammar] ~46-~46: There might be a mistake here.
Context: ...rror | Signature | |-------|-----------| | InsufficientMaxFees()
| 0x0e5bc492
...
(QB_NEW_EN)
[grammar] ~51-~51: There might be a mistake here.
Context: ...otocol/Socket.sol | Error | Signature | |-------|-----------| | `PayloadAlreadyE...
(QB_NEW_EN)
[grammar] ~52-~52: There might be a mistake here.
Context: ...rror | Signature | |-------|-----------| | `PayloadAlreadyExecuted(ExecutionStatu...
(QB_NEW_EN)
[grammar] ~53-~53: There might be a mistake here.
Context: ...cuted(ExecutionStatus)|
0xf4c54edd| |
VerificationFailed()|
0x439cc0cd` ...
(QB_NEW_EN)
[grammar] ~54-~54: There might be a mistake here.
Context: ... VerificationFailed()
| 0x439cc0cd
| | LowGasLimit()
| 0xd38edae0
| | `In...
(QB_NEW_EN)
[grammar] ~55-~55: There might be a mistake here.
Context: ...cd| |
LowGasLimit()|
0xd38edae0| |
InsufficientMsgValue()|
0x78f38f76...
(QB_NEW_EN)
[grammar] ~60-~60: There might be a mistake here.
Context: .../SocketConfig.sol | Error | Signature | |-------|-----------| | `SwitchboardExis...
(QB_NEW_EN)
[grammar] ~61-~61: There might be a mistake here.
Context: ...rror | Signature | |-------|-----------| | SwitchboardExists()
| 0x2dff8555
|...
(QB_NEW_EN)
[grammar] ~62-~62: There might be a mistake here.
Context: ...| SwitchboardExists()
| 0x2dff8555
| | SwitchboardExistsOrDisabled()
| `0x1...
(QB_NEW_EN)
[grammar] ~67-~67: There might be a mistake here.
Context: ...ketFeeManager.sol | Error | Signature | |-------|-----------| | `InsufficientFee...
(QB_NEW_EN)
[grammar] ~68-~68: There might be a mistake here.
Context: ...rror | Signature | |-------|-----------| | InsufficientFees()
| 0x8d53e553
| ...
(QB_NEW_EN)
[grammar] ~69-~69: There might be a mistake here.
Context: ... | InsufficientFees()
| 0x8d53e553
| | FeeTooLow()
| 0x732f9413
| ## pro...
(QB_NEW_EN)
[grammar] ~74-~74: There might be a mistake here.
Context: ...l/SocketUtils.sol | Error | Signature | |-------|-----------| | OnlyOffChain()
...
(QB_NEW_EN)
[grammar] ~75-~75: There might be a mistake here.
Context: ...rror | Signature | |-------|-----------| | OnlyOffChain()
| 0x9cbfe066
| | `S...
(QB_NEW_EN)
[grammar] ~76-~76: There might be a mistake here.
Context: ...---| | OnlyOffChain()
| 0x9cbfe066
| | SimulationFailed()
| 0x2fbab3ac
| ...
(QB_NEW_EN)
[grammar] ~81-~81: There might be a mistake here.
Context: ...stSwitchboard.sol | Error | Signature | |-------|-----------| | `AlreadyAttested...
(QB_NEW_EN)
[grammar] ~82-~82: There might be a mistake here.
Context: ...rror | Signature | |-------|-----------| | AlreadyAttested()
| 0x35d90805
| |...
(QB_NEW_EN)
[grammar] ~83-~83: There might be a mistake here.
Context: ...| | AlreadyAttested()
| 0x35d90805
| | WatcherNotFound()
| 0xa278e4ad
| ...
(QB_NEW_EN)
[grammar] ~88-~88: There might be a mistake here.
Context: ...AccessControl.sol | Error | Signature | |-------|-----------| | `NoPermit(bytes3...
(QB_NEW_EN)
[grammar] ~89-~89: There might be a mistake here.
Context: ...rror | Signature | |-------|-----------| | NoPermit(bytes32)
| 0x962f6333
| ...
(QB_NEW_EN)
[grammar] ~94-~94: There might be a mistake here.
Context: ...on/Converters.sol | Error | Signature | |-------|-----------| | `NotAnEvmAddress...
(QB_NEW_EN)
[grammar] ~95-~95: There might be a mistake here.
Context: ...rror | Signature | |-------|-----------| | NotAnEvmAddress(bytes32)
| `0x33b960...
(QB_NEW_EN)
🔇 Additional comments (8)
EventTopics.md (4)
5-18
: Docs reflow is consistent and readable.Uniform 3-column tables improve scanability; hashes and args look unchanged.
132-135
: Confirm Forwarder ownership events removal from this section.If Forwarder still inherits/uses OwnershipHandover* and OwnershipTransferred, this section should list them for discoverability.
136-141
: ForwarderSolana: add-only looks good; verify no other events are emitted.If the contract also emits ownership/role events via base contracts, include them here for parity with other sections.
266-278
: WritePrecompile events: new digest fields acknowledged.The WriteProofRequested args list (including prevBatchDigestHash, deadline) matches recent code paths.
foundry.toml (1)
12-39
: Verify label references and Contracts enum updatesNo duplicate addresses detected in foundry.toml. You still need to confirm that the new labels are properly wired into your code:
• Ensure the
Contracts
enum (wherever it’s defined) includes bothForwarderSolana
andForwarderSolanaImpl
.
• Search code and scripts for usages of these labels (e.g.labels.ForwarderSolana
,labels.APP_GATEWAY
,labels.WritePrecompileImpl
,labels.RequestHandlerImpl
) and add missing references.
• Update any deployment or test helpers that consume the[labels]
block to handle the new entries.Errors.md (1)
35-42
: Ignore stale ownership comment: docs correctly list errors in FeesPlug.solrg shows both
InvalidDepositAmount()
andTokenNotWhitelisted(address token_)
are still declared in contracts/evmx/plugs/FeesPlug.sol (at lines 31 and 33). No other “Configurations” contract declares these errors. The docs should continue listing them under FeesPlug to match the code.Likely an incorrect or invalid review comment.
FunctionSignatures.md (2)
284-299
: Forwarder section lists both chainSlug and getChainSlug; confirm both exist.If one is legacy, deprecate or annotate to reduce confusion for integrators.
300-315
: Verify ForwarderSolana selectors align with compiled output
The documented selectors in FunctionSignatures.md must match the on-chain compiled signatures to prevent tooling drift. The automated Node.js check failed due to a missing ethers dependency. This should be manually verified against the contract ABI or using a keccak256 tool.• Functions to verify:
– callSolana((bytes32,bytes,bytes,bytes,bytes,bytes,bytes)[]) → 0x4ef7957b
– getChainSlug() → 0xb349ba65
– getOnChainAddress() → 0x9da48789
– initialize(uint32,bytes32,address) → 0x148841cb
– onChainAddress() → 0x8bd0b363
– chainSlug() → 0xb349ba65
– addressResolver__() → 0x6a750469
– asyncDeployer__() → 0x2a39e801
– deployForwarder__() → 0xd4e3b034
– feesManager__() → 0x70568b58
– watcher__() → 0x300bb063
Errors.md
Outdated
| `DeploymentFailed()` | `0x30116425` | | ||
| `ExecutionFailed(bytes32,bytes)` | `0xd255d8a3` | | ||
| `information(bool,,bytes)` | `0x3a82a1f3` | | ||
| `information(bool,,bytes)` | `0x3a82a1f3` | | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in error entry: double comma in parameters.
information(bool,,bytes)
has an extra comma and likely an incorrect name. Fix the signature immediately to avoid propagating a bad ABI reference.
Apply:
-| `information(bool,,bytes)` | `0x3a82a1f3` |
+| `information(bool,bytes)` | `0x3a82a1f3` |
If the actual error differs, replace with the correct identifier and selector.
📝 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.
| `DeploymentFailed()` | `0x30116425` | | |
| `ExecutionFailed(bytes32,bytes)` | `0xd255d8a3` | | |
| `information(bool,,bytes)` | `0x3a82a1f3` | | |
| `information(bool,,bytes)` | `0x3a82a1f3` | | |
| `DeploymentFailed()` | `0x30116425` | | |
| `ExecutionFailed(bytes32,bytes)` | `0xd255d8a3` | | |
| `information(bool,bytes)` | `0x3a82a1f3` | |
🧰 Tools
🪛 LanguageTool
[grammar] ~31-~31: There might be a mistake here.
Context: ... | DeploymentFailed()
| 0x30116425
| | ExecutionFailed(bytes32,bytes)
| `0x...
(QB_NEW_EN)
[grammar] ~32-~32: There might be a mistake here.
Context: ...nFailed(bytes32,bytes)|
0xd255d8a3| |
information(bool,,bytes)|
0x3a82a1...
(QB_NEW_EN)
🤖 Prompt for AI Agents
In Errors.md around lines 31 to 34, the error entry `information(bool,,bytes)`
contains a stray comma and possibly the wrong name; remove the extra comma to
make the signature `information(bool,bytes)` and then verify against the
contract ABI to ensure the error name and its selector (0x3a82a1f3) are correct
— if the ABI shows a different name or selector, update the entry to the exact
ABI signature and corresponding selector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 28
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (21)
contracts/protocol/interfaces/ISocketBatcher.sol (1)
13-20
: Missing @param for switchboardId_ and incomplete @return docs.NatSpec must cover all params and both return values.
* @notice Attests a payload and executes it * @param executeParams_ The execution parameters + * @param switchboardId_ The Switchboard identifier used to verify the attestation * @param digest_ The digest of the payload * @param proof_ The proof of the payload * @param transmitterSignature_ The signature of the transmitter * @param refundAddress_ The address to refund the fees to - * @return The return data after execution + * @return success True if execution succeeded + * @return returnData ABI-encoded return data from the executed call + * @dev Define behavior for refundAddress_ == address(0) (revert or default to msg.sender).contracts/utils/common/Errors.sol (1)
78-80
: Unify access-control errors — remove legacy Not and use Only*Allowed*Both error families coexist; this should be unified to avoid inconsistent revert types and downstream decoding complexity.
- This should replace
revert NotRequestHandler();
→revert OnlyRequestHandlerAllowed();
in contracts/evmx/fees/FeesManager.sol (line 33).- This should replace
revert NotPromiseResolver();
→revert OnlyPromiseResolverAllowed();
in contracts/evmx/watcher/RequestHandler.sol (line 91).- This should remove the legacy definitions
error NotRequestHandler();
anderror NotPromiseResolver();
from contracts/utils/common/Errors.sol (lines ~61, ~63). WatcherBase already usesOnlyRequestHandlerAllowed
/OnlyPromiseResolverAllowed
(lines ~23, ~28).Verify there are no remaining usages: rg -n '\bNot(RequestHandler|PromiseResolver)('.
contracts/evmx/watcher/Configurations.sol (2)
121-132
: NatSpec says “Only callable by the app gateway” but code restricts to watcher. Fix the authorization docs.The function is
onlyWatcher
. The doc is wrong and misleading for integrators and audits. Update the comment to match code.- /// @dev Only callable by the app gateway + /// @dev Only callable by the watcher
67-73
: Revert event parameter reordering or add IsValidPlugSetV2 — this is a breaking ABI change.Reordering event params changes the ABI and breaks existing consumers (EventTopics.md documents the old signature). This should keep the original IsValidPlugSet signature and introduce a new IsValidPlugSetV2 with the new order; emit both during a deprecation window.
Locations:
- contracts/evmx/watcher/Configurations.sol — event declaration (line ~72) and emit (line ~134).
- test/evmx/Watcher.t.sol — vm.expectEmit / emit usage (around line ~465).
- EventTopics.md — current entry documents the prior signature (line ~191).
Apply (keep original event, add V2, emit both):
- /// @notice Emitted when a valid plug is set for an app gateway - /// @param appGateway The address of the app gateway - /// @param chainSlug The identifier of the network - /// @param plug The address of the plug - /// @param isValid Whether the plug is valid - event IsValidPlugSet(bool isValid, uint32 chainSlug, bytes32 plug, address appGateway); + /// @notice Emitted when a valid plug is set for an app gateway (backwards-compatible) + /// @param appGateway The address of the app gateway + /// @param chainSlug The identifier of the network + /// @param plug The address of the plug + /// @param isValid Whether the plug is valid + event IsValidPlugSet(address appGateway, uint32 chainSlug, bytes32 plug, bool isValid); + /// @notice New event with reordered params + event IsValidPlugSetV2(bool isValid, uint32 chainSlug, bytes32 plug, address appGateway); @@ - emit IsValidPlugSet(isValid_, chainSlug_, plug_, appGateway_); + emit IsValidPlugSet(appGateway_, chainSlug_, plug_, isValid_); + emit IsValidPlugSetV2(isValid_, chainSlug_, plug_, appGateway_);contracts/protocol/base/PlugBase.sol (2)
76-89
: Lock down initSocket: anyone can one-shot bind this plug to an arbitrary socketinitSocket is external, callable once, and permanently sets socket__/appGatewayId. Any EOAs/contracts can front‑run deployment wiring and hijack the plug. This should be owner/factory gated (or made internal and exposed by derived contracts with their own ACL). Emit an initialization event for observability.
Primary fix (Ownable-based ACL + event):
-abstract contract PlugBase is IPlug { +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +abstract contract PlugBase is IPlug, Ownable { + event SocketInitialized(bytes32 appGatewayId, address socket, uint64 switchboardId); @@ - function initSocket( + function initSocket( bytes32 appGatewayId_, address socket_, uint64 switchboardId_ - ) external virtual socketInitializer { - _connectSocket(appGatewayId_, socket_, switchboardId_); - } + ) external virtual socketInitializer onlyOwner { + _connectSocket(appGatewayId_, socket_, switchboardId_); + emit SocketInitialized(appGatewayId_, socket_, switchboardId_); + }If OZ Ownable is not available, alternative (make it internal; derived contracts expose a guarded external wrapper):
- ) external virtual socketInitializer { + ) internal virtual socketInitializer { _connectSocket(appGatewayId_, socket_, switchboardId_); }
41-55
: Validate inputs before connecting socketThis should reject zero appGatewayId and zero socket to avoid writing invalid state and external calls that revert deeper.
function _connectSocket( bytes32 appGatewayId_, address socket_, uint64 switchboardId_ ) internal { - _setSocket(socket_); - appGatewayId = appGatewayId_; + require(socket_ != address(0), "PlugBase: socket zero"); + require(appGatewayId_ != bytes32(0), "PlugBase: appGatewayId zero"); + _setSocket(socket_); + appGatewayId = appGatewayId_; // connect to the app gateway and switchboard socket__.connect(appGatewayId_, switchboardId_); }script/counter/WithdrawFeesArbitrumFeesPlug.s.sol (1)
30-41
: Do not subtract ETH gas cost from a USDC-denominated balance.availableFees are token credits (USDC). estimatedGasCost is in wei. Subtracting across currencies is a logic bug and will produce incorrect amounts.
Minimal fix (keep it operational; remove the cross-currency subtraction):
- // Calculate amount to withdraw - uint256 amountToWithdraw = availableFees > estimatedGasCost - ? availableFees - estimatedGasCost - : 0; + // Calculate amount to withdraw (no cross-currency subtraction) + uint256 amountToWithdraw = availableFees;If you need gas-cost-aware withdrawals, this should convert ETH gas cost to USDC via a price feed (off-chain or on-chain oracle) before comparing.
contracts/evmx/watcher/Trigger.sol (1)
31-44
: Set the "already-called" guard before any external calls — pull fees after state changes.This should follow checks-effects-interactions: set triggerFromChainSlug, triggerFromPlug and isAppGatewayCalled[params_.triggerId] = true before calling the ERC20 transferFrom or appGateway.tryCall. Use OpenZeppelin SafeERC20.safeTransferFrom (or otherwise require the transfer success) to handle non-standard tokens. A failing transferFrom that reverts will roll back the state (so it will NOT leave the trigger marked); only an unhandled, non-reverting token could leave the guard set.
File: contracts/evmx/watcher/Trigger.sol (around lines 31–44).
contracts/evmx/watcher/precompiles/SchedulePrecompile.sol (4)
59-62
: Fix invalid delay check: comparing against uninitialized expiryTime.Constructor checks
maxScheduleDelayInSeconds < expiryTime
before assigningexpiryTime
, so the guard is ineffective. SetexpiryTime
first, then validate.- if (maxScheduleDelayInSeconds < expiryTime) revert InvalidScheduleDelay(); - expiryTime = expiryTime_; + expiryTime = expiryTime_; + if (maxScheduleDelayInSeconds < expiryTime) revert InvalidScheduleDelay();
73-77
: Use the parameter in the guard, not the old state.The setter validates the old
maxScheduleDelayInSeconds
instead of the incoming value.- if (maxScheduleDelayInSeconds < expiryTime) revert InvalidScheduleDelay(); - maxScheduleDelayInSeconds = maxScheduleDelayInSeconds_; + if (maxScheduleDelayInSeconds_ < expiryTime) revert InvalidScheduleDelay(); + maxScheduleDelayInSeconds = maxScheduleDelayInSeconds_;
101-105
: Validate new expiryTime against current max delay.This check accidentally compares current
expiryTime
instead of the newexpiryTime_
.- if (maxScheduleDelayInSeconds < expiryTime) revert InvalidScheduleDelay(); - expiryTime = expiryTime_; + if (maxScheduleDelayInSeconds < expiryTime_) revert InvalidScheduleDelay(); + expiryTime = expiryTime_;
64-67
: Decode shape mismatch vs callers encoding two words.Callers encode
(delayInSeconds, executeAfterPlaceholder)
, butgetPrecompileFees
decodes a singleuint256
. Make the decoder accept both encodings.- function getPrecompileFees(bytes memory precompileData_) public view returns (uint256) { - uint256 delayInSeconds = abi.decode(precompileData_, (uint256)); - return scheduleFeesPerSecond * delayInSeconds + scheduleCallbackFees; - } + function getPrecompileFees(bytes memory precompileData_) public view returns (uint256) { + uint256 delayInSeconds; + if (precompileData_.length == 32) { + delayInSeconds = abi.decode(precompileData_, (uint256)); + } else { + (delayInSeconds, ) = abi.decode(precompileData_, (uint256, uint256)); + } + return scheduleFeesPerSecond * delayInSeconds + scheduleCallbackFees; + }hardhat-scripts/deploy/1.deploy.ts (1)
100-105
: Await getWatcherSigner; current code assigns a Promise to signer.This breaks
signer.address
and downstream deployments.- const signer: Wallet = getWatcherSigner(); + const signer: Wallet = await getWatcherSigner();script/helpers/TransferRemainingCredits.s.sol (1)
31-37
: Fix: calling transferFrom on the wrong contract (will always fail).This calls transferFrom on appGateway, but transferFrom is on FeesManager. This should invoke the typed method on feesManager (and avoid fragile string signatures). Also skip zero-amount transfers.
Apply:
- bytes memory data = abi.encodeWithSignature( - "transferFrom(address,address,uint256)", - appGateway, - newAppGateway, - availableFees - ); - (bool success, ) = appGateway.call(data); - require(success, "Transfer failed"); + require(availableFees > 0, "No available fees to transfer"); + feesManager.transferFrom(appGateway, newAppGateway, availableFees);hardhat-scripts/deploy/9.setupTransmitter.ts (2)
64-82
: Top up only the delta to threshold, not the full threshold.Depositing the full threshold every time underfunded over-allocates capital. Compute needed = threshold - current.
export const checkAndDepositCredits = async (transmitter: string) => { console.log("Checking and depositing credits"); const credits = await feesManagerContract .connect(transmitterSigner) .balanceOf(transmitter); - if (credits.lt(TRANSMITTER_CREDIT_THRESHOLD)) { + if (credits.lt(TRANSMITTER_CREDIT_THRESHOLD)) { + const needed = TRANSMITTER_CREDIT_THRESHOLD.sub(credits); console.log("Depositing credits for transmitter..."); const tx = await feesManagerContract .connect(getWatcherSigner()) - .wrap(transmitter, { + .wrap(transmitter, { ...(await overrides(EVMX_CHAIN_ID as ChainSlug)), - value: TRANSMITTER_CREDIT_THRESHOLD, + value: needed, });
84-101
: Top up native only to the threshold.Mirror the credit top-up logic for native balance.
export const checkAndDepositNative = async (transmitter: string) => { console.log("Checking and depositing native"); const nativeBalance = await transmitterSigner.provider!.getBalance( transmitter ); if (nativeBalance.lt(TRANSMITTER_NATIVE_THRESHOLD)) { + const needed = TRANSMITTER_NATIVE_THRESHOLD.sub(nativeBalance); console.log("Depositing native for transmitter..."); const tx = await getWatcherSigner().sendTransaction({ to: transmitter, - value: TRANSMITTER_NATIVE_THRESHOLD, + value: needed, ...(await overrides(EVMX_CHAIN_ID as ChainSlug)), });contracts/protocol/SocketBatcher.sol (1)
92-104
: Don’t call syncOut when execute fails.This should only advance batch state after a successful execute; calling
syncOut
on failure can desync chains.Apply:
- (bool success, bytes memory returnData) = socket__.execute{value: msg.value}( + (bool success, bytes memory returnData) = socket__.execute{value: msg.value}( execParams_.executeParams, TransmissionParams({ transmitterProof: execParams_.transmitterSignature, socketFees: 0, extraData: execParams_.executeParams.extraData, refundAddress: execParams_.refundAddress }) ); - - ICCTPSwitchboard(switchboard).syncOut(payloadId, cctpParams_.nextBatchRemoteChainSlugs); - return (success, returnData); + if (success) { + ICCTPSwitchboard(switchboard).syncOut(payloadId, cctpParams_.nextBatchRemoteChainSlugs); + } + return (success, returnData);contracts/evmx/AuctionManager.sol (1)
165-169
: Fix inverted OPEN check in _startAuction().This currently reverts unless status is already OPEN. It should allow NOT_STARTED/RESTARTED and then mark OPEN.
- function _startAuction(uint40 requestCount_) internal { - if (auctionStatus[requestCount_] != AuctionStatus.OPEN) revert AuctionNotOpen(); - auctionStatus[requestCount_] = AuctionStatus.OPEN; - emit AuctionStarted(requestCount_); - } + function _startAuction(uint40 requestCount_) internal { + if ( + auctionStatus[requestCount_] != AuctionStatus.NOT_STARTED && + auctionStatus[requestCount_] != AuctionStatus.RESTARTED + ) revert AuctionNotOpen(); + auctionStatus[requestCount_] = AuctionStatus.OPEN; + emit AuctionStarted(requestCount_); + }test/SetupTest.t.sol (1)
1123-1128
: ABI decode type mismatch for precompileData (6th tuple item).You decode the 6th field as address, elsewhere as uint64. Mismatch will revert at runtime.
- (address, Transaction, WriteFinality, uint256, uint256, address) + (address, Transaction, WriteFinality, uint256, uint256, uint64)contracts/evmx/fees/Credit.sol (2)
241-251
: isCreditSpendable ignores allowance size; only checks non-zeroThis returns true for any non-zero allowance, then
transferFrom
can revert. It should requireallowance(consumeFrom_, spender_) >= amount_
for non-watcher spenders. Also use available balance, not overriddenbalanceOf
.- if (!_isWatcher(spender_) && consumeFrom_ != spender_) { - if (allowance(consumeFrom_, spender_) == 0) return false; - } - return balanceOf(consumeFrom_) >= amount_; + if (!_isWatcher(spender_) && consumeFrom_ != spender_) { + if (allowance(consumeFrom_, spender_) < amount_) return false; + } + return availableBalanceOf(consumeFrom_) >= amount_;
329-352
: withdrawCredits doesn’t lockmaxFees_
; race enables fee-evading spendsYou require
available >= credits_ + maxFees_
but only burncredits_
. Without lockingmaxFees_
, the caller can spend those before processing. This should blockmaxFees_
from the user, track it by request, and unblock/consume on settle/revert.Suggested approach:
- On enqueue:
userBlockedCredits[consumeFrom] += maxFees_; requestBlockedCredits[requestId] = maxFees_;
- On settle success: burn or transfer the blocked fees; on revert:
userBlockedCredits[consumeFrom] -= requestBlockedCredits[requestId];
- Emit events on block/unblock.
Update_createRequest
to return/capturerequestId
(or emit and react) so you can map blocked funds to the request.
♻️ Duplicate comments (6)
contracts/evmx/watcher/precompiles/WritePrecompile.sol (3)
306-311
: Add tests that assert Solana payload packing order/discriminator/programId/accounts.Digest integrity depends on exact packing. Tests should compute a reference digest and compare.
- Assert order: programId || accounts[] || discriminator || borsh(args).
- Include at least one multi-account, multi-arg case.
300-331
: Remove hardcoded Solana socket; resolve from configuration and assert non-zero.Hardcoding breaks correctness and upgrades. Use configured socket and revert if zero.
- // bytes32 of Solana Socket address : 9vFEQ5e3xf4eo17WttfqmXmnqN3gUicrhFGppmmNwyqV - bytes32 hardcodedSocket = 0x84815e8ca2f6dad7e12902c39a51bc72e13c48139b4fb10025d94e7abea2969c; - return - DigestParams( - // watcherPrecompileConfig__.sockets(params_.payloadHeader.getChainSlug()), // TODO: this does not work, for some reason it returns 0x000.... address - hardcodedSocket, + bytes32 socket_ = configurations__().sockets(transaction_.chainSlug); + require(socket_ != bytes32(0), "socket not configured for chain"); + return + DigestParams( + socket_, toBytes32Format(transmitter_), payloadParams_.payloadId, deadline_, payloadParams_.callType, gasLimit_, value_, payloadPacked, transaction_.target, toBytes32Format(appGateway_), prevBatchDigestHash_, bytes("") );
263-288
: Require a configured socket (non-zero) in EVM path to avoid corrupt digests.Digest must include the real configured socket. A zero socket produces unverifiable digests.
- return - DigestParams( - configurations__().sockets(transaction_.chainSlug), + bytes32 socket_ = configurations__().sockets(transaction_.chainSlug); + require(socket_ != bytes32(0), "socket not configured for chain"); + return + DigestParams( + socket_, toBytes32Format(transmitter_), payloadParams_.payloadId, deadline_, payloadParams_.callType, gasLimit_, value_, transaction_.payload, transaction_.target, toBytes32Format(appGateway_), prevBatchDigestHash_, bytes("") );hardhat-scripts/deploy/3.configureChains.ts (1)
187-208
: Normalize SWITCHBOARD_SOLANA and fix missing import; compare/set with the same canonical value.This block reads the env unsafely, logs a misleading “reversed” hex, passes a raw string to
requiredValue
, and usestoBytes32Format
without importing it. This should: (1) guard the env read, (2) normalize to a 0x-prefixed 32-byte hex once, (3) use that normalized value for both compare and setter args, (4) log the normalized hex, and (5) importtoBytes32Format
.Apply:
@@ -import { +import { DeployParams, getAddresses, getInstance, getSocketSigner, getWatcherSigner, overrides, storeAddresses, toBytes32FormatHexString, + toBytes32Format, updateContractSettings, } from "../utils"; @@ - console.log("XXX Setting solana switchboard"); - console.log("FAST_SWITCHBOARD_TYPE: ", FAST_SWITCHBOARD_TYPE); - const solanaSwitchboard = process.env.SWITCHBOARD_SOLANA; - if (!solanaSwitchboard) throw new Error("SWITCHBOARD_SOLANA is not set"); - console.log( - "solanaSwitchboard as bytes32 reversed: ", - Buffer.from(toBytes32Format(solanaSwitchboard)).toString("hex") - ); + console.log("Setting solana switchboard"); + console.log("FAST_SWITCHBOARD_TYPE:", FAST_SWITCHBOARD_TYPE); + const solanaSwitchboardRaw = process.env.SWITCHBOARD_SOLANA; + if (!solanaSwitchboardRaw) throw new Error("SWITCHBOARD_SOLANA is not set"); + const solanaSwitchboardHex = toBytes32FormatHexString(solanaSwitchboardRaw); + console.log("solanaSwitchboard (bytes32):", solanaSwitchboardHex); await updateContractSettings( EVMX_CHAIN_ID, Contracts.Configurations, "switchboards", [ChainSlug.SOLANA_DEVNET, FAST_SWITCHBOARD_TYPE], - solanaSwitchboard, + solanaSwitchboardHex, "setSwitchboard", [ ChainSlug.SOLANA_DEVNET, FAST_SWITCHBOARD_TYPE, - toBytes32Format(solanaSwitchboard), + toBytes32Format(solanaSwitchboardHex), ], signer );hardhat-scripts/deploy/6.connect.ts (2)
158-189
: Unsafe env read and inconsistent hex formatting for Solana POC.
.slice(2)
before null-check can throw; manual Buffer concatenation produces non-normalized hex; align with bytes32 helpers.-//TODO:GW: This is a temporary workaround for th Solana POC +// TODO:GW: Temporary workaround for the Solana POC @@ -const appGatewayAddress = process.env.APP_GATEWAY; -if (!appGatewayAddress) throw new Error("APP_GATEWAY is not set"); -const solanaSwitchboard = process.env.SWITCHBOARD_SOLANA!.slice(2); // remove 0x prefix for Buffer from conversion -if (!solanaSwitchboard) throw new Error("SWITCHBOARD_SOLANA is not set"); - -const solanaSwitchboardBytes32 = Buffer.from(solanaSwitchboard, "hex"); -const solanaAppGatewayId = ethers.utils.hexZeroPad(appGatewayAddress, 32); +const appGatewayAddress = process.env.APP_GATEWAY; +if (!appGatewayAddress) throw new Error("APP_GATEWAY is not set"); +const solanaSwitchboardRaw = process.env.SWITCHBOARD_SOLANA; +if (!solanaSwitchboardRaw) throw new Error("SWITCHBOARD_SOLANA is not set"); +const solanaSwitchboardBytes32Hex = toBytes32FormatHexString(solanaSwitchboardRaw); +const solanaAppGatewayId = toBytes32FormatHexString(appGatewayAddress); @@ -console.log("SolanaAppGatewayId: ", solanaAppGatewayId); -console.log( - "SolanaSwitchboardBytes32: ", - solanaSwitchboardBytes32.toString("hex") -); +console.log("SolanaAppGatewayId:", solanaAppGatewayId); +console.log("SolanaSwitchboardBytes32:", solanaSwitchboardBytes32Hex); @@ - plugConfig: { - appGatewayId: solanaAppGatewayId, - switchboard: "0x" + solanaSwitchboardBytes32.toString("hex"), - }, + plugConfig: { + appGatewayId: solanaAppGatewayId, + switchboard: solanaSwitchboardBytes32Hex, + },
1-1
: ethers is used but not imported.
ethers.utils.hexZeroPad
is referenced later; this will crash at runtime/compile. Either importethers
or replace with the existing bytes32 helper.Fix by avoiding
ethers
:-const solanaAppGatewayId = ethers.utils.hexZeroPad(appGatewayAddress, 32); +const solanaAppGatewayId = toBytes32FormatHexString(appGatewayAddress);
IERC20(address(feesManager__())).transferFrom(from_, to_, watcherFees); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Revisit fee movement semantics in deductScheduleFees().
Switching to IERC20(address(feesManager__())).transferFrom(from_, to_, watcherFees)
moves credits to to_
(often address(this)
or the same transmitter), not to the watcher/escrow. This should reserve/pay schedule fees in the same place the watcher expects (previously via feesManager__().transferCredits(...)
). As-is, fees risk sitting on this contract and not being consumed.
Run to trace fee flow and confirm no stranded balances:
Expected: either (a) watcher consumes from AuctionManager balance, or (b) credits are moved to a watcher-owned escrow. If neither, revert to a transferCredits
-style reservation or route to_
to the correct escrow.
🏁 Script executed:
#!/bin/bash
rg -nP -C3 'deductScheduleFees\(|transferCredits\(|feesManager__\(\).*transferFrom\(|getPrecompileFees\('
rg -nP -C3 '\bwatcher__\(\).*consume|withdraw|redeem|settle|collect'
rg -nP -C3 '\bFeesManager\b|\bIFeesManager\b|\bsusdc\b'
Length of output: 71720
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== AuctionManager.deductScheduleFees (context) ==="
nl -ba contracts/evmx/AuctionManager.sol | sed -n '250,276p'
echo
echo "=== RequestHandler - fee collection (around transferFrom) ==="
nl -ba contracts/evmx/watcher/RequestHandler.sol | sed -n '316,330p'
echo
echo "=== RequestHandler._settleRequest (context) ==="
nl -ba contracts/evmx/watcher/RequestHandler.sol | sed -n '412,428p'
echo
echo "=== Search for unblock/block/assign functions in fees/ directory ==="
rg -n 'unblockAndAssignCredits|blockAndAssignCredits|blockCredits|assignCredits|unblockCredits|consumeCredits|transferCredits' contracts/evmx -S || true
echo
echo "=== Show FeesManager.sol head (to inspect token-like behavior) ==="
nl -ba contracts/evmx/fees/FeesManager.sol | sed -n '1,260p'
echo
echo "=== Show Credit.sol head (mint/burn/withdraw semantics) ==="
nl -ba contracts/evmx/fees/Credit.sol | sed -n '1,420p'
Length of output: 92
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== AuctionManager.deductScheduleFees (lines 256-272) ==="
sed -n '256,272p' contracts/evmx/AuctionManager.sol || true
echo
echo "=== RequestHandler - fee collection (lines 316-330) ==="
sed -n '316,330p' contracts/evmx/watcher/RequestHandler.sol || true
echo
echo "=== RequestHandler._settleRequest (lines 412-428) ==="
sed -n '412,428p' contracts/evmx/watcher/RequestHandler.sol || true
echo
echo "=== Search for unblockAndAssignCredits definition ==="
rg -n 'unblockAndAssignCredits' -S || true
echo
echo "=== Show FeesManager.sol (first 420 lines) ==="
sed -n '1,420p' contracts/evmx/fees/FeesManager.sol || true
echo
echo "=== Show Credit.sol (first 420 lines) ==="
sed -n '1,420p' contracts/evmx/fees/Credit.sol || true
echo
echo "=== Show IFeesManager.sol ==="
sed -n '1,240p' contracts/evmx/interfaces/IFeesManager.sol || true
Length of output: 24720
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Find queue definitions ==="
rg -n "function queue\(" -S || true
echo
echo "=== Print Watcher.queue implementation ==="
sed -n '1,320p' contracts/evmx/watcher/Watcher.sol | sed -n '1,320p' || true
Length of output: 9495
Critical: preserve fee reservation semantics — don't transfer sUSDC into AuctionManager; reserve via FeesManager/RequestHandler.
deductScheduleFees currently does IERC20(address(feesManager__())).transferFrom(from_, to_, watcherFees) which moves credits to to_
(often address(this)
or the transmitter) instead of reserving them via FeesManager.blockCredits; RequestHandler later calls unblockAndAssignCredits which reads requestBlockedCredits (but blockCredits isn't being used) — fees can be left stranded on contracts and never consumed.
- This should NOT use ERC20.transferFrom(...) to move fees into AuctionManager. Move fee reservation to the RequestHandler so FeesManager.blockCredits(requestCount, consumeFrom, amount) is called at request creation (onlyRequestHandler is enforced).
- OR, if immediate transfer remains necessary, this should transfer to the watcher/fees-escrow that the watcher actually consumes (not to AuctionManager), and ensure unblock/assignment logic is consistent.
- Add unit tests that assert no sUSDC remains on AuctionManager/RequestHandler after schedule/expire flows and that unblockAndAssignCredits actually assigns funds to the transmitter.
Locations: contracts/evmx/AuctionManager.sol (deductScheduleFees, ~lines 260-266); contracts/evmx/watcher/RequestHandler.sol (fee collect transferFrom ~lines 316-325 and unblockAndAssignCredits call ~412-421); contracts/evmx/fees/FeesManager.sol (blockCredits / unblockAndAssignCredits).
🤖 Prompt for AI Agents
In contracts/evmx/AuctionManager.sol around lines 266 (deductScheduleFees) the
code currently calls IERC20(address(feesManager__())).transferFrom(...), which
moves sUSDC into AuctionManager instead of reserving it; change the flow so
AuctionManager does NOT call ERC20.transferFrom here but instead delegates fee
reservation to the RequestHandler/FeesManager at request creation: remove the
transferFrom and call the RequestHandler-only entry (or emit the params) so
RequestHandler calls FeesManager.blockCredits(requestCount, consumeFrom, amount)
under the onlyRequestHandler guard; ensure FeesManager.blockCredits updates
requestBlockedCredits and unblockAndAssignCredits later consumes those blocked
credits; alternatively, if immediate token movement is required, transfer tokens
into the designated fees-escrow/watcher-escrow contract (not AuctionManager) and
wire FeesManager.unblockAndAssignCredits to read from that escrow; finally add
unit tests that assert no sUSDC balance remains on AuctionManager/RequestHandler
after schedule/expire flows and that unblockAndAssignCredits assigns funds to
the transmitter.
function setSusdcToken(uint32 chainSlug_, bytes32 susdcToken_) external onlyOwner { | ||
forwarderAddresses[susdcToken][chainSlug_] = asyncDeployer__().getOrDeployForwarderContract( | ||
susdcToken_, | ||
chainSlug_ | ||
); | ||
_setValidPlug(true, chainSlug_, susdcToken); | ||
emit SusdcTokenSet(chainSlug_, susdcToken_); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix setSusdcToken: state not updated; wrong key used for forwarder lookup
This writes into forwarderAddresses[susdcToken][chainSlug_]
but never assigns susdcToken = susdcToken_
. Calls to burn
will resolve the forwarder under the old/zero key. Update state and use the freshly set key.
function setSusdcToken(uint32 chainSlug_, bytes32 susdcToken_) external onlyOwner {
- forwarderAddresses[susdcToken][chainSlug_] = asyncDeployer__().getOrDeployForwarderContract(
- susdcToken_,
- chainSlug_
- );
- _setValidPlug(true, chainSlug_, susdcToken);
- emit SusdcTokenSet(chainSlug_, susdcToken_);
+ susdcToken = susdcToken_;
+ forwarderAddresses[susdcToken][chainSlug_] =
+ asyncDeployer__().getOrDeployForwarderContract(susdcToken_, chainSlug_);
+ _setValidPlug(true, chainSlug_, susdcToken);
+ emit SusdcTokenSet(chainSlug_, susdcToken_);
}
📝 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.
function setSusdcToken(uint32 chainSlug_, bytes32 susdcToken_) external onlyOwner { | |
forwarderAddresses[susdcToken][chainSlug_] = asyncDeployer__().getOrDeployForwarderContract( | |
susdcToken_, | |
chainSlug_ | |
); | |
_setValidPlug(true, chainSlug_, susdcToken); | |
emit SusdcTokenSet(chainSlug_, susdcToken_); | |
} | |
function setSusdcToken(uint32 chainSlug_, bytes32 susdcToken_) external onlyOwner { | |
susdcToken = susdcToken_; | |
forwarderAddresses[susdcToken][chainSlug_] = asyncDeployer__().getOrDeployForwarderContract( | |
susdcToken_, | |
chainSlug_ | |
); | |
_setValidPlug(true, chainSlug_, susdcToken); | |
emit SusdcTokenSet(chainSlug_, susdcToken); | |
} |
🤖 Prompt for AI Agents
In contracts/evmx/fees/Credit.sol around lines 129 to 136, the function
setSusdcToken writes the forwarder address using the old susdcToken key and
never updates the contract state; to fix it assign the state variable susdcToken
= susdcToken_ first, then store the forwarder under
forwarderAddresses[susdcToken_][chainSlug_] (or use the freshly set susdcToken)
by calling asyncDeployer__().getOrDeployForwarderContract(susdcToken_,
chainSlug_), call _setValidPlug(true, chainSlug_, susdcToken_) using the new key
(susdcToken_ or the updated state), and emit SusdcTokenSet(chainSlug_,
susdcToken_) with the updated value so subsequent burn/lookups use the correct
key.
tokenOnChainBalances[chainSlug_][token_] += creditAmount_ + nativeAmount_; | ||
|
||
UserCredits storage userCredit = userCredits[depositTo_]; | ||
userCredit.totalCredits += creditAmount_; | ||
// Mint tokens to the user | ||
_mint(depositTo_, creditAmount_); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deposit double-mints on native withdraw failure; wrong credit math
On !success
, it mints creditAmount_
again and then sets nativeAmount_ = 0
before adding it to creditAmount_
(no-op). This should mint nativeAmount_
and convert it to credits.
- if (!success) {
- _mint(depositTo_, creditAmount_);
- nativeAmount_ = 0;
- creditAmount_ += nativeAmount_;
- }
+ if (!success) {
+ // convert native to credits instead of duplicating the credit mint
+ _mint(depositTo_, nativeAmount_);
+ creditAmount_ += nativeAmount_;
+ nativeAmount_ = 0;
+ }
Also applies to: 165-169
if (data_.length > 0) | ||
IReceiver(depositTo_).onTransfer( | ||
chainSlug_, | ||
token_, | ||
creditAmount_, | ||
nativeAmount_, | ||
data_ | ||
); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
onTransfer callback can brick deposits; wrap in try/catch
A failing IReceiver.onTransfer
reverts the entire deposit (even after mint). This should not brick credits. Wrap in try/catch and emit a diagnostic event.
- if (data_.length > 0)
- IReceiver(depositTo_).onTransfer(chainSlug_, token_, creditAmount_, nativeAmount_, data_);
+ if (data_.length > 0) {
+ try IReceiver(depositTo_).onTransfer(chainSlug_, token_, creditAmount_, nativeAmount_, data_) {
+ } catch {
+ // optionally emit an event e.g., OnTransferCallbackFailed(depositTo_, chainSlug_, token_)
+ }
+ }
📝 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.
if (data_.length > 0) | |
IReceiver(depositTo_).onTransfer( | |
chainSlug_, | |
token_, | |
creditAmount_, | |
nativeAmount_, | |
data_ | |
); | |
if (data_.length > 0) { | |
try IReceiver(depositTo_).onTransfer( | |
chainSlug_, | |
token_, | |
creditAmount_, | |
nativeAmount_, | |
data_ | |
) { | |
} catch { | |
// optionally emit an event e.g., OnTransferCallbackFailed(depositTo_, chainSlug_, token_) | |
} | |
} |
🤖 Prompt for AI Agents
In contracts/evmx/fees/Credit.sol around lines 172-180, the external call to
IReceiver(depositTo_).onTransfer(...) can revert and therefore undo the deposit;
wrap this call in a try/catch so a failing receiver does not revert the whole
function, and emit a diagnostic event in the catch with relevant details
(receiver address, chainSlug_, token_, creditAmount_, nativeAmount_, and
optionally the revert reason or bytes data) so failures are observable while
allowing the deposit to complete.
/// @notice Override balanceOf to return available (unblocked) credits | ||
function balanceOf(address account) public view override returns (uint256) { | ||
return super.balanceOf(account) - userBlockedCredits[account]; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Overriding balanceOf breaks ERC-20 invariants and can underflow
Returning “available” (minus blocked) makes sum of balances != totalSupply and can underflow if userBlockedCredits[account] > super.balanceOf(account)
, reverting view calls. This should expose availability via a separate accessor and keep ERC-20 semantics intact.
-/// @notice Override balanceOf to return available (unblocked) credits
-function balanceOf(address account) public view override returns (uint256) {
- return super.balanceOf(account) - userBlockedCredits[account];
-}
+/// @notice Available (unblocked) credits
+function availableBalanceOf(address account) public view returns (uint256) {
+ uint256 bal = super.balanceOf(account);
+ uint256 blocked = userBlockedCredits[account];
+ return blocked >= bal ? 0 : bal - blocked;
+}
Follow-ups within this file:
- Use
availableBalanceOf
in spendability checks and preconditions. - Restore base
ERC20.balanceOf
behavior. Update tests accordingly.
📝 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.
/// @notice Override balanceOf to return available (unblocked) credits | |
function balanceOf(address account) public view override returns (uint256) { | |
return super.balanceOf(account) - userBlockedCredits[account]; | |
} | |
/// @notice Available (unblocked) credits | |
function availableBalanceOf(address account) public view returns (uint256) { | |
uint256 bal = super.balanceOf(account); | |
uint256 blocked = userBlockedCredits[account]; | |
return blocked >= bal ? 0 : bal - blocked; | |
} |
function testFuzzLargeProofs(bytes32 digest, uint256 proofSize) public { | ||
vm.assume(digest != bytes32(0)); | ||
vm.assume(proofSize >= 65 && proofSize <= 1000); // Reasonable proof sizes | ||
|
||
// Create a large proof | ||
bytes memory largeProof = new bytes(proofSize); | ||
for (uint256 i = 0; i < proofSize; i++) { | ||
largeProof[i] = bytes1(uint8(i % 256)); | ||
} | ||
|
||
vm.expectRevert(InvalidSignature.selector); | ||
fastSwitchboard.attest(digest, largeProof); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Fuzz test is over-constrained; 65-byte proofs won’t always hit InvalidSignature.
For 65 bytes, ECDSA parsing succeeds and the revert should be WatcherNotFound. Branch by size.
- vm.expectRevert(InvalidSignature.selector);
- fastSwitchboard.attest(digest, largeProof);
+ if (proofSize == 65) {
+ vm.expectRevert(FastSwitchboard.WatcherNotFound.selector);
+ } else {
+ vm.expectRevert(FastSwitchboard.InvalidSignature.selector);
+ }
+ fastSwitchboard.attest(digest, largeProof);
📝 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.
function testFuzzLargeProofs(bytes32 digest, uint256 proofSize) public { | |
vm.assume(digest != bytes32(0)); | |
vm.assume(proofSize >= 65 && proofSize <= 1000); // Reasonable proof sizes | |
// Create a large proof | |
bytes memory largeProof = new bytes(proofSize); | |
for (uint256 i = 0; i < proofSize; i++) { | |
largeProof[i] = bytes1(uint8(i % 256)); | |
} | |
vm.expectRevert(InvalidSignature.selector); | |
fastSwitchboard.attest(digest, largeProof); | |
} | |
function testFuzzLargeProofs(bytes32 digest, uint256 proofSize) public { | |
vm.assume(digest != bytes32(0)); | |
vm.assume(proofSize >= 65 && proofSize <= 1000); // Reasonable proof sizes | |
// Create a large proof | |
bytes memory largeProof = new bytes(proofSize); | |
for (uint256 i = 0; i < proofSize; i++) { | |
largeProof[i] = bytes1(uint8(i % 256)); | |
} | |
if (proofSize == 65) { | |
vm.expectRevert(FastSwitchboard.WatcherNotFound.selector); | |
} else { | |
vm.expectRevert(FastSwitchboard.InvalidSignature.selector); | |
} | |
fastSwitchboard.attest(digest, largeProof); | |
} |
🤖 Prompt for AI Agents
In test/protocol/switchboards/FastSwitchboardTest.t.sol around lines 154 to 166,
the fuzz test assumes all proof sizes between 65 and 1000 should revert with
InvalidSignature but a 65-byte proof parses as a valid ECDSA signature and will
instead revert with WatcherNotFound; change the assertion to branch on
proofSize: when proofSize == 65 expectRevert(WatcherNotFound.selector) (or the
WatcherNotFound error) and for all other sizes
expectRevert(InvalidSignature.selector), keeping the same proof generation and
size assumptions.
vm.expectRevert(InvalidSignature.selector); | ||
fastSwitchboard.attest(digest, largeProof); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use the correct error type qualifier for expectRevert.
InvalidSignature must be referenced from the contract that defines it.
Option A (if FastSwitchboard declares the error):
- vm.expectRevert(InvalidSignature.selector);
+ vm.expectRevert(FastSwitchboard.InvalidSignature.selector);
Option B (if it’s from a library, e.g., ECDSA):
- vm.expectRevert(InvalidSignature.selector);
+ vm.expectRevert(ECDSA.InvalidSignature.selector);
📝 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.
vm.expectRevert(InvalidSignature.selector); | |
fastSwitchboard.attest(digest, largeProof); | |
} | |
vm.expectRevert(FastSwitchboard.InvalidSignature.selector); | |
fastSwitchboard.attest(digest, largeProof); | |
} |
🤖 Prompt for AI Agents
In test/protocol/switchboards/FastSwitchboardTest.t.sol around lines 164 to 166,
the expectRevert call references InvalidSignature without its defining
contract/library qualifier; update the expectRevert to use the correct scoped
error selector (e.g. FastSwitchboard.InvalidSignature.selector if the error is
declared in FastSwitchboard, or ECDSA.InvalidSignature.selector if declared in a
library), and ensure any necessary contract/library name is imported or visible
in the test scope.
// SPDX-License-Identifier: GPL-3.0-only | ||
pragma solidity ^0.8.21; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
File will not be picked up by Foundry as a test
The filename includes a space before .sol and does not end with .t.sol. Foundry won’t run these tests.
Rename to:
- test/protocol/switchboards/MessageSwitchboardTest.t.sol
And delete the stray copy to avoid duplicate compilation.
🤖 Prompt for AI Agents
In test/protocol/switchboards/MessageSwitchboardTest.t copy.sol around lines
1-3, the filename contains a space and does not end with .t.sol so Foundry will
not detect it as a test; rename the file to
test/protocol/switchboards/MessageSwitchboardTest.t.sol (removing the space and
adding the .t.sol suffix) and remove the stray "copy" file to avoid duplicate
compilation artifacts.
function approve(address appGateway_, address user_) internal { | ||
bool approval = feesManager.isApproved(user_, appGateway_); | ||
if (approval) return; | ||
|
||
AppGatewayApprovals[] memory approvals = new AppGatewayApprovals[](1); | ||
approvals[0] = AppGatewayApprovals({appGateway: appGateway_, approval: true}); | ||
|
||
hoax(user_); | ||
feesManager.approveAppGateways(approvals); | ||
feesManager.approve(appGateway_, true); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Signature/order of isApproved appears inconsistent with interface.
Here you call isApproved(user_, appGateway_), but IFeesManager declares isApproved(appGateway_, user_). Confirm and standardize across codebase to avoid subtle bugs.
Run to verify implementation signature and call sites:
🏁 Script executed:
#!/bin/bash
# Check definition
rg -nP 'function\s+isApproved\s*\(' contracts --type=sol -C2
# Check call sites
rg -nP '\bisApproved\s*\(' --type=sol -C3
Length of output: 55
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "PWD: $(pwd)" >&2
echo "--- list first 200 .sol files ---" >&2
find . -type f -iname '*.sol' -print | sed -n '1,200p' || true
echo "--- search for IFeesManager/interface and isApproved definitions/usages ---" >&2
if command -v rg >/dev/null 2>&1; then
rg -n --hidden --no-ignore -S -P "interface\s+IFeesManager\b" -C4 || true
rg -n --hidden --no-ignore -S -P "contract\s+IFeesManager\b" -C4 || true
rg -n --hidden --no-ignore -S -P "function\s+isApproved\s*\(" -C4 || true
rg -n --hidden --no-ignore -S -P "\bisApproved\s*\(" -C4 || true
rg -n --hidden --no-ignore -S -P "feesManager\b" -C3 || true
else
echo "rg not available, falling back to grep" >&2
grep -RIn --exclude-dir=node_modules -E "interface\s+IFeesManager\b" . || true
grep -RIn --exclude-dir=node_modules -E "contract\s+IFeesManager\b" . || true
grep -RIn --exclude-dir=node_modules -E "function\s+isApproved\s*\(" . || true
grep -RIn --exclude-dir=node_modules -E "\bisApproved\s*\(" . || true
grep -RIn --exclude-dir=node_modules -E "feesManager\b" . || true
fi
# show the test file snippet if present
echo "--- show test/SetupTest.t.sol around reported lines if file exists ---" >&2
file=$(find . -type f -iname 'SetupTest.t.sol' -print -quit || true)
if [ -n "$file" ]; then
echo "Found: $file" >&2
sed -n '640,680p' "$file" || true
else
echo "SetupTest.t.sol not found by that name; searching for files under test/ with 'SetupTest' in name..." >&2
find . -type f -path '*/test/*' -iname '*SetupTest*.sol' -print -exec sed -n '640,680p' {} \; || true
fi
Length of output: 39646
Standardize isApproved parameter order (interface vs implementation & callers)
IFeesManager declares isApproved(address appGateway_, address user_) (contracts/evmx/interfaces/IFeesManager.sol:47) but Credit.sol implements isApproved(address user_, address appGateway_) (contracts/evmx/fees/Credit.sol:138) and tests/scripts call isApproved(user_, appGateway_) (test/SetupTest.t.sol:661–672, 677–700; hardhat-scripts/deploy/9.setupTransmitter.ts:43–45). This should be fixed by updating the interface to isApproved(address user_, address appGateway_) (or aligning the implementation/callers to the intended order), update any ABI/TS callers, and run tests.
🤖 Prompt for AI Agents
In test/SetupTest.t.sol around lines 661 to 667, the test calls
isApproved(user_, appGateway_) but IFeesManager declares isApproved(address
appGateway_, address user_) while Credit.sol implements isApproved(address
user_, address appGateway_), causing mismatched parameter order across
interface, implementation and callers; fix by standardizing to
isApproved(address user_, address appGateway_) in the IFeesManager interface (or
alternatively change implementation/callers to match the interface), then update
any ABI/TypeScript callers (hardhat-scripts/deploy/9.setupTransmitter.ts and
other tests) to the chosen parameter order, regenerate ABIs/TS types if used,
and run the full test suite to verify.
* @dev Tests for IdUtils utility functions | ||
*/ | ||
contract IdUtilsTest is Test { | ||
function testCreatePayloadId() public pure { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix: Tests declared pure will not compile (assert/log/cheatcodes). Remove pure
.
These tests call assertEq
, fail
, and vm.*
which are not allowed in pure
functions. This should drop pure
from all test function signatures to avoid compilation errors.
Apply:
- function testCreatePayloadId() public pure {
+ function testCreatePayloadId() public {
- function testCreatePayloadIdWithZeroValues() public pure {
+ function testCreatePayloadIdWithZeroValues() public {
- function testCreatePayloadIdWithMaxValues() public pure {
+ function testCreatePayloadIdWithMaxValues() public {
- ) public pure {
+ ) public {
- function testToBytes32Format() public pure {
+ function testToBytes32Format() public {
- function testToBytes32FormatWithZeroAddress() public pure {
+ function testToBytes32FormatWithZeroAddress() public {
- function testFromBytes32Format() public pure {
+ function testFromBytes32Format() public {
- function testFromBytes32FormatWithZeroAddress() public pure {
+ function testFromBytes32FormatWithZeroAddress() public {
- function testFromBytes32FormatWithMaxValidAddress() public pure {
+ function testFromBytes32FormatWithMaxValidAddress() public {
- function testConvertersRoundTrip() public pure {
+ function testConvertersRoundTrip() public {
- function testConvertersFuzz(address addr) public pure {
+ function testConvertersFuzz(address addr) public {
Also applies to: 30-30, 36-36, 57-57, 76-76, 83-83, 89-89, 98-98, 122-122, 131-131, 140-140
🤖 Prompt for AI Agents
In test/Utils.t.sol around lines 13, 30, 36, 57, 76, 83, 89, 98, 122, 131, and
140, the test functions are declared `pure` but call assertions, logs, or vm
cheatcodes which are not allowed in `pure` functions; remove the `pure` keyword
from each affected function signature so they are non-pure (e.g., change
`function testX() public pure` to `function testX() public`) to allow
assertions, fail(), and vm.* calls to compile and run.
Summary by CodeRabbit
New Features
Documentation
Tests
Chores